From 6a2f558ea512a0ac18e5fcb60aa76fd65d38e1fe Mon Sep 17 00:00:00 2001 From: h2zero Date: Sat, 27 Aug 2022 13:13:27 -0600 Subject: [PATCH] [BREAKING] Replace advertised device callbacks with scan callbacks. (#389) This replaces NimBLEAdvertisedDeviceCallbacks with NimBLEScanCallbacks and adds a onScanEnd callback. The callback parameter for NimBLEScan::start has been removed and the blocking overload for NimBLEScan::start has been replaced by an overload of NimBLEScan::getResults with the same parameters. --- docs/New_user_guide.md | 2 +- examples/Advanced/NimBLE_Client/main/main.cpp | 43 ++++---- .../NimBLE_extended_client/main/main.cpp | 29 +++--- examples/basic/BLE_client/main/main.cpp | 2 +- examples/basic/BLE_scan/main/main.cpp | 4 +- src/NimBLEAdvertisedDevice.h | 19 ---- src/NimBLEDevice.h | 2 +- src/NimBLEScan.cpp | 98 +++++++++---------- src/NimBLEScan.h | 45 ++++++--- 9 files changed, 114 insertions(+), 130 deletions(-) diff --git a/docs/New_user_guide.md b/docs/New_user_guide.md index d5b8e6f..506a368 100644 --- a/docs/New_user_guide.md +++ b/docs/New_user_guide.md @@ -162,7 +162,7 @@ void app_main(void) NimBLEDevice::init(""); NimBLEScan *pScan = NimBLEDevice::getScan(); - NimBLEScanResults results = pScan->start(10 * 1000); + NimBLEScanResults results = pScan->getResults(10 * 1000); } ```
diff --git a/examples/Advanced/NimBLE_Client/main/main.cpp b/examples/Advanced/NimBLE_Client/main/main.cpp index 8971355..d276aad 100644 --- a/examples/Advanced/NimBLE_Client/main/main.cpp +++ b/examples/Advanced/NimBLE_Client/main/main.cpp @@ -11,8 +11,6 @@ extern "C" {void app_main(void);} -void scanEndedCB(NimBLEScanResults results); - static NimBLEAdvertisedDevice* advDevice; static bool doConnect = false; @@ -31,13 +29,13 @@ class ClientCallbacks : public NimBLEClientCallbacks { * Min interval: 120 * 1.25ms = 150, Max interval: 120 * 1.25ms = 150, 0 latency, 45 * 10ms = 450ms timeout */ pClient->updateConnParams(120,120,0,45); - }; + } void onDisconnect(NimBLEClient* pClient, int reason) { printf("%s Disconnected, reason = %d - Starting scan\n", pClient->getPeerAddress().toString().c_str(), reason); - NimBLEDevice::getScan()->start(scanTime, scanEndedCB); - }; + NimBLEDevice::getScan()->start(scanTime); + } /********************* Security handled here ********************** ****** Note: these are the same return values as defaults ********/ @@ -45,29 +43,28 @@ class ClientCallbacks : public NimBLEClientCallbacks { printf("Client Passkey Request\n"); /** return the passkey to send to the server */ return 123456; - }; + } bool onConfirmPIN(uint32_t pass_key){ printf("The passkey YES/NO number: %d\n", pass_key); /** Return false if passkeys don't match. */ return true; - }; + } - /** Pairing process complete, we can check the results in ble_gap_conn_desc */ - void onAuthenticationComplete(ble_gap_conn_desc* desc){ - if(!desc->sec_state.encrypted) { + /** Pairing process complete, we can check the results in connInfo */ + void onAuthenticationComplete(NimBLEConnInfo& connInfo){ + if(!connInfo.isEncrypted()) { printf("Encrypt connection failed - disconnecting\n"); /** Find the client with the connection handle provided in desc */ - NimBLEDevice::getClientByID(desc->conn_handle)->disconnect(); + NimBLEDevice::getClientByID(connInfo.getConnHandle())->disconnect(); return; } - }; + } }; /** Define a class to handle the callbacks when advertisments are received */ -class AdvertisedDeviceCallbacks: public NimBLEAdvertisedDeviceCallbacks { - +class scanCallbacks: public NimBLEScanCallbacks { void onResult(NimBLEAdvertisedDevice* advertisedDevice) { printf("Advertised Device found: %s\n", advertisedDevice->toString().c_str()); if(advertisedDevice->isAdvertisingService(NimBLEUUID("DEAD"))) @@ -80,7 +77,12 @@ class AdvertisedDeviceCallbacks: public NimBLEAdvertisedDeviceCallbacks { /** Ready to connect now */ doConnect = true; } - }; + } + + /** Callback to process the results of the completed scan or restart it */ + void onScanEnd(NimBLEScanResults results) { + printf("Scan Ended\n"); + } }; @@ -95,11 +97,6 @@ void notifyCB(NimBLERemoteCharacteristic* pRemoteCharacteristic, uint8_t* pData, printf("%s\n", str.c_str()); } -/** Callback to process the results of the last scan or restart it */ -void scanEndedCB(NimBLEScanResults results){ - printf("Scan Ended\n"); -} - /** Create a single global instance of the callback class to be used by all clients */ static ClientCallbacks clientCB; @@ -312,7 +309,7 @@ void connectTask (void * parameter){ printf("Failed to connect, starting scan\n"); } - NimBLEDevice::getScan()->start(scanTime,scanEndedCB); + NimBLEDevice::getScan()->start(scanTime); } vTaskDelay(10/portTICK_PERIOD_MS); } @@ -351,7 +348,7 @@ void app_main (void){ NimBLEScan* pScan = NimBLEDevice::getScan(); /** create a callback that gets called when advertisers are found */ - pScan->setAdvertisedDeviceCallbacks(new AdvertisedDeviceCallbacks()); + pScan->setScanCallbacks (new scanCallbacks()); /** Set scan interval (how often) and window (how long) in milliseconds */ pScan->setInterval(400); @@ -364,7 +361,7 @@ void app_main (void){ /** Start scanning for advertisers for the scan time specified (in seconds) 0 = forever * Optional callback for when scanning stops. */ - pScan->start(scanTime, scanEndedCB); + pScan->start(scanTime); printf("Scanning for peripherals\n"); diff --git a/examples/Bluetooth_5/NimBLE_extended_client/main/main.cpp b/examples/Bluetooth_5/NimBLE_extended_client/main/main.cpp index 30baeb5..c9013d9 100644 --- a/examples/Bluetooth_5/NimBLE_extended_client/main/main.cpp +++ b/examples/Bluetooth_5/NimBLE_extended_client/main/main.cpp @@ -11,8 +11,6 @@ extern "C" void app_main(void); -void scanEndedCB(NimBLEScanResults results); - #define SERVICE_UUID "ABCD" #define CHARACTERISTIC_UUID "1234" @@ -32,14 +30,13 @@ class ClientCallbacks : public NimBLEClientCallbacks { void onDisconnect(NimBLEClient* pClient, int reason) { printf("%s Disconnected, reason = %d - Starting scan\n", pClient->getPeerAddress().toString().c_str(), reason); - NimBLEDevice::getScan()->start(scanTime, scanEndedCB); + NimBLEDevice::getScan()->start(scanTime); }; }; /* Define a class to handle the callbacks when advertisements are received */ -class AdvertisedDeviceCallbacks: public NimBLEAdvertisedDeviceCallbacks { - +class scanCallbacks: public NimBLEScanCallbacks { void onResult(NimBLEAdvertisedDevice* advertisedDevice) { printf("Advertised Device found: %s\n", advertisedDevice->toString().c_str()); if(advertisedDevice->isAdvertisingService(NimBLEUUID("ABCD"))) @@ -52,17 +49,13 @@ class AdvertisedDeviceCallbacks: public NimBLEAdvertisedDeviceCallbacks { /* stop scan before connecting */ NimBLEDevice::getScan()->stop(); } - }; -}; - - -/* Callback to process the results of the last scan or restart it */ -void scanEndedCB(NimBLEScanResults results){ - printf("Scan Ended\n"); - if (!doConnect) { /* Don't start the scan while connecting */ - NimBLEDevice::getScan()->start(scanTime, scanEndedCB); } -} + + /** Callback to process the results of the completed scan or restart it */ + void onScanEnd(NimBLEScanResults results) { + printf("Scan Ended\n"); + } +}; /* Handles the provisioning of clients and connects / interfaces with the server */ @@ -132,7 +125,7 @@ void connectTask (void * parameter){ } doConnect = false; - NimBLEDevice::getScan()->start(scanTime, scanEndedCB); + NimBLEDevice::getScan()->start(scanTime); } vTaskDelay(pdMS_TO_TICKS(10)); } @@ -150,7 +143,7 @@ void app_main (void) { NimBLEScan* pScan = NimBLEDevice::getScan(); /* create a callback that gets called when advertisers are found */ - pScan->setAdvertisedDeviceCallbacks(new AdvertisedDeviceCallbacks()); + pScan->setScanCallbacks(new scanCallbacks()); /* Set scan interval (how often) and window (how long) in milliseconds */ pScan->setInterval(97); @@ -164,7 +157,7 @@ void app_main (void) { /* Start scanning for advertisers for the scan time specified (in seconds) 0 = forever * Optional callback for when scanning stops. */ - pScan->start(scanTime, scanEndedCB); + pScan->start(scanTime); printf("Scanning for peripherals\n"); } diff --git a/examples/basic/BLE_client/main/main.cpp b/examples/basic/BLE_client/main/main.cpp index 9db0c07..f6d9495 100644 --- a/examples/basic/BLE_client/main/main.cpp +++ b/examples/basic/BLE_client/main/main.cpp @@ -191,7 +191,7 @@ void app_main(void) { // have detected a new device. Specify that we want active scanning and start the // scan to run for 5 seconds. BLEScan* pBLEScan = BLEDevice::getScan(); - pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks()); + pBLEScan->setScanCallbacks(new MyAdvertisedDeviceCallbacks()); pBLEScan->setInterval(1349); pBLEScan->setWindow(449); pBLEScan->setActiveScan(true); diff --git a/examples/basic/BLE_scan/main/main.cpp b/examples/basic/BLE_scan/main/main.cpp index 8a9e83b..d936c01 100644 --- a/examples/basic/BLE_scan/main/main.cpp +++ b/examples/basic/BLE_scan/main/main.cpp @@ -29,7 +29,7 @@ class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks { void scanTask (void * parameter){ for(;;) { // put your main code here, to run repeatedly: - BLEScanResults foundDevices = pBLEScan->start(scanTime, false); + BLEScanResults foundDevices = pBLEScan->getResults(scanTime, false); printf("Devices found: %d\n", foundDevices.getCount()); printf("Scan done!\n"); pBLEScan->clearResults(); // delete results fromBLEScan buffer to release memory @@ -44,7 +44,7 @@ void app_main(void) { BLEDevice::init(""); pBLEScan = BLEDevice::getScan(); //create new scan - pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks()); + pBLEScan->setScanCallbacks(new MyAdvertisedDeviceCallbacks()); pBLEScan->setActiveScan(true); //active scan uses more power, but get results faster pBLEScan->setInterval(100); pBLEScan->setWindow(99); // less or equal setInterval value diff --git a/src/NimBLEAdvertisedDevice.h b/src/NimBLEAdvertisedDevice.h index 772bab9..c582a7b 100644 --- a/src/NimBLEAdvertisedDevice.h +++ b/src/NimBLEAdvertisedDevice.h @@ -175,24 +175,5 @@ private: std::vector m_payload; }; -/** - * @brief A callback handler for callbacks associated device scanning. - * - * When we are performing a scan as a %BLE client, we may wish to know when a new device that is advertising - * has been found. This class can be sub-classed and registered such that when a scan is performed and - * a new advertised device has been found, we will be called back to be notified. - */ -class NimBLEAdvertisedDeviceCallbacks { -public: - virtual ~NimBLEAdvertisedDeviceCallbacks() {} - /** - * @brief Called when a new scan result is detected. - * - * As we are scanning, we will find new devices. When found, this call back is invoked with a reference to the - * device that was found. During any individual scan, a device will only be detected one time. - */ - virtual void onResult(NimBLEAdvertisedDevice* advertisedDevice) = 0; -}; - #endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_OBSERVER */ #endif /* COMPONENTS_NIMBLEADVERTISEDDEVICE_H_ */ diff --git a/src/NimBLEDevice.h b/src/NimBLEDevice.h index a32c3b8..60baf59 100644 --- a/src/NimBLEDevice.h +++ b/src/NimBLEDevice.h @@ -62,7 +62,7 @@ #define BLEAddress NimBLEAddress #define BLEUtils NimBLEUtils #define BLEClientCallbacks NimBLEClientCallbacks -#define BLEAdvertisedDeviceCallbacks NimBLEAdvertisedDeviceCallbacks +#define BLEAdvertisedDeviceCallbacks NimBLEScanCallbacks #define BLEScanResults NimBLEScanResults #define BLEServer NimBLEServer #define BLEService NimBLEService diff --git a/src/NimBLEScan.cpp b/src/NimBLEScan.cpp index 1d4d239..d907c54 100644 --- a/src/NimBLEScan.cpp +++ b/src/NimBLEScan.cpp @@ -35,7 +35,7 @@ NimBLEScan::NimBLEScan() { m_scan_params.window = 0; // The duration of the LE scan. LE_Scan_Window shall be less than or equal to LE_Scan_Interval (units=0.625 msec) m_scan_params.limited = 0; // If set, only discover devices in limited discoverable mode. m_scan_params.filter_duplicates = 1; // If set, the controller ignores all but the first advertisement from each device. - m_pAdvertisedDeviceCallbacks = nullptr; + m_pScanCallbacks = nullptr; m_ignoreResults = false; m_pTaskData = nullptr; m_duration = BLE_HS_FOREVER; // make sure this is non-zero in the event of a host reset @@ -55,7 +55,8 @@ NimBLEScan::~NimBLEScan() { * @param [in] event The event type for this event. * @param [in] param Parameter data for this event. */ -/*STATIC*/int NimBLEScan::handleGapEvent(ble_gap_event* event, void* arg) { +/*STATIC*/ +int NimBLEScan::handleGapEvent(ble_gap_event* event, void* arg) { (void)arg; NimBLEScan* pScan = NimBLEDevice::getScan(); @@ -133,7 +134,7 @@ NimBLEScan::~NimBLEScan() { advertisedDevice->setPayload(disc.data, disc.length_data, (isLegacyAdv && event_type == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP)); - if (pScan->m_pAdvertisedDeviceCallbacks) { + if (pScan->m_pScanCallbacks) { if (pScan->m_scan_params.filter_duplicates && advertisedDevice->m_callbackSent) { return 0; } @@ -145,12 +146,12 @@ NimBLEScan::~NimBLEScan() { advertisedDevice->getAdvType() != BLE_HCI_ADV_TYPE_ADV_SCAN_IND)) { advertisedDevice->m_callbackSent = true; - pScan->m_pAdvertisedDeviceCallbacks->onResult(advertisedDevice); + pScan->m_pScanCallbacks->onResult(advertisedDevice); // Otherwise, wait for the scan response so we can report the complete data. } else if (isLegacyAdv && event_type == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP) { advertisedDevice->m_callbackSent = true; - pScan->m_pAdvertisedDeviceCallbacks->onResult(advertisedDevice); + pScan->m_pScanCallbacks->onResult(advertisedDevice); } // If not storing results and we have invoked the callback, delete the device. if(pScan->m_maxResults == 0 && advertisedDevice->m_callbackSent) { @@ -166,10 +167,10 @@ NimBLEScan::~NimBLEScan() { // If a device advertised with scan response available and it was not received // the callback would not have been invoked, so do it here. - if(pScan->m_pAdvertisedDeviceCallbacks) { + if(pScan->m_pScanCallbacks) { for(auto &it : pScan->m_scanResults.m_advertisedDevicesVector) { if(!it->m_callbackSent) { - pScan->m_pAdvertisedDeviceCallbacks->onResult(it); + pScan->m_pScanCallbacks->onResult(it); } } } @@ -178,8 +179,8 @@ NimBLEScan::~NimBLEScan() { pScan->clearResults(); } - if (pScan->m_scanCompleteCB != nullptr) { - pScan->m_scanCompleteCB(pScan->m_scanResults); + if (pScan->m_pScanCallbacks != nullptr) { + pScan->m_pScanCallbacks->onScanEnd(pScan->m_scanResults); } if(pScan->m_pTaskData != nullptr) { @@ -263,14 +264,13 @@ void NimBLEScan::setMaxResults(uint8_t maxResults) { /** * @brief Set the call backs to be invoked. - * @param [in] pAdvertisedDeviceCallbacks Call backs to be invoked. + * @param [in] pScanCallbacks Call backs to be invoked. * @param [in] wantDuplicates True if we wish to be called back with duplicates. Default is false. */ -void NimBLEScan::setAdvertisedDeviceCallbacks(NimBLEAdvertisedDeviceCallbacks* pAdvertisedDeviceCallbacks, - bool wantDuplicates) { +void NimBLEScan::setScanCallbacks(NimBLEScanCallbacks* pScanCallbacks, bool wantDuplicates) { setDuplicateFilter(!wantDuplicates); - m_pAdvertisedDeviceCallbacks = pAdvertisedDeviceCallbacks; -} // setAdvertisedDeviceCallbacks + m_pScanCallbacks = pScanCallbacks; +} // setScanCallbacks /** @@ -303,15 +303,12 @@ bool NimBLEScan::isScanning() { /** * @brief Start scanning. * @param [in] duration The duration in milliseconds for which to scan. - * @param [in] scanCompleteCB A function to be called when scanning has completed. * @param [in] is_continue Set to true to save previous scan results, false to clear them. * @return True if scan started or false if there was an error. */ -bool NimBLEScan::start(uint32_t duration, void (*scanCompleteCB)(NimBLEScanResults), bool is_continue) { +bool NimBLEScan::start(uint32_t duration, bool is_continue) { NIMBLE_LOGD(LOG_TAG, ">> start: duration=%" PRIu32, duration); - // Save the callback to be invoked when the scan completes. - m_scanCompleteCB = scanCompleteCB; // Save the duration in the case that the host is reset so we can reuse it. m_duration = duration; @@ -386,34 +383,6 @@ bool NimBLEScan::start(uint32_t duration, void (*scanCompleteCB)(NimBLEScanResul } // start -/** - * @brief Start scanning and block until scanning has been completed. - * @param [in] duration The duration in seconds for which to scan. - * @param [in] is_continue Set to true to save previous scan results, false to clear them. - * @return The NimBLEScanResults. - */ -NimBLEScanResults NimBLEScan::start(uint32_t duration, bool is_continue) { - if(duration == 0) { - NIMBLE_LOGW(LOG_TAG, "Blocking scan called with duration = forever"); - } - - TaskHandle_t cur_task = xTaskGetCurrentTaskHandle(); - ble_task_data_t taskData = {nullptr, cur_task, 0, nullptr}; - m_pTaskData = &taskData; - - if(start(duration, nullptr, is_continue)) { -#ifdef ulTaskNotifyValueClear - // Clear the task notification value to ensure we block - ulTaskNotifyValueClear(cur_task, ULONG_MAX); -#endif - ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - } - - m_pTaskData = nullptr; - return m_scanResults; -} // start - - /** * @brief Stop an in progress scan. * @return True if successful. @@ -431,8 +400,8 @@ bool NimBLEScan::stop() { clearResults(); } - if (rc != BLE_HS_EALREADY && m_scanCompleteCB != nullptr) { - m_scanCompleteCB(m_scanResults); + if (rc != BLE_HS_EALREADY && m_pScanCallbacks != nullptr) { + m_pScanCallbacks->onScanEnd(m_scanResults); } if(m_pTaskData != nullptr) { @@ -487,11 +456,40 @@ void NimBLEScan::onHostReset() { void NimBLEScan::onHostSync() { m_ignoreResults = false; - if(m_duration == 0 && m_pAdvertisedDeviceCallbacks != nullptr) { - start(m_duration, m_scanCompleteCB); + if(m_duration == 0 && m_pScanCallbacks != nullptr) { + start(0, false); } } + +/** + * @brief Start scanning and block until scanning has been completed. + * @param [in] duration The duration in seconds for which to scan. + * @param [in] is_continue Set to true to save previous scan results, false to clear them. + * @return The scan results. + */ +NimBLEScanResults NimBLEScan::getResults(uint32_t duration, bool is_continue) { + if(duration == 0) { + NIMBLE_LOGW(LOG_TAG, "Blocking scan called with duration = forever"); + } + + TaskHandle_t cur_task = xTaskGetCurrentTaskHandle(); + ble_task_data_t taskData = {nullptr, cur_task, 0, nullptr}; + m_pTaskData = &taskData; + + if(start(duration, is_continue)) { +#ifdef ulTaskNotifyValueClear + // Clear the task notification value to ensure we block + ulTaskNotifyValueClear(cur_task, ULONG_MAX); +#endif + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + } + + m_pTaskData = nullptr; + return m_scanResults; +} // getResults + + /** * @brief Get the results of the scan. * @return NimBLEScanResults object. diff --git a/src/NimBLEScan.h b/src/NimBLEScan.h index 76a1142..9bf11bb 100644 --- a/src/NimBLEScan.h +++ b/src/NimBLEScan.h @@ -31,7 +31,7 @@ class NimBLEDevice; class NimBLEScan; class NimBLEAdvertisedDevice; -class NimBLEAdvertisedDeviceCallbacks; +class NimBLEScanCallbacks; class NimBLEAddress; /** @@ -62,10 +62,9 @@ private: */ class NimBLEScan { public: - bool start(uint32_t duration, void (*scanCompleteCB)(NimBLEScanResults), bool is_continue = false); - NimBLEScanResults start(uint32_t duration, bool is_continue = false); + bool start(uint32_t duration, bool is_continue = false); bool isScanning(); - void setAdvertisedDeviceCallbacks(NimBLEAdvertisedDeviceCallbacks* pAdvertisedDeviceCallbacks, bool wantDuplicates = false); + void setScanCallbacks(NimBLEScanCallbacks* pScanCallbacks, bool wantDuplicates = false); void setActiveScan(bool active); void setInterval(uint16_t intervalMSecs); void setWindow(uint16_t windowMSecs); @@ -76,6 +75,7 @@ public: bool stop(); void clearResults(); NimBLEScanResults getResults(); + NimBLEScanResults getResults(uint32_t duration, bool is_continue = false); void setMaxResults(uint8_t maxResults); void erase(const NimBLEAddress &address); @@ -85,18 +85,33 @@ private: NimBLEScan(); ~NimBLEScan(); - static int handleGapEvent(ble_gap_event* event, void* arg); - void onHostReset(); - void onHostSync(); + static int handleGapEvent(ble_gap_event* event, void* arg); + void onHostReset(); + void onHostSync(); - NimBLEAdvertisedDeviceCallbacks* m_pAdvertisedDeviceCallbacks = nullptr; - void (*m_scanCompleteCB)(NimBLEScanResults scanResults); - ble_gap_disc_params m_scan_params; - bool m_ignoreResults; - NimBLEScanResults m_scanResults; - uint32_t m_duration; - ble_task_data_t *m_pTaskData; - uint8_t m_maxResults; + NimBLEScanCallbacks* m_pScanCallbacks; + ble_gap_disc_params m_scan_params; + bool m_ignoreResults; + NimBLEScanResults m_scanResults; + uint32_t m_duration; + ble_task_data_t *m_pTaskData; + uint8_t m_maxResults; +}; + +/** + * @brief A callback handler for callbacks associated device scanning. + */ +class NimBLEScanCallbacks { +public: + virtual ~NimBLEScanCallbacks() {} + /** + * @brief Called when a new scan result is detected. + * + * As we are scanning, we will find new devices. When found, this call back is invoked with a reference to the + * device that was found. During any individual scan, a device will only be detected one time. + */ + virtual void onResult(NimBLEAdvertisedDevice* advertisedDevice) {}; + virtual void onScanEnd(NimBLEScanResults scanResults) {}; }; #endif /* CONFIG_BT_ENABLED CONFIG_BT_NIMBLE_ROLE_OBSERVER */