From 79b480ce7325d78c426d25e06d23c799a0958228 Mon Sep 17 00:00:00 2001 From: Simon Hailes Date: Wed, 17 Feb 2021 09:19:45 +0000 Subject: [PATCH] Update NimBLE to 1.2.0 release version - no TAS code changes required. --- lib/libesp32/NimBLE-Arduino/CHANGELOG.md | 68 +- .../docs/Command_line_config.md | 136 ++-- .../NimBLE-Arduino/docs/Migration_guide.md | 9 +- .../NimBLE-Arduino/docs/Usage_tips.md | 41 ++ .../NimBLE_Scan_Continuous.ino | 71 ++ .../NimBLE_Service_Data_Advertiser.ino | 33 + lib/libesp32/NimBLE-Arduino/library.json | 2 +- .../NimBLE-Arduino/library.properties | 2 +- .../src/NimBLEAdvertisedDevice.cpp | 688 +++++++++++------- .../src/NimBLEAdvertisedDevice.h | 51 +- .../NimBLE-Arduino/src/NimBLEAdvertising.cpp | 361 ++++++--- .../NimBLE-Arduino/src/NimBLEAdvertising.h | 21 + .../src/NimBLECharacteristic.cpp | 26 +- .../NimBLE-Arduino/src/NimBLECharacteristic.h | 29 +- .../NimBLE-Arduino/src/NimBLEDescriptor.cpp | 10 +- .../NimBLE-Arduino/src/NimBLEDescriptor.h | 15 +- .../NimBLE-Arduino/src/NimBLEDevice.cpp | 64 +- .../NimBLE-Arduino/src/NimBLEDevice.h | 4 + .../NimBLE-Arduino/src/NimBLEHIDDevice.cpp | 10 +- .../NimBLE-Arduino/src/NimBLEScan.cpp | 101 ++- lib/libesp32/NimBLE-Arduino/src/NimBLEScan.h | 3 +- .../NimBLE-Arduino/src/NimBLEServer.cpp | 37 +- .../NimBLE-Arduino/src/NimBLEServer.h | 5 +- .../NimBLE-Arduino/src/NimBLEService.cpp | 62 +- .../NimBLE-Arduino/src/NimBLEService.h | 26 +- .../NimBLE-Arduino/src/NimBLEUUID.cpp | 31 +- .../src/esp-hci/src/esp_nimble_hci.c | 4 - lib/libesp32/NimBLE-Arduino/src/nimconfig.h | 239 +++--- .../NimBLE-Arduino/src/nimconfig_rename.h | 53 ++ 29 files changed, 1515 insertions(+), 687 deletions(-) create mode 100644 lib/libesp32/NimBLE-Arduino/docs/Usage_tips.md create mode 100644 lib/libesp32/NimBLE-Arduino/examples/NimBLE_Scan_Continuous/NimBLE_Scan_Continuous.ino create mode 100644 lib/libesp32/NimBLE-Arduino/examples/NimBLE_Service_Data_Advertiser/NimBLE_Service_Data_Advertiser.ino create mode 100644 lib/libesp32/NimBLE-Arduino/src/nimconfig_rename.h diff --git a/lib/libesp32/NimBLE-Arduino/CHANGELOG.md b/lib/libesp32/NimBLE-Arduino/CHANGELOG.md index e763a3c6d..a76ef59a6 100644 --- a/lib/libesp32/NimBLE-Arduino/CHANGELOG.md +++ b/lib/libesp32/NimBLE-Arduino/CHANGELOG.md @@ -2,6 +2,70 @@ All notable changes to this project will be documented in this file. +## [1.2.0] - 2021-02-08 + +### Added +- `NimBLECharacteristic::getDescriptorByHandle`: Return the BLE Descriptor for the given handle. + +- `NimBLEDescriptor::getStringValue`: Get the value of this descriptor as a string. + +- `NimBLEServer::getServiceByHandle`: Get a service by its handle. + +- `NimBLEService::getCharacteristicByHandle`: Get a pointer to the characteristic object with the specified handle. + +- `NimBLEService::getCharacteristics`: Get the vector containing pointers to each characteristic associated with this service. +Overloads to get a vector containing pointers to all the characteristics in a service with the UUID. (supports multiple same UUID's in a service) + - `NimBLEService::getCharacteristics(const char *uuid)` + - `NimBLEService::getCharacteristics(const NimBLEUUID &uuid)` + +- `NimBLEAdvertisementData` New methods: + - `NimBLEAdvertisementData::addTxPower`: Adds transmission power to the advertisement. + - `NimBLEAdvertisementData::setPreferredParams`: Adds connection parameters to the advertisement. + - `NimBLEAdvertisementData::setURI`: Adds URI data to the advertisement. + +- `NimBLEAdvertising` New methods: + - `NimBLEAdvertising::setName`: Set the name advertised. + - `NimBLEAdvertising::setManufacturerData`: Adds manufacturer data to the advertisement. + - `NimBLEAdvertising::setURI`: Adds URI data to the advertisement. + - `NimBLEAdvertising::setServiceData`: Adds service data to the advertisement. + - `NimBLEAdvertising::addTxPower`: Adds transmission power to the advertisement. + - `NimBLEAdvertising::reset`: Stops the current advertising and resets the advertising data to the default values. + +- `NimBLEDevice::setScanFilterMode`: Set the controller duplicate filter mode for filtering scanned devices. + +- `NimBLEDevice::setScanDuplicateCacheSize`: Sets the number of advertisements filtered before the cache is reset. + +- `NimBLEScan::setMaxResults`: This allows for setting a maximum number of advertised devices stored in the results vector. + +- `NimBLEAdvertisedDevice` New data retrieval methods added: + - `haveAdvInterval/getAdvInterval`: checks if the interval is advertised / gets the advertisement interval value. + + - `haveConnParams/getMinInterval/getMaxInterval`: checks if the parameters are advertised / get min value / get max value. + + - `haveURI/getURI`: checks if a URI is advertised / gets the URI data. + + - `haveTargetAddress/getTargetAddressCount/getTargetAddress(index)`: checks if a target address is present / gets a count of the addresses targeted / gets the address of the target at index. + +### Changed +- `nimconfig.h` (Arduino) is now easier to use. + +- `NimBLEServer::getServiceByUUID` Now takes an extra parameter of instanceID to support multiple services with the same UUID. + +- `NimBLEService::getCharacteristic` Now takes an extra parameter of instanceID to support multiple characteristics with the same UUID. + +- `NimBLEAdvertising` Transmission power is no longer advertised by default and can be added to the advertisement by calling `NimBLEAdvertising::addTxPower` + +- `NimBLEAdvertising` Custom scan response data can now be used without custom advertisment. + +- `NimBLEScan` Now uses the controller duplicate filter. + +- `NimBLEAdvertisedDevice` Has been refactored to store the complete advertisement payload and no longer parses the data from each advertisement. +Instead the data will be parsed on-demand when the user application asks for specific data. + +### Fixed +- `NimBLEHIDDevice` Characteristics now use encryption, this resolves an issue with communicating with devices requiring encryption for HID devices. + + ## [1.1.0] - 2021-01-20 ### Added @@ -9,7 +73,7 @@ All notable changes to this project will be documented in this file. - New examples for securing and authenticating client/server connections, by mblasee. -- `NimBLEAdvertiseing::SetMinPreferred` and `NimBLEAdvertiseing::SetMinPreferred` re-added. +- `NimBLEAdvertising::SetMinPreferred` and `NimBLEAdvertising::SetMinPreferred` re-added. - Conditional checks added for command line config options in `nimconfig.h` to support custom configuration in platformio. @@ -71,6 +135,7 @@ advertised them as 16/32bit but resolved them to 128bits. Both are now checked. - (Arduino) Ensure controller mode is set to BLE Only. + ## [1.0.2] - 2020-09-13 ### Changed @@ -84,6 +149,7 @@ Any changes to the controller max connection settings in `sdkconfig.h` will now - (Arduino) Revert the previous change to fix the advertising start delay. Instead a replacement fix that routes all BLE controller commands from a task running on core 0 (same as the controller) has been implemented. This improves response times and reliability for all BLE functions. + ## [1.0.1] - 2020-09-02 ### Added diff --git a/lib/libesp32/NimBLE-Arduino/docs/Command_line_config.md b/lib/libesp32/NimBLE-Arduino/docs/Command_line_config.md index 813156f76..c22565f4f 100644 --- a/lib/libesp32/NimBLE-Arduino/docs/Command_line_config.md +++ b/lib/libesp32/NimBLE-Arduino/docs/Command_line_config.md @@ -1,93 +1,117 @@ # Arduino command line and platformio config options -`CONFIG_BT_NIMBLE_ROLE_CENTRAL_DISABLED` - - If defined, NimBLE Client functions will not be included. -- Reduces flash size by approx. 7kB. -
+`CONFIG_BT_NIMBLE_MAX_CONNECTIONS` -`CONFIG_BT_NIMBLE_ROLE_OBSERVER_DISABLED` +Sets the number of simultaneous connections (esp controller max is 9) +- Default value is 3 +
-If defined, NimBLE Scan functions will not be included. -- Reduces flash size by approx. 26kB. -
+`CONFIG_BT_NIMBLE_ATT_PREFERRED_MTU` -`CONFIG_BT_NIMBLE_ROLE_PERIPHERAL_DISABLED` +Sets the default MTU size. +- Default value is 255 +
-If defined NimBLE Server functions will not be included. -- Reduces flash size by approx. 16kB. -
+`CONFIG_BT_NIMBLE_SVC_GAP_DEVICE_NAME` -`CONFIG_BT_NIMBLE_ROLE_BROADCASTER_DISABLED` - -If defined, NimBLE Advertising functions will not be included. -- Reduces flash size by approx. 5kB. -
+Set the default device name +- Default value is "nimble" +
`CONFIG_BT_NIMBLE_DEBUG` If defined, enables debug log messages from the NimBLE host - Uses approx. 32kB of flash memory. -
+
`CONFIG_NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT` If defined, NimBLE host return codes will be printed as text in debug log messages. - Uses approx. 7kB of flash memory. -
+
`CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT` If defined, GAP event codes will be printed as text in debug log messages. - Uses approx. 1kB of flash memory. -
+
`CONFIG_NIMBLE_CPP_ENABLE_ADVERTISMENT_TYPE_TEXT` If defined, advertisment types will be printed as text while scanning in debug log messages. - Uses approx. 250 bytes of flash memory. -
+
+ +`CONFIG_BT_NIMBLE_SVC_GAP_APPEARANCE` + +Set the default appearance. +- Default value is 0x00 +
+ +`CONFIG_BT_NIMBLE_ROLE_CENTRAL_DISABLED` + +If defined, NimBLE Client functions will not be included. +- Reduces flash size by approx. 7kB. +
+ +`CONFIG_BT_NIMBLE_ROLE_OBSERVER_DISABLED` + +If defined, NimBLE Scan functions will not be included. +- Reduces flash size by approx. 26kB. +
+ +`CONFIG_BT_NIMBLE_ROLE_PERIPHERAL_DISABLED` + +If defined NimBLE Server functions will not be included. +- Reduces flash size by approx. 16kB. +
+ +`CONFIG_BT_NIMBLE_ROLE_BROADCASTER_DISABLED` + +If defined, NimBLE Advertising functions will not be included. +- Reduces flash size by approx. 5kB. +
+ +`CONFIG_BT_NIMBLE_MAX_BONDS` + +Sets the number of devices allowed to store/bond with +- Default value is 3 +
+ +`CONFIG_BT_NIMBLE_MAX_CCCDS` + +Sets the maximum number of CCCD subscriptions to store +- Default value is 8 +
+ +`CONFIG_BT_NIMBLE_RPA_TIMEOUT` + +Sets the random address refresh time in seconds. +- Default value is 900 +
+ +`CONFIG_BT_NIMBLE_MSYS1_BLOCK_COUNT` + +Set the number of msys blocks For prepare write & prepare responses. This may need to be increased if +you are sending large blocks of data with a low MTU. E.g: 512 bytes with 23 MTU will fail. +- Default value is 12 +
+ +`CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL` + +Sets the NimBLE stack to use external PSRAM will be loaded +- Must be defined with a value of 1; Default is CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_INTERNAL 1 +
`CONFIG_BT_NIMBLE_PINNED_TO_CORE` Sets the core the NimBLE host stack will run on - Options: 0 or 1 -
+
`CONFIG_BT_NIMBLE_TASK_STACK_SIZE` -Set the task stack size for the NimBLE core. +Set the task stack size for the NimBLE core. - Default is 4096 -
- - -`CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL` - -Sets the NimBLE stack to use external PSRAM will be loaded -- Must be defined with a value of 1; Default is CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_INTERNAL 1 -
- -`CONFIG_BT_NIMBLE_MAX_CONNECTIONS` - -Sets the number of simultaneous connections (esp controller max is 9) -- Default value is 3 -
- -`CONFIG_BT_NIMBLE_MAX_BONDS` - -Sets the number of devices allowed to store/bond with -- Default value is 3 -
- -`CONFIG_BT_NIMBLE_MAX_CCCDS` - -Sets the maximum number of CCCD subscriptions to store -- Default value is 8 -
- -`CONFIG_BT_NIMBLE_SVC_GAP_DEVICE_NAME` - -Set the default device name -- Default value is "nimble" -
+
diff --git a/lib/libesp32/NimBLE-Arduino/docs/Migration_guide.md b/lib/libesp32/NimBLE-Arduino/docs/Migration_guide.md index 69671824a..59854e5fd 100644 --- a/lib/libesp32/NimBLE-Arduino/docs/Migration_guide.md +++ b/lib/libesp32/NimBLE-Arduino/docs/Migration_guide.md @@ -69,6 +69,8 @@ For example `BLEServer::createService(SERVICE_UUID)` will work just as it did be ### Characteristics +The constructor for `(Nim)BLECharacteristic` is now private, so if you currently subclass it to add logic you should switch to use `NimBLEService::createCharacteristic` instead. Any custom processing logic previously in a `BLECharacteristic` subclass should be moved to a `NimBLECharacteristicCallbacks` subclass instead, and passed into `NimBLECharacteristic::setCallbacks`. + `BLEService::createCharacteristic` (`NimBLEService::createCharacteristic`) is used the same way as originally except the properties parameter has changed. When creating a characteristic the properties are now set with `NIMBLE_PROPERTY::XXXX` instead of `BLECharacteristic::XXXX`. @@ -218,10 +220,11 @@ If you wish to advertise these parameters you can still do so manually via `BLEA
Calling `NimBLEAdvertising::setAdvertisementData` will entirely replace any data set with `NimBLEAdvertising::addServiceUUID`, or -`NimBLEAdvertising::setAppearance`. You should set all the data you wish to advertise within the `NimBLEAdvertisementData` instead. +`NimBLEAdvertising::setAppearance` or similar methods. You should set all the data you wish to advertise within the `NimBLEAdvertisementData` instead. -Calling `NimBLEAdvertising::setScanResponseData` without also calling `NimBLEAdvertising::setAdvertisementData` will have no effect. -When using custom scan response data you must also use custom advertisement data. +~~Calling `NimBLEAdvertising::setScanResponseData` without also calling `NimBLEAdvertising::setAdvertisementData` will have no effect. +When using custom scan response data you must also use custom advertisement data.~~ +No longer true as of release 1.2.0 and above, custom scan response is now supported without custom advertisement data.
> BLEAdvertising::start (NimBLEAdvertising::start) diff --git a/lib/libesp32/NimBLE-Arduino/docs/Usage_tips.md b/lib/libesp32/NimBLE-Arduino/docs/Usage_tips.md new file mode 100644 index 000000000..b8edde2de --- /dev/null +++ b/lib/libesp32/NimBLE-Arduino/docs/Usage_tips.md @@ -0,0 +1,41 @@ +# Usage Tips + +## Put BLE functions in a task running on the NimBLE stack core + +When commands are sent to the stack from a differnt core they can experience delays in execution. +This library detects this and invokes the esp32 IPC to reroute these commands through the correct core but this also increases overhead. +Therefore it is highly recommended to create tasks for BLE to run on the same core, the macro `CONFIG_BT_NIMBLE_PINNED_TO_CORE` can be used to set the core. +
+ +## Do not delete client instances unless necessary or unused + +When a client instance has been created and has connected to a peer device and it has retrieved service/characteristic information it will store that data for the life of the client instance. +If you are periodically connecting to the same devices and you have deleted the client instance or the services when connecting again it will cause a retrieval of that information from the peer again. +This results in significant energy drain on the battery of the devices, fragments heap, and reduces connection performance. + +Client instances in this library use approximately 20% of the original bluedroid library, deleteing them will provide much less gain than it did before. + +It is recommended to retain the client instance in cases where the time between connecting to the same device is less than 5 minutes. +
+ +## Only retrieve the services and characteriscs needed + +As a client the use of `NimBLEClient::getServices` or `NimBLERemoteService::getCharacteristics` and using `true` for the parameter should be limited to devices that are not known. +Instead `NimBLEClient::getService(NimBLEUUID)` or `NimBLERemoteService::getCharacteristic(NimBLEUUID)` should be used to access certain attributes that are useful to the application. +This reduces energy consumed, heap allocated, connection time and improves overall efficiency. +
+ +## Check return values + +Many user issues can be avoided by checking if a function returned successfully, by either testing for true/false such as when calling `NimBLEClient::connect`, +or nullptr such as when calling `NimBLEClient::getService`. The latter being a must, as calling a method on a nullptr will surely result in a crash. +Most of the functions in this library return something that should be checked before proceeding. +
+ +## There will be bugs - please report them + +No code is bug free and unit testing will not find them all on it's own. If you encounter a bug, please report it along with any logs and decoded backtrace if applicable. +Best efforts will be made to correct any errors ASAP. + +Bug reports can be made at https://github.com/h2zero/NimBLE-Arduino/issues or https://github.com/h2zero/esp-nimble-cpp/issues. +Questions and suggestions will be happily accepted there as well. diff --git a/lib/libesp32/NimBLE-Arduino/examples/NimBLE_Scan_Continuous/NimBLE_Scan_Continuous.ino b/lib/libesp32/NimBLE-Arduino/examples/NimBLE_Scan_Continuous/NimBLE_Scan_Continuous.ino new file mode 100644 index 000000000..b8d24d264 --- /dev/null +++ b/lib/libesp32/NimBLE-Arduino/examples/NimBLE_Scan_Continuous/NimBLE_Scan_Continuous.ino @@ -0,0 +1,71 @@ +/** Example of continuous scanning for BLE advertisements. + * This example will scan forever while consuming as few resources as possible + * and report all advertisments on the serial monitor. + * + * Created: on January 31 2021 + * Author: H2zero + * + */ + +#include "NimBLEDevice.h" + +NimBLEScan* pBLEScan; + +class MyAdvertisedDeviceCallbacks: public NimBLEAdvertisedDeviceCallbacks { + void onResult(NimBLEAdvertisedDevice* advertisedDevice) { + Serial.printf("Advertised Device: %s \n", advertisedDevice->toString().c_str()); + } +}; + +void setup() { + Serial.begin(115200); + Serial.println("Scanning..."); + +/** *Optional* Sets the filtering mode used by the scanner in the BLE controller. + * + * Can be one of: + * CONFIG_BTDM_SCAN_DUPL_TYPE_DEVICE (0) (default) + * Filter by device address only, advertisements from the same address will be reported only once. + * + * CONFIG_BTDM_SCAN_DUPL_TYPE_DATA (1) + * Filter by data only, advertisements with the same data will only be reported once, + * even from different addresses. + * + * CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE (2) + * Filter by address and data, advertisements from the same address will be reported only once, + * except if the data in the advertisement has changed, then it will be reported again. + * + * Can only be used BEFORE calling NimBLEDevice::init. +*/ + NimBLEDevice::setScanFilterMode(CONFIG_BTDM_SCAN_DUPL_TYPE_DEVICE); + +/** *Optional* Sets the scan filter cache size in the BLE controller. + * When the number of duplicate advertisements seen by the controller + * reaches this value it will clear the cache and start reporting previously + * seen devices. The larger this number, the longer time between repeated + * device reports. Range 10 - 1000. (default 20) + * + * Can only be used BEFORE calling NimBLEDevice::init. + */ + NimBLEDevice::setScanDuplicateCacheSize(200); + + NimBLEDevice::init(""); + + pBLEScan = NimBLEDevice::getScan(); //create new scan + // Set the callback for when devices are discovered, no duplicates. + pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks(), false); + pBLEScan->setActiveScan(true); // Set active scanning, this will get more data from the advertiser. + pBLEScan->setInterval(97); // How often the scan occurs / switches channels; in milliseconds, + pBLEScan->setWindow(37); // How long to scan during the interval; in milliseconds. + pBLEScan->setMaxResults(0); // do not store the scan results, use callback only. +} + +void loop() { + // If an error occurs that stops the scan, it will be restarted here. + if(pBLEScan->isScanning() == false) { + // Start scan with: duration = 0 seconds(forever), no scan end callback, not a continuation of a previous scan. + pBLEScan->start(0, nullptr, false); + } + + delay(2000); +} \ No newline at end of file diff --git a/lib/libesp32/NimBLE-Arduino/examples/NimBLE_Service_Data_Advertiser/NimBLE_Service_Data_Advertiser.ino b/lib/libesp32/NimBLE-Arduino/examples/NimBLE_Service_Data_Advertiser/NimBLE_Service_Data_Advertiser.ino new file mode 100644 index 000000000..dd588fd22 --- /dev/null +++ b/lib/libesp32/NimBLE-Arduino/examples/NimBLE_Service_Data_Advertiser/NimBLE_Service_Data_Advertiser.ino @@ -0,0 +1,33 @@ +/** NimBLE_Service_Data_Advertiser Demo: + * + * Simple demo of advertising service data that changes every 5 seconds + * + * Created: on February 7 2021 + * Author: H2zero + * +*/ + +#include + +#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b" + +static NimBLEUUID dataUuid(SERVICE_UUID); +static NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising(); +static uint32_t count = 0; + +void setup() { + Serial.begin(115200); + Serial.println("Starting BLE work!"); + + NimBLEDevice::init("svc data"); +} + +void loop() { + pAdvertising->stop(); + pAdvertising->setServiceData(dataUuid, std::string((char*)&count, sizeof(count))); + pAdvertising->start(); + + Serial.printf("Advertising count = %d\n", count); + count++; + delay(5000); +} diff --git a/lib/libesp32/NimBLE-Arduino/library.json b/lib/libesp32/NimBLE-Arduino/library.json index a64024df6..a56985a06 100644 --- a/lib/libesp32/NimBLE-Arduino/library.json +++ b/lib/libesp32/NimBLE-Arduino/library.json @@ -2,7 +2,7 @@ "name": "NimBLE-Arduino", "keywords": "esp32, bluetooth", "description": "Bluetooth low energy (BLE) library for arduino-esp32 based on NimBLE", - "version": "1.1.0", + "version": "1.2.0", "frameworks": "arduino", "platforms": "espressif32" } diff --git a/lib/libesp32/NimBLE-Arduino/library.properties b/lib/libesp32/NimBLE-Arduino/library.properties index 7f2508333..4435958d1 100644 --- a/lib/libesp32/NimBLE-Arduino/library.properties +++ b/lib/libesp32/NimBLE-Arduino/library.properties @@ -1,5 +1,5 @@ name=NimBLE-Arduino -version=1.1.0 +version=1.2.0 author=h2zero maintainer=h2zero sentence=Bluetooth low energy (BLE) library for arduino-esp32 based on NimBLE. diff --git a/lib/libesp32/NimBLE-Arduino/src/NimBLEAdvertisedDevice.cpp b/lib/libesp32/NimBLE-Arduino/src/NimBLEAdvertisedDevice.cpp index 992b1f377..c697fe752 100644 --- a/lib/libesp32/NimBLE-Arduino/src/NimBLEAdvertisedDevice.cpp +++ b/lib/libesp32/NimBLE-Arduino/src/NimBLEAdvertisedDevice.cpp @@ -28,25 +28,14 @@ static const char* LOG_TAG = "NimBLEAdvertisedDevice"; /** * @brief Constructor */ -NimBLEAdvertisedDevice::NimBLEAdvertisedDevice() { +NimBLEAdvertisedDevice::NimBLEAdvertisedDevice() : + m_payload(62,0) +{ m_advType = 0; - m_appearance = 0; - m_manufacturerData = ""; - m_name = ""; m_rssi = -9999; - m_txPower = 0; - m_payloadLength = 0; - m_payload = nullptr; - - m_haveAppearance = false; - m_haveManufacturerData = false; - m_haveName = false; - m_haveRSSI = false; - m_haveServiceData = false; - m_haveServiceUUID = false; - m_haveTXPower = false; - m_callbackSent = false; - + m_callbackSent = false; + m_timestamp = 0; + m_advLength = 0; } // NimBLEAdvertisedDevice @@ -82,25 +71,126 @@ uint8_t NimBLEAdvertisedDevice::getAdvType() { * @return The appearance of the advertised device. */ uint16_t NimBLEAdvertisedDevice::getAppearance() { - return m_appearance; + uint8_t data_loc = 0; + + if(findAdvField(BLE_HS_ADV_TYPE_APPEARANCE, 0, &data_loc) > 0) { + ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc]; + if(field->length == BLE_HS_ADV_APPEARANCE_LEN + 1) { + return *field->value | *(field->value + 1) << 8; + } + } + + return 0; } // getAppearance +/** + * @brief Get the advertisement interval. + * @return The advertisement interval in 0.625ms units. + */ +uint16_t NimBLEAdvertisedDevice::getAdvInterval() { + uint8_t data_loc = 0; + + if(findAdvField(BLE_HS_ADV_TYPE_ADV_ITVL, 0, &data_loc) > 0) { + ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc]; + if(field->length == BLE_HS_ADV_ADV_ITVL_LEN + 1) { + return *field->value | *(field->value + 1) << 8; + } + } + + return 0; +} // getAdvInterval + + +/** + * @brief Get the preferred min connection interval. + * @return The preferred min connection interval in 1.25ms units. + */ +uint16_t NimBLEAdvertisedDevice::getMinInterval() { + uint8_t data_loc = 0; + + if(findAdvField(BLE_HS_ADV_TYPE_SLAVE_ITVL_RANGE, 0, &data_loc) > 0) { + ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc]; + if(field->length == BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN + 1) { + return *field->value | *(field->value + 1) << 8; + } + } + + return 0; +} // getMinInterval + + +/** + * @brief Get the preferred max connection interval. + * @return The preferred max connection interval in 1.25ms units. + */ +uint16_t NimBLEAdvertisedDevice::getMaxInterval() { + uint8_t data_loc = 0; + + if(findAdvField(BLE_HS_ADV_TYPE_SLAVE_ITVL_RANGE, 0, &data_loc) > 0) { + ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc]; + if(field->length == BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN + 1) { + return *(field->value + 2) | *(field->value + 3) << 8; + } + } + + return 0; +} // getMaxInterval + + /** * @brief Get the manufacturer data. * @return The manufacturer data of the advertised device. */ std::string NimBLEAdvertisedDevice::getManufacturerData() { - return m_manufacturerData; + uint8_t data_loc = 0; + + if(findAdvField(BLE_HS_ADV_TYPE_MFG_DATA, 0, &data_loc) > 0) { + ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc]; + if(field->length > 1) { + return std::string((char*)field->value, field->length - 1); + } + } + + return ""; } // getManufacturerData +/** + * @brief Get the URI from the advertisement. + * @return The URI data. + */ +std::string NimBLEAdvertisedDevice::getURI() { + uint8_t data_loc = 0; + + if(findAdvField(BLE_HS_ADV_TYPE_URI, 0, &data_loc) > 0) { + ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc]; + if(field->length > 1) { + return std::string((char*)field->value, field->length - 1); + } + } + + return ""; +} // getURI + + /** * @brief Get the advertised name. * @return The name of the advertised device. */ std::string NimBLEAdvertisedDevice::getName() { - return m_name; + uint8_t data_loc = 0; + + if(findAdvField(BLE_HS_ADV_TYPE_COMP_NAME, 0, &data_loc) > 0 || + findAdvField(BLE_HS_ADV_TYPE_INCOMP_NAME, 0, &data_loc) > 0) + { + ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc]; + if(field->length > 1) { + return std::string((char*)field->value, field->length - 1); + } + } + + return ""; } // getName @@ -122,17 +212,70 @@ NimBLEScan* NimBLEAdvertisedDevice::getScan() { } // getScan +/** + * @brief Get the number of target addresses. + * @return The number of addresses. + */ +size_t NimBLEAdvertisedDevice::getTargetAddressCount() { + uint8_t count = 0; + + count = findAdvField(BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR); + count += findAdvField(BLE_HS_ADV_TYPE_RANDOM_TGT_ADDR); + + return count; +} + + +/** + * @brief Get the target address at the index. + * @param [in] index The index of the target address. + * @return The target address. + */ +NimBLEAddress NimBLEAdvertisedDevice::getTargetAddress(uint8_t index) { + ble_hs_adv_field *field = nullptr; + uint8_t count = 0; + uint8_t data_loc = 0xFF; + + index++; + count = findAdvField(BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR, index, &data_loc); + + if (count < index) { + index -= count; + count = findAdvField(BLE_HS_ADV_TYPE_RANDOM_TGT_ADDR, index, &data_loc); + } + + if(count > 0 && data_loc != 0xFF) { + field = (ble_hs_adv_field *)&m_payload[data_loc]; + if(field->length < index * BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN) { + index -= count - field->length / BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN; + } + if(field->length > index * BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN) { + return NimBLEAddress(field->value + (index - 1) * BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN); + } + } + + return NimBLEAddress(""); +} + + /** * @brief Get the service data. - * @param [in] index The vector index of the service data requested. + * @param [in] index The index of the service data requested. * @return The advertised service data or empty string if no data. */ std::string NimBLEAdvertisedDevice::getServiceData(uint8_t index) { - if(index > m_serviceDataVec.size()) { - NIMBLE_LOGW(LOG_TAG, "getServiceData: index out of range"); - return ""; + ble_hs_adv_field *field = nullptr; + uint8_t bytes; + uint8_t data_loc = findServiceData(index, &bytes); + + if(data_loc != 0xFF) { + field = (ble_hs_adv_field *)&m_payload[data_loc]; + if(field->length > bytes) { + return std::string((char*)(field->value + bytes), field->length - bytes - 1); + } } - return m_serviceDataVec[index].second; + + return ""; } //getServiceData @@ -141,51 +284,148 @@ std::string NimBLEAdvertisedDevice::getServiceData(uint8_t index) { * @param [in] uuid The uuid of the service data requested. * @return The advertised service data or empty string if no data. */ -std::string NimBLEAdvertisedDevice::getServiceData(const NimBLEUUID &uuid) const { - for(auto &it : m_serviceDataVec) { - if(it.first == uuid) { - return it.second; +std::string NimBLEAdvertisedDevice::getServiceData(const NimBLEUUID &uuid) { + ble_hs_adv_field *field = nullptr; + uint8_t bytes; + uint8_t index = 0; + uint8_t data_loc = findServiceData(index, &bytes); + uint8_t uuidBytes = uuid.bitSize() / 8; + uint8_t plSize = m_payload.size() - 2; + + while(data_loc < plSize) { + field = (ble_hs_adv_field *)&m_payload[data_loc]; + if(bytes == uuidBytes && NimBLEUUID(field->value, bytes, false) == uuid) { + return std::string((char*)(field->value + bytes), field->length - bytes - 1); } + + index++; + data_loc = findServiceData(index, &bytes); } - NIMBLE_LOGW(LOG_TAG, "getServiceData: uuid not found"); + + NIMBLE_LOGI(LOG_TAG, "No service data found"); return ""; } //getServiceData /** - * @brief Get the advertised service UUID. - * @param [in] index The vector index of the service data UUID requested. - * @return The advertised service UUID or an empty UUID if not found. + * @brief Get the UUID of the serice data at the index. + * @param [in] index The index of the service data UUID requested. + * @return The advertised service data UUID or an empty UUID if not found. */ NimBLEUUID NimBLEAdvertisedDevice::getServiceDataUUID(uint8_t index) { - if(!haveServiceData() || index > m_serviceDataVec.size()) { - NIMBLE_LOGW(LOG_TAG, "getServiceDataUUID: index out of range"); - return NimBLEUUID(""); + ble_hs_adv_field *field = nullptr; + uint8_t bytes; + uint8_t data_loc = findServiceData(index, &bytes); + + if(data_loc != 0xFF) { + field = (ble_hs_adv_field *)&m_payload[data_loc]; + if(field->length >= bytes) { + return NimBLEUUID(field->value, bytes, false); + } } - return m_serviceDataVec[index].first; + + return NimBLEUUID(""); } // getServiceDataUUID +/** + * @brief Find the service data at the index. + * @param [in] index The index of the service data to find. + * @param [in] bytes A pointer to storage for the number of the bytes in the UUID. + * @return The index in the vector where the data is located, 0xFF if not found. + */ +uint8_t NimBLEAdvertisedDevice::findServiceData(uint8_t index, uint8_t *bytes) { + uint8_t data_loc = 0; + uint8_t found = 0; + + *bytes = 0; + index++; + found = findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID16, index, &data_loc); + if(found == index) { + *bytes = 2; + return data_loc; + } + + index -= found; + found = findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID32, index, &data_loc); + if(found == index) { + *bytes = 4; + return data_loc; + } + + index -= found; + found = findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID128, index, &data_loc); + if(found == index) { + *bytes = 16; + return data_loc; + } + + return 0xFF; +} + + /** * @brief Get the count of advertised service data UUIDS * @return The number of service data UUIDS in the vector. */ size_t NimBLEAdvertisedDevice::getServiceDataCount() { - return m_serviceDataVec.size(); + uint8_t count = 0; + + count += findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID16); + count += findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID32); + count += findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID128); + + return count; } // getServiceDataCount /** * @brief Get the Service UUID. - * @param [in] index The vector index of the service UUID requested. + * @param [in] index The index of the service UUID requested. * @return The Service UUID of the advertised service, or an empty UUID if not found. */ NimBLEUUID NimBLEAdvertisedDevice::getServiceUUID(uint8_t index) { - if(!haveServiceUUID() || index > m_serviceUUIDs.size()) { - NIMBLE_LOGW(LOG_TAG, "getServiceUUID: index out of range"); - return NimBLEUUID(""); + uint8_t count = 0; + uint8_t data_loc = 0; + uint8_t uuidBytes = 0; + uint8_t type = BLE_HS_ADV_TYPE_INCOMP_UUIDS16; + ble_hs_adv_field *field = nullptr; + + index++; + + do { + count = findAdvField(type, index, &data_loc); + if(count >= index) { + if(type < BLE_HS_ADV_TYPE_INCOMP_UUIDS32) { + uuidBytes = 2; + } else if(type < BLE_HS_ADV_TYPE_INCOMP_UUIDS128) { + uuidBytes = 4; + } else { + uuidBytes = 16; + } + break; + + } else { + type++; + index -= count; + } + + } while(type <= BLE_HS_ADV_TYPE_COMP_UUIDS128); + + if(uuidBytes > 0) { + field = (ble_hs_adv_field *)&m_payload[data_loc]; + // In the case of more than one field of service uuid's we need to adjust + // the index to account for the uuids of the previous fields. + if(field->length < index * uuidBytes) { + index -= count - field->length / uuidBytes; + } + + if(field->length > uuidBytes * index) { + return NimBLEUUID(field->value + uuidBytes * (index - 1), uuidBytes, false); + } } - return m_serviceUUIDs[index]; + + return NimBLEUUID(""); } // getServiceUUID @@ -194,18 +434,32 @@ NimBLEUUID NimBLEAdvertisedDevice::getServiceUUID(uint8_t index) { * @return The count of services in the advertising packet. */ size_t NimBLEAdvertisedDevice::getServiceUUIDCount() { - return m_serviceUUIDs.size(); + uint8_t count = 0; + + count += findAdvField(BLE_HS_ADV_TYPE_INCOMP_UUIDS16); + count += findAdvField(BLE_HS_ADV_TYPE_COMP_UUIDS16); + count += findAdvField(BLE_HS_ADV_TYPE_INCOMP_UUIDS32); + count += findAdvField(BLE_HS_ADV_TYPE_COMP_UUIDS32); + count += findAdvField(BLE_HS_ADV_TYPE_INCOMP_UUIDS128); + count += findAdvField(BLE_HS_ADV_TYPE_COMP_UUIDS128); + + return count; } // getServiceUUIDCount /** * @brief Check advertised services for existance of the required UUID + * @param [in] uuid The service uuid to look for in the advertisement. * @return Return true if service is advertised */ -bool NimBLEAdvertisedDevice::isAdvertisingService(const NimBLEUUID &uuid) const { - for (int i = 0; i < m_serviceUUIDs.size(); i++) { - if (m_serviceUUIDs[i].equals(uuid)) return true; +bool NimBLEAdvertisedDevice::isAdvertisingService(const NimBLEUUID &uuid) { + size_t count = getServiceUUIDCount(); + for(size_t i = 0; i < count; i++) { + if(uuid == getServiceUUID(i)) { + return true; + } } + return false; } // isAdvertisingService @@ -215,16 +469,43 @@ bool NimBLEAdvertisedDevice::isAdvertisingService(const NimBLEUUID &uuid) const * @return The TX Power of the advertised device. */ int8_t NimBLEAdvertisedDevice::getTXPower() { - return m_txPower; + uint8_t data_loc = 0; + + if(findAdvField(BLE_HS_ADV_TYPE_TX_PWR_LVL, 0, &data_loc) > 0) { + ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc]; + if(field->length == BLE_HS_ADV_TX_PWR_LVL_LEN + 1) { + return *(int8_t*)field->value; + } + } + + return -99; } // getTXPower +/** + * @brief Does this advertisement have preferred connection parameters? + * @return True if connection parameters are present. + */ +bool NimBLEAdvertisedDevice::haveConnParams() { + return findAdvField(BLE_HS_ADV_TYPE_SLAVE_ITVL_RANGE) > 0; +} // haveConnParams + + +/** + * @brief Does this advertisement have have the advertising interval? + * @return True if the advertisement interval is present. + */ +bool NimBLEAdvertisedDevice::haveAdvInterval() { + return findAdvField(BLE_HS_ADV_TYPE_ADV_ITVL) > 0; +} // haveAdvInterval + + /** * @brief Does this advertisement have an appearance value? * @return True if there is an appearance value present. */ bool NimBLEAdvertisedDevice::haveAppearance() { - return m_haveAppearance; + return findAdvField(BLE_HS_ADV_TYPE_APPEARANCE) > 0; } // haveAppearance @@ -233,16 +514,36 @@ bool NimBLEAdvertisedDevice::haveAppearance() { * @return True if there is manufacturer data present. */ bool NimBLEAdvertisedDevice::haveManufacturerData() { - return m_haveManufacturerData; + return findAdvField(BLE_HS_ADV_TYPE_MFG_DATA) > 0; } // haveManufacturerData +/** + * @brief Does this advertisement have a URI? + * @return True if there is a URI present. + */ +bool NimBLEAdvertisedDevice::haveURI() { + return findAdvField(BLE_HS_ADV_TYPE_URI) > 0; +} // haveURI + + +/** + * @brief Does the advertisement contain a target address? + * @return True if an address is present. + */ +bool NimBLEAdvertisedDevice::haveTargetAddress() { + return findAdvField(BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR) > 0 || + findAdvField(BLE_HS_ADV_TYPE_RANDOM_TGT_ADDR) > 0; +} + + /** * @brief Does this advertisement have a name value? * @return True if there is a name value present. */ bool NimBLEAdvertisedDevice::haveName() { - return m_haveName; + return findAdvField(BLE_HS_ADV_TYPE_COMP_NAME) > 0 || + findAdvField(BLE_HS_ADV_TYPE_INCOMP_NAME) > 0; } // haveName @@ -251,7 +552,7 @@ bool NimBLEAdvertisedDevice::haveName() { * @return True if there is a signal strength value present. */ bool NimBLEAdvertisedDevice::haveRSSI() { - return m_haveRSSI; + return m_rssi != -9999; } // haveRSSI @@ -260,7 +561,7 @@ bool NimBLEAdvertisedDevice::haveRSSI() { * @return True if there is a service data value present. */ bool NimBLEAdvertisedDevice::haveServiceData() { - return m_haveServiceData; + return getServiceDataCount() > 0; } // haveServiceData @@ -269,7 +570,7 @@ bool NimBLEAdvertisedDevice::haveServiceData() { * @return True if there is a service UUID value present. */ bool NimBLEAdvertisedDevice::haveServiceUUID() { - return m_haveServiceUUID; + return getServiceUUIDCount() > 0; } // haveServiceUUID @@ -278,143 +579,71 @@ bool NimBLEAdvertisedDevice::haveServiceUUID() { * @return True if there is a transmission power value present. */ bool NimBLEAdvertisedDevice::haveTXPower() { - return m_haveTXPower; + return findAdvField(BLE_HS_ADV_TYPE_TX_PWR_LVL) > 0; } // haveTXPower -/** - * @brief Parse the advertising pay load. - * - * The pay load is a buffer of bytes that is either 31 bytes long or terminated by - * a 0 length value. Each entry in the buffer has the format: - * [length][type][data...] - * - * The length does not include itself but does include everything after it until the next record. A record - * with a length value of 0 indicates a terminator. - * - * https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile - */ - void NimBLEAdvertisedDevice::parseAdvertisement(uint8_t* payload, uint8_t length) { - struct ble_hs_adv_fields fields; - int rc = ble_hs_adv_parse_fields(&fields, payload, length); - if (rc != 0) { - NIMBLE_LOGE(LOG_TAG, "Gap Event Parse ERROR."); - return; +uint8_t NimBLEAdvertisedDevice::findAdvField(uint8_t type, uint8_t index, uint8_t *data_loc) { + ble_hs_adv_field *field = nullptr; + uint8_t data = 0; + uint8_t length = m_payload.size(); + uint8_t count = 0; + + if(length < 2) { + return count; } - m_payload = payload; - m_payloadLength = length; + while (length > 1) { + field = (ble_hs_adv_field*)&m_payload[data]; -#if CONFIG_LOG_DEFAULT_LEVEL > 3 || (ARDUINO_ARCH_ESP32 && CORE_DEBUG_LEVEL >= 4) - char* pHex = NimBLEUtils::buildHexData(nullptr, m_payload, m_payloadLength); - NIMBLE_LOGD(LOG_TAG,"payload: %s", pHex); - free(pHex); -#endif - - if (fields.uuids16 != NULL) { - for (int i = 0; i < fields.num_uuids16; i++) { - setServiceUUID(NimBLEUUID(fields.uuids16[i].value)); + if (field->length >= length) { + return count; } - } - if (fields.uuids32 != NULL) { - for (int i = 0; i < fields.num_uuids32; i++) { - setServiceUUID(NimBLEUUID(fields.uuids32[i].value)); - } - } + if (field->type == type) { + switch(type) { + case BLE_HS_ADV_TYPE_INCOMP_UUIDS16: + case BLE_HS_ADV_TYPE_COMP_UUIDS16: + count += field->length / 2; + break; - if (fields.uuids128 != NULL) { - for (int i = 0; i < fields.num_uuids128; i++) { - setServiceUUID(NimBLEUUID(&fields.uuids128[i])); - } - } + case BLE_HS_ADV_TYPE_INCOMP_UUIDS32: + case BLE_HS_ADV_TYPE_COMP_UUIDS32: + count += field->length / 4; + break; - if (fields.name != NULL) { - setName(std::string(reinterpret_cast(fields.name), fields.name_len)); - } + case BLE_HS_ADV_TYPE_INCOMP_UUIDS128: + case BLE_HS_ADV_TYPE_COMP_UUIDS128: + count += field->length / 16; + break; - if (fields.tx_pwr_lvl_is_present) { - setTXPower(fields.tx_pwr_lvl); - } + case BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR: + case BLE_HS_ADV_TYPE_RANDOM_TGT_ADDR: + count += field->length / 6; + break; - if (fields.svc_data_uuid16 != NULL || - fields.svc_data_uuid32 != NULL || - fields.svc_data_uuid128 != NULL) - { - ble_hs_adv_field *field; - uint8_t *data = payload; - while(length > 1) { - field = (ble_hs_adv_field*)data; - - if(field->length > length) { - break; + default: + count++; + break; } - if(field->type == BLE_HS_ADV_TYPE_SVC_DATA_UUID16) { - if(field->length > 2) { - uint16_t uuid; - memcpy(&uuid, field->value, 2); - setServiceData(NimBLEUUID(uuid), std::string(reinterpret_cast(field->value + 2), field->length - 3)); + if(data_loc != nullptr) { + if(index == 0 || count >= index) { + break; } } - - if(field->type == BLE_HS_ADV_TYPE_SVC_DATA_UUID32) { - if(field->length > 4) { - uint32_t uuid; - memcpy(&uuid, field->value, 4); - setServiceData(NimBLEUUID(uuid), std::string(reinterpret_cast(field->value + 4), field->length - 5)); - } - } - - if(field->type == BLE_HS_ADV_TYPE_SVC_DATA_UUID128) { - if(field->length > 16) { - NimBLEUUID uuid(field->value, (size_t)16, false); - setServiceData(uuid, std::string(reinterpret_cast(field->value + 16), field->length - 17)); - } - } - - length -= 1 + field->length; - data += 1 + field->length; } + + length -= 1 + field->length; + data += 1 + field->length; } - if (fields.appearance_is_present) { - setAppearance(fields.appearance); + if(data_loc != nullptr && field != nullptr) { + *data_loc = data; } - if (fields.mfg_data != NULL) { - setManufacturerData(std::string(reinterpret_cast(fields.mfg_data), fields.mfg_data_len)); - } - -/* TODO: create storage and fucntions for these parameters - if (fields.public_tgt_addr != NULL) { - NIMBLE_LOGD(LOG_TAG, " public_tgt_addr="); - u8p = fields.public_tgt_addr; - for (i = 0; i < fields.num_public_tgt_addrs; i++) { - NIMBLE_LOGD(LOG_TAG, "public_tgt_addr=%s ", addr_str(u8p)); - u8p += BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN; - } - NIMBLE_LOGD(LOG_TAG, "\n"); - } - - if (fields.slave_itvl_range != NULL) { - NIMBLE_LOGD(LOG_TAG, " slave_itvl_range="); - print_bytes(fields.slave_itvl_range, BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN); - NIMBLE_LOGD(LOG_TAG, "\n"); - } - - if (fields.adv_itvl_is_present) { - NIMBLE_LOGD(LOG_TAG, " adv_itvl=0x%04x\n", fields.adv_itvl); - } - - if (fields.uri != NULL) { - NIMBLE_LOGD(LOG_TAG, " uri="); - print_bytes(fields.uri, fields.uri_len); - NIMBLE_LOGD(LOG_TAG, "\n"); - } -*/ - - } //parseAdvertisement + return count; +} /** @@ -428,106 +657,22 @@ void NimBLEAdvertisedDevice::setAddress(NimBLEAddress address) { /** * @brief Set the adFlag for this device. - * @param [in] The discovered adFlag. + * @param [in] advType The advertisement flag data from the advertisement. */ void NimBLEAdvertisedDevice::setAdvType(uint8_t advType) { m_advType = advType; } // setAdvType -/** - * @brief Set the appearance for this device. - * @param [in] The discovered appearance. - */ -void NimBLEAdvertisedDevice::setAppearance(uint16_t appearance) { - m_appearance = appearance; - m_haveAppearance = true; -} // setAppearance - - -/** - * @brief Set the manufacturer data for this device. - * @param [in] The discovered manufacturer data. - */ -void NimBLEAdvertisedDevice::setManufacturerData(std::string manufacturerData) { - m_manufacturerData = manufacturerData; - m_haveManufacturerData = true; -} // setManufacturerData - - -/** - * @brief Set the name for this device. - * @param [in] name The discovered name. - */ -void NimBLEAdvertisedDevice::setName(std::string name) { - m_name = name; - m_haveName = true; -} // setName - - /** * @brief Set the RSSI for this device. - * @param [in] rssi The discovered RSSI. + * @param [in] rssi The RSSI of the discovered device. */ void NimBLEAdvertisedDevice::setRSSI(int rssi) { - m_rssi = rssi; - m_haveRSSI = true; + m_rssi = rssi; } // setRSSI -/** - * @brief Set the Service UUID for this device. - * @param [in] serviceUUID The discovered serviceUUID - */ - -void NimBLEAdvertisedDevice::setServiceUUID(const char* serviceUUID) { - return setServiceUUID(NimBLEUUID(serviceUUID)); -} // setServiceUUID - - -/** - * @brief Set the Service UUID for this device. - * @param [in] serviceUUID The discovered serviceUUID - */ -void NimBLEAdvertisedDevice::setServiceUUID(NimBLEUUID serviceUUID) { - // Don't add duplicates - for (int i = 0; i < m_serviceUUIDs.size(); i++) { - if (m_serviceUUIDs[i] == serviceUUID) { - return; - } - } - m_serviceUUIDs.push_back(serviceUUID); - m_haveServiceUUID = true; -} // setServiceUUID - - -/** - * @brief Set the ServiceData value. - * @param [in] uuid The UUID that the service data belongs to. - * @param [in] data The service data. - */ -void NimBLEAdvertisedDevice::setServiceData(NimBLEUUID uuid, std::string data) { - m_haveServiceData = true; - for(auto &it : m_serviceDataVec) { - if(it.first == uuid) { - it.second = data; - return; - } - } - m_serviceDataVec.push_back({uuid, data}); -} //setServiceData - - -/** - * @brief Set the power level for this device. - * @param [in] txPower The discovered power level. - */ -void NimBLEAdvertisedDevice::setTXPower(int8_t txPower) { - m_txPower = txPower; - m_haveTXPower = true; -} // setTXPower - - /** * @brief Create a string representation of this device. * @return A string representation of this device. @@ -579,10 +724,35 @@ std::string NimBLEAdvertisedDevice::toString() { * @return The advertisement payload. */ uint8_t* NimBLEAdvertisedDevice::getPayload() { - return m_payload; + return &m_payload[0]; } // getPayload +/** + * @brief Stores the payload of the advertised device in a vector. + * @param [in] payload The advertisement payload. + * @param [in] length The length of the payload in bytes. + * @param [in] append Indicates if the the data should be appended (scan response). + */ +void NimBLEAdvertisedDevice::setPayload(uint8_t *payload, uint8_t length, bool append) { + if(!append) { + m_advLength = length; + m_payload.assign(payload, payload + length); + } else { + m_payload.insert(m_payload.end(), payload, payload + length); + } +} + + +/** + * @brief Get the length of the advertisement data in the payload. + * @return The number of bytes in the payload that is from the advertisment. + */ +uint8_t NimBLEAdvertisedDevice::getAdvLength() { + return m_advLength; +} + + /** * @brief Get the advertised device address type. * @return The device address type: @@ -610,7 +780,7 @@ time_t NimBLEAdvertisedDevice::getTimestamp() { * @return The size of the payload in bytes. */ size_t NimBLEAdvertisedDevice::getPayloadLength() { - return m_payloadLength; + return m_payload.size(); } // getPayloadLength diff --git a/lib/libesp32/NimBLE-Arduino/src/NimBLEAdvertisedDevice.h b/lib/libesp32/NimBLE-Arduino/src/NimBLEAdvertisedDevice.h index ebdb85c9e..ef354bc41 100644 --- a/lib/libesp32/NimBLE-Arduino/src/NimBLEAdvertisedDevice.h +++ b/lib/libesp32/NimBLE-Arduino/src/NimBLEAdvertisedDevice.h @@ -44,7 +44,11 @@ public: NimBLEAddress getAddress(); uint8_t getAdvType(); uint16_t getAppearance(); + uint16_t getAdvInterval(); + uint16_t getMinInterval(); + uint16_t getMaxInterval(); std::string getManufacturerData(); + std::string getURI(); /** * @brief A template to convert the service data to . @@ -67,7 +71,7 @@ public: NimBLEScan* getScan(); size_t getServiceDataCount(); std::string getServiceData(uint8_t index = 0); - std::string getServiceData(const NimBLEUUID &uuid) const; + std::string getServiceData(const NimBLEUUID &uuid); /** * @brief A template to convert the service data to . @@ -106,12 +110,15 @@ public: NimBLEUUID getServiceDataUUID(uint8_t index = 0); NimBLEUUID getServiceUUID(uint8_t index = 0); size_t getServiceUUIDCount(); + NimBLEAddress getTargetAddress(uint8_t index = 0); + size_t getTargetAddressCount(); int8_t getTXPower(); uint8_t* getPayload(); + uint8_t getAdvLength(); size_t getPayloadLength(); uint8_t getAddressType(); time_t getTimestamp(); - bool isAdvertisingService(const NimBLEUUID &uuid) const; + bool isAdvertisingService(const NimBLEUUID &uuid); bool haveAppearance(); bool haveManufacturerData(); bool haveName(); @@ -119,46 +126,30 @@ public: bool haveServiceData(); bool haveServiceUUID(); bool haveTXPower(); + bool haveConnParams(); + bool haveAdvInterval(); + bool haveTargetAddress(); + bool haveURI(); std::string toString(); private: friend class NimBLEScan; - void parseAdvertisement(uint8_t* payload, uint8_t length); - void setAddress(NimBLEAddress address); - void setAdvType(uint8_t advType); - void setAppearance(uint16_t appearance); - void setManufacturerData(std::string manufacturerData); - void setName(std::string name); - void setRSSI(int rssi); - void setServiceData(NimBLEUUID serviceUUID, std::string data); - void setServiceUUID(const char* serviceUUID); - void setServiceUUID(NimBLEUUID serviceUUID); - void setTXPower(int8_t txPower); - - bool m_haveAppearance; - bool m_haveManufacturerData; - bool m_haveName; - bool m_haveRSSI; - bool m_haveServiceData; - bool m_haveServiceUUID; - bool m_haveTXPower; - + void setAddress(NimBLEAddress address); + void setAdvType(uint8_t advType); + void setPayload(uint8_t *payload, uint8_t length, bool append); + void setRSSI(int rssi); + uint8_t findAdvField(uint8_t type, uint8_t index = 0, uint8_t *data_loc = nullptr); + uint8_t findServiceData(uint8_t index, uint8_t* bytes); NimBLEAddress m_address = NimBLEAddress(""); uint8_t m_advType; - uint16_t m_appearance; - std::string m_manufacturerData; - std::string m_name; int m_rssi; - int8_t m_txPower; - uint8_t* m_payload; - size_t m_payloadLength; time_t m_timestamp; bool m_callbackSent; + uint8_t m_advLength; - std::vector m_serviceUUIDs; - std::vector>m_serviceDataVec; + std::vector m_payload; }; /** diff --git a/lib/libesp32/NimBLE-Arduino/src/NimBLEAdvertising.cpp b/lib/libesp32/NimBLE-Arduino/src/NimBLEAdvertising.cpp index a10480410..3e9ae4a64 100644 --- a/lib/libesp32/NimBLE-Arduino/src/NimBLEAdvertising.cpp +++ b/lib/libesp32/NimBLE-Arduino/src/NimBLEAdvertising.cpp @@ -32,23 +32,29 @@ static const char* LOG_TAG = "NimBLEAdvertising"; /** * @brief Construct a default advertising object. */ -NimBLEAdvertising::NimBLEAdvertising() : m_slaveItvl() { +NimBLEAdvertising::NimBLEAdvertising() { + reset(); +} // NimBLEAdvertising + + +/** + * @brief Stops the current advertising and resets the advertising data to the default values. + */ +void NimBLEAdvertising::reset() { + if(NimBLEDevice::getInitialized() && isAdvertising()) { + stop(); + } memset(&m_advData, 0, sizeof m_advData); memset(&m_scanData, 0, sizeof m_scanData); memset(&m_advParams, 0, sizeof m_advParams); + memset(&m_slaveItvl, 0, sizeof m_slaveItvl); const char *name = ble_svc_gap_device_name(); m_advData.name = (uint8_t *)name; m_advData.name_len = strlen(name); m_advData.name_is_complete = 1; - m_advData.tx_pwr_lvl_is_present = 1; m_advData.tx_pwr_lvl = NimBLEDevice::getPower(); m_advData.flags = (BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP); - m_advData.appearance = 0; - m_advData.appearance_is_present = 0; - m_advData.mfg_data_len = 0; - m_advData.mfg_data = nullptr; - m_advData.slave_itvl_range = nullptr; #if !defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) m_advParams.conn_mode = BLE_GAP_CONN_MODE_NON; @@ -56,17 +62,13 @@ NimBLEAdvertising::NimBLEAdvertising() : m_slaveItvl() { m_advParams.conn_mode = BLE_GAP_CONN_MODE_UND; #endif m_advParams.disc_mode = BLE_GAP_DISC_MODE_GEN; - m_advParams.itvl_min = 0; - m_advParams.itvl_max = 0; - m_customAdvData = false; m_customScanResponseData = false; m_scanResp = true; m_advDataSet = false; // Set this to non-zero to prevent auto start if host reset before started by app. m_duration = BLE_HS_FOREVER; - -} // NimBLEAdvertising +} // reset /** @@ -85,6 +87,7 @@ void NimBLEAdvertising::addServiceUUID(const NimBLEUUID &serviceUUID) { */ void NimBLEAdvertising::addServiceUUID(const char* serviceUUID) { addServiceUUID(NimBLEUUID(serviceUUID)); + m_advDataSet = false; } // addServiceUUID @@ -112,9 +115,95 @@ void NimBLEAdvertising::removeServiceUUID(const NimBLEUUID &serviceUUID) { void NimBLEAdvertising::setAppearance(uint16_t appearance) { m_advData.appearance = appearance; m_advData.appearance_is_present = 1; + m_advDataSet = false; } // setAppearance +/** + * @brief Add the transmission power level to the advertisement packet. + */ +void NimBLEAdvertising::addTxPower() { + m_advData.tx_pwr_lvl_is_present = 1; + m_advDataSet = false; +} // addTxPower + + +/** + * @brief Set the advertised name of the device. + * @param [in] name The name to advertise. + */ +void NimBLEAdvertising::setName(const std::string &name) { + m_name.assign(name.begin(), name.end()); + m_advData.name = &m_name[0]; + m_advData.name_len = m_name.size(); + m_advDataSet = false; +} // setName + + +/** + * @brief Set the advertised manufacturer data. + * @param [in] data The data to advertise. + */ +void NimBLEAdvertising::setManufacturerData(const std::string &data) { + m_mfgData.assign(data.begin(), data.end()); + m_advData.mfg_data = &m_mfgData[0]; + m_advData.mfg_data_len = m_mfgData.size(); + m_advDataSet = false; +} // setManufacturerData + + +/** + * @brief Set the advertised URI. + * @param [in] uri The URI to advertise. + */ +void NimBLEAdvertising::setURI(const std::string &uri) { + m_uri.assign(uri.begin(), uri.end()); + m_advData.uri = &m_uri[0]; + m_advData.uri_len = m_uri.size(); + m_advDataSet = false; +} // setURI + + +/** + * @brief Set the service data advertised for the UUID. + * @param [in] uuid The UUID the service data belongs to. + * @param [in] data The data to advertise. + * @note If data length is 0 the service data will not be advertised. + */ +void NimBLEAdvertising::setServiceData(const NimBLEUUID &uuid, const std::string &data) { + switch (uuid.bitSize()) { + case 16: { + m_svcData16.assign((uint8_t*)&uuid.getNative()->u16.value, (uint8_t*)&uuid.getNative()->u16.value + 2); + m_svcData16.insert(m_svcData16.end(), data.begin(), data.end()); + m_advData.svc_data_uuid16 = (uint8_t*)&m_svcData16[0]; + m_advData.svc_data_uuid16_len = (data.length() > 0) ? m_svcData16.size() : 0; + break; + } + + case 32: { + m_svcData32.assign((uint8_t*)&uuid.getNative()->u32.value, (uint8_t*)&uuid.getNative()->u32.value + 4); + m_svcData32.insert(m_svcData32.end(), data.begin(), data.end()); + m_advData.svc_data_uuid32 = (uint8_t*)&m_svcData32[0]; + m_advData.svc_data_uuid32_len = (data.length() > 0) ? m_svcData32.size() : 0; + break; + } + + case 128: { + m_svcData128.assign(uuid.getNative()->u128.value, uuid.getNative()->u128.value + 16); + m_svcData128.insert(m_svcData128.end(), data.begin(), data.end()); + m_advData.svc_data_uuid128 = (uint8_t*)&m_svcData128[0]; + m_advData.svc_data_uuid128_len = (data.length() > 0) ? m_svcData128.size() : 0; + break; + } + + default: + return; + } + + m_advDataSet = false; +} // setServiceData + + /** * @brief Set the type of advertisment to use. * @param [in] adv_type: @@ -172,6 +261,8 @@ void NimBLEAdvertising::setMinPreferred(uint16_t mininterval) { m_slaveItvl[2] = m_slaveItvl[0]; m_slaveItvl[3] = m_slaveItvl[1]; } + + m_advDataSet = false; } // setMinPreferred @@ -200,6 +291,8 @@ void NimBLEAdvertising::setMaxPreferred(uint16_t maxinterval) { m_slaveItvl[0] = m_slaveItvl[2]; m_slaveItvl[1] = m_slaveItvl[3]; } + + m_advDataSet = false; } // setMaxPreferred @@ -209,6 +302,7 @@ void NimBLEAdvertising::setMaxPreferred(uint16_t maxinterval) { */ void NimBLEAdvertising::setScanResponse(bool set) { m_scanResp = set; + m_advDataSet = false; } // setScanResponse @@ -344,12 +438,29 @@ bool NimBLEAdvertising::start(uint32_t duration, void (*advCompleteCB)(NimBLEAdv if (!m_customAdvData && !m_advDataSet) { //start with 3 bytes for the flags data uint8_t payloadLen = (2 + 1); + if(m_advData.mfg_data_len > 0) + payloadLen += (2 + m_advData.mfg_data_len); + + if(m_advData.svc_data_uuid16_len > 0) + payloadLen += (2 + m_advData.svc_data_uuid16_len); + + if(m_advData.svc_data_uuid32_len > 0) + payloadLen += (2 + m_advData.svc_data_uuid32_len); + + if(m_advData.svc_data_uuid128_len > 0) + payloadLen += (2 + m_advData.svc_data_uuid128_len); + + if(m_advData.uri_len > 0) + payloadLen += (2 + m_advData.uri_len); + if(m_advData.appearance_is_present) payloadLen += (2 + BLE_HS_ADV_APPEARANCE_LEN); + if(m_advData.tx_pwr_lvl_is_present) - payloadLen += (2 + 1); + payloadLen += (2 + BLE_HS_ADV_TX_PWR_LVL_LEN); + if(m_advData.slave_itvl_range != nullptr) - payloadLen += (2 + 4); + payloadLen += (2 + BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN); for(auto &it : m_serviceUUIDs) { if(it.getNative()->u.type == BLE_UUID_TYPE_16) { @@ -419,7 +530,7 @@ bool NimBLEAdvertising::start(uint32_t duration, void (*advCompleteCB)(NimBLEAdv // check if there is room for the name, if not put it in scan data if((payloadLen + (2 + m_advData.name_len)) > BLE_HS_ADV_MAX_SZ) { - if(m_scanResp){ + if(m_scanResp && !m_customScanResponseData){ m_scanData.name = m_advData.name; m_scanData.name_len = m_advData.name_len; if(m_scanData.name_len > BLE_HS_ADV_MAX_SZ - 2) { @@ -433,7 +544,6 @@ bool NimBLEAdvertising::start(uint32_t duration, void (*advCompleteCB)(NimBLEAdv m_advData.name_is_complete = 0; } else { if(m_advData.tx_pwr_lvl_is_present) { - m_advData.tx_pwr_lvl = 0; m_advData.tx_pwr_lvl_is_present = 0; payloadLen -= (2 + 1); } @@ -446,7 +556,7 @@ bool NimBLEAdvertising::start(uint32_t duration, void (*advCompleteCB)(NimBLEAdv } } - if(m_scanResp) { + if(m_scanResp && !m_customScanResponseData) { rc = ble_gap_adv_rsp_set_fields(&m_scanData); switch(rc) { case 0: @@ -581,7 +691,7 @@ void NimBLEAdvertising::advCompleteCB() { if(m_advCompCB != nullptr) { m_advCompCB(this); } -} +} // advCompleteCB /** @@ -590,7 +700,7 @@ void NimBLEAdvertising::advCompleteCB() { */ bool NimBLEAdvertising::isAdvertising() { return ble_gap_adv_active(); -} +} // isAdvertising /* @@ -608,7 +718,7 @@ void NimBLEAdvertising::onHostSync() { // Otherwise we should tell the app that advertising stopped. advCompleteCB(); } -} +} // onHostSync /** @@ -646,6 +756,7 @@ int NimBLEAdvertising::handleGapEvent(struct ble_gap_event *event, void *arg) { */ void NimBLEAdvertisementData::addData(const std::string &data) { if ((m_payload.length() + data.length()) > BLE_HS_ADV_MAX_SZ) { + NIMBLE_LOGE(LOG_TAG, "Advertisement data length exceded"); return; } m_payload.append(data); @@ -657,11 +768,8 @@ void NimBLEAdvertisementData::addData(const std::string &data) { * @param [in] data The data to be added to the payload. * @param [in] length The size of data to be added to the payload. */ -void NimBLEAdvertisementData::addData(char * data, size_t length){ - if ((m_payload.length() + length) > BLE_HS_ADV_MAX_SZ) { - return; - } - m_payload.append(data,length); +void NimBLEAdvertisementData::addData(char * data, size_t length) { + addData(std::string(data, length)); } // addData @@ -680,43 +788,6 @@ void NimBLEAdvertisementData::setAppearance(uint16_t appearance) { } // setAppearance -/** - * @brief Set the complete services to advertise. - * @param [in] uuid The UUID of the service. - */ -void NimBLEAdvertisementData::setCompleteServices(const NimBLEUUID &uuid) { - char cdata[2]; - switch (uuid.bitSize()) { - case 16: { - // [Len] [0x02] [LL] [HH] - cdata[0] = 3; - cdata[1] = BLE_HS_ADV_TYPE_COMP_UUIDS16; // 0x03 - addData(std::string(cdata, 2) + std::string((char*) &uuid.getNative()->u16.value, 2)); - break; - } - - case 32: { - // [Len] [0x04] [LL] [LL] [HH] [HH] - cdata[0] = 5; - cdata[1] = BLE_HS_ADV_TYPE_COMP_UUIDS32; // 0x05 - addData(std::string(cdata, 2) + std::string((char*) &uuid.getNative()->u32.value, 4)); - break; - } - - case 128: { - // [Len] [0x04] [0] [1] ... [15] - cdata[0] = 17; - cdata[1] = BLE_HS_ADV_TYPE_COMP_UUIDS128; // 0x07 - addData(std::string(cdata, 2) + std::string((char*) uuid.getNative()->u128.value, 16)); - break; - } - - default: - return; - } -} // setCompleteServices - - /** * @brief Set the advertisement flags. * @param [in] flag The flags to be set in the advertisement. @@ -738,64 +809,141 @@ void NimBLEAdvertisementData::setFlags(uint8_t flag) { * @param [in] data The manufacturer data to advertise. */ void NimBLEAdvertisementData::setManufacturerData(const std::string &data) { - NIMBLE_LOGD("NimBLEAdvertisementData", ">> setManufacturerData"); char cdata[2]; cdata[0] = data.length() + 1; cdata[1] = BLE_HS_ADV_TYPE_MFG_DATA ; // 0xff addData(std::string(cdata, 2) + data); - NIMBLE_LOGD("NimBLEAdvertisementData", "<< setManufacturerData"); } // setManufacturerData +/** + * @brief Set the URI to advertise. + * @param [in] uri The uri to advertise. + */ +void NimBLEAdvertisementData::setURI(const std::string &uri) { + char cdata[2]; + cdata[0] = uri.length() + 1; + cdata[1] = BLE_HS_ADV_TYPE_URI; + addData(std::string(cdata, 2) + uri); +} // setURI + + /** * @brief Set the complete name of this device. * @param [in] name The name to advertise. */ void NimBLEAdvertisementData::setName(const std::string &name) { - NIMBLE_LOGD("NimBLEAdvertisementData", ">> setName: %s", name.c_str()); char cdata[2]; cdata[0] = name.length() + 1; cdata[1] = BLE_HS_ADV_TYPE_COMP_NAME; // 0x09 addData(std::string(cdata, 2) + name); - NIMBLE_LOGD("NimBLEAdvertisementData", "<< setName"); } // setName /** - * @brief Set the partial services to advertise. - * @param [in] uuid The single service to advertise. + * @brief Set a single service to advertise as a complete list of services. + * @param [in] uuid The service to advertise. + */ +void NimBLEAdvertisementData::setCompleteServices(const NimBLEUUID &uuid) { + setServices(true, uuid.bitSize(), {uuid}); +} // setCompleteServices + + +/** + * @brief Set the complete list of 16 bit services to advertise. + * @param [in] v_uuid A vector of 16 bit UUID's to advertise. + */ +void NimBLEAdvertisementData::setCompleteServices16(const std::vector& v_uuid) { + setServices(true, 16, v_uuid); +} // setCompleteServices16 + + +/** + * @brief Set the complete list of 32 bit services to advertise. + * @param [in] v_uuid A vector of 32 bit UUID's to advertise. + */ +void NimBLEAdvertisementData::setCompleteServices32(const std::vector& v_uuid) { + setServices(true, 32, v_uuid); +} // setCompleteServices32 + + +/** + * @brief Set a single service to advertise as a partial list of services. + * @param [in] uuid The service to advertise. */ void NimBLEAdvertisementData::setPartialServices(const NimBLEUUID &uuid) { + setServices(false, uuid.bitSize(), {uuid}); +} // setPartialServices + + +/** + * @brief Set the partial list of services to advertise. + * @param [in] v_uuid A vector of 16 bit UUID's to advertise. + */ +void NimBLEAdvertisementData::setPartialServices16(const std::vector& v_uuid) { + setServices(false, 16, v_uuid); +} // setPartialServices16 + + +/** + * @brief Set the partial list of services to advertise. + * @param [in] v_uuid A vector of 32 bit UUID's to advertise. + */ +void NimBLEAdvertisementData::setPartialServices32(const std::vector& v_uuid) { + setServices(false, 32, v_uuid); +} // setPartialServices32 + + +/** + * @brief Utility function to create the list of service UUID's from a vector. + * @param [in] complete If true the vector is the complete set of services. + * @param [in] size The bit size of the UUID's in the vector. (16, 32, or 128). + * @param [in] v_uuid The vector of service UUID's to advertise. + */ +void NimBLEAdvertisementData::setServices(const bool complete, const uint8_t size, + const std::vector &v_uuid) +{ char cdata[2]; - switch (uuid.bitSize()) { - case 16: { - // [Len] [0x02] [LL] [HH] - cdata[0] = 3; - cdata[1] = BLE_HS_ADV_TYPE_INCOMP_UUIDS16; // 0x02 - addData(std::string(cdata, 2) + std::string((char *) &uuid.getNative()->u16.value, 2)); + cdata[0] = (size / 8) * v_uuid.size() + 1; + switch(size) { + case 16: + cdata[1] = complete ? BLE_HS_ADV_TYPE_COMP_UUIDS16 : BLE_HS_ADV_TYPE_INCOMP_UUIDS16; break; - } - - case 32: { - // [Len] [0x04] [LL] [LL] [HH] [HH] - cdata[0] = 5; - cdata[1] = BLE_HS_ADV_TYPE_INCOMP_UUIDS32; // 0x04 - addData(std::string(cdata, 2) + std::string((char *) &uuid.getNative()->u32.value, 4)); + case 32: + cdata[1] = complete ? BLE_HS_ADV_TYPE_COMP_UUIDS32 : BLE_HS_ADV_TYPE_INCOMP_UUIDS32; break; - } - - case 128: { - // [Len] [0x04] [0] [1] ... [15] - cdata[0] = 17; - cdata[1] = BLE_HS_ADV_TYPE_INCOMP_UUIDS128; // 0x06 - addData(std::string(cdata, 2) + std::string((char *) &uuid.getNative()->u128.value, 16)); + case 128: + cdata[1] = complete ? BLE_HS_ADV_TYPE_COMP_UUIDS128 : BLE_HS_ADV_TYPE_INCOMP_UUIDS128; break; - } - default: return; } -} // setPartialServices + + std::string uuids; + + for(auto &it : v_uuid){ + if(it.bitSize() != size) { + NIMBLE_LOGE(LOG_TAG, "Service UUID(%d) invalid", size); + return; + } else { + switch(size) { + case 16: + uuids += std::string((char*)&it.getNative()->u16.value, 2); + break; + case 32: + uuids += std::string((char*)&it.getNative()->u32.value, 4); + break; + case 128: + uuids += std::string((char*)&it.getNative()->u128.value, 16); + break; + default: + return; + } + } + } + + addData(std::string(cdata, 2) + uuids); +} // setServices /** @@ -841,15 +989,42 @@ void NimBLEAdvertisementData::setServiceData(const NimBLEUUID &uuid, const std:: * @param [in] name The short name of the device. */ void NimBLEAdvertisementData::setShortName(const std::string &name) { - NIMBLE_LOGD("NimBLEAdvertisementData", ">> setShortName: %s", name.c_str()); char cdata[2]; cdata[0] = name.length() + 1; cdata[1] = BLE_HS_ADV_TYPE_INCOMP_NAME; // 0x08 addData(std::string(cdata, 2) + name); - NIMBLE_LOGD("NimBLEAdvertisementData", "<< setShortName"); } // setShortName +/** + * @brief Adds Tx power level to the advertisement data. + */ +void NimBLEAdvertisementData::addTxPower() { + char cdata[3]; + cdata[0] = BLE_HS_ADV_TX_PWR_LVL_LEN + 1; + cdata[1] = BLE_HS_ADV_TYPE_TX_PWR_LVL; + cdata[2] = NimBLEDevice::getPower(); + addData(cdata, 3); +} // addTxPower + + +/** + * @brief Set the preferred connection interval parameters. + * @param [in] min The minimum interval desired. + * @param [in] max The maximum interval desired. + */ +void NimBLEAdvertisementData::setPreferredParams(uint16_t min, uint16_t max) { + char cdata[6]; + cdata[0] = BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN + 1; + cdata[1] = BLE_HS_ADV_TYPE_SLAVE_ITVL_RANGE; + cdata[2] = min; + cdata[3] = min >> 8; + cdata[4] = max; + cdata[5] = max >> 8; + addData(cdata, 6); +} // setPreferredParams + + /** * @brief Retrieve the payload that is to be advertised. * @return The payload that is to be advertised. diff --git a/lib/libesp32/NimBLE-Arduino/src/NimBLEAdvertising.h b/lib/libesp32/NimBLE-Arduino/src/NimBLEAdvertising.h index 0d97ecbbc..17a866561 100644 --- a/lib/libesp32/NimBLE-Arduino/src/NimBLEAdvertising.h +++ b/lib/libesp32/NimBLE-Arduino/src/NimBLEAdvertising.h @@ -50,18 +50,27 @@ class NimBLEAdvertisementData { public: void setAppearance(uint16_t appearance); void setCompleteServices(const NimBLEUUID &uuid); + void setCompleteServices16(const std::vector &v_uuid); + void setCompleteServices32(const std::vector &v_uuid); void setFlags(uint8_t); void setManufacturerData(const std::string &data); + void setURI(const std::string &uri); void setName(const std::string &name); void setPartialServices(const NimBLEUUID &uuid); + void setPartialServices16(const std::vector &v_uuid); + void setPartialServices32(const std::vector &v_uuid); void setServiceData(const NimBLEUUID &uuid, const std::string &data); void setShortName(const std::string &name); void addData(const std::string &data); // Add data to the payload. void addData(char * data, size_t length); + void addTxPower(); + void setPreferredParams(uint16_t min, uint16_t max); std::string getPayload(); // Retrieve the current advert payload. private: friend class NimBLEAdvertising; + void setServices(const bool complete, const uint8_t size, + const std::vector &v_uuid); std::string m_payload; // The payload of the advertisement. }; // NimBLEAdvertisementData @@ -80,6 +89,10 @@ public: bool start(uint32_t duration = 0, void (*advCompleteCB)(NimBLEAdvertising *pAdv) = nullptr); void stop(); void setAppearance(uint16_t appearance); + void setName(const std::string &name); + void setManufacturerData(const std::string &data); + void setURI(const std::string &uri); + void setServiceData(const NimBLEUUID &uuid, const std::string &data); void setAdvertisementType(uint8_t adv_type); void setMaxInterval(uint16_t maxinterval); void setMinInterval(uint16_t mininterval); @@ -89,6 +102,8 @@ public: void setScanResponse(bool); void setMinPreferred(uint16_t); void setMaxPreferred(uint16_t); + void addTxPower(); + void reset(); void advCompleteCB(); bool isAdvertising(); @@ -109,6 +124,12 @@ private: void (*m_advCompCB)(NimBLEAdvertising *pAdv); uint8_t m_slaveItvl[4]; uint32_t m_duration; + std::vector m_svcData16; + std::vector m_svcData32; + std::vector m_svcData128; + std::vector m_name; + std::vector m_mfgData; + std::vector m_uri; }; #endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) diff --git a/lib/libesp32/NimBLE-Arduino/src/NimBLECharacteristic.cpp b/lib/libesp32/NimBLE-Arduino/src/NimBLECharacteristic.cpp index e9a5a49c9..0ffa9fb03 100644 --- a/lib/libesp32/NimBLE-Arduino/src/NimBLECharacteristic.cpp +++ b/lib/libesp32/NimBLE-Arduino/src/NimBLECharacteristic.cpp @@ -101,9 +101,9 @@ NimBLEDescriptor* NimBLECharacteristic::createDescriptor(const NimBLEUUID &uuid, /** - * @brief Return the BLE Descriptor for the given UUID if associated with this characteristic. - * @param [in] uuid The UUID of the descriptor that we wish to retrieve. - * @return pointer to the NimBLEDescriptor. If no such descriptor is associated with the characteristic, nullptr is returned. + * @brief Return the BLE Descriptor for the given UUID. + * @param [in] uuid The UUID of the descriptor. + * @return A pointer to the descriptor object or nullptr if not found. */ NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const char* uuid) { return getDescriptorByUUID(NimBLEUUID(uuid)); @@ -111,9 +111,9 @@ NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const char* uuid) { /** - * @brief Return the BLE Descriptor for the given UUID if associated with this characteristic. - * @param [in] uuid The UUID of the descriptor that we wish to retrieve. - * @return pointer to the NimBLEDescriptor. If no such descriptor is associated with the characteristic, nullptr is returned. + * @brief Return the BLE Descriptor for the given UUID. + * @param [in] uuid The UUID of the descriptor. + * @return A pointer to the descriptor object or nullptr if not found. */ NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const NimBLEUUID &uuid) { for (auto &it : m_dscVec) { @@ -124,6 +124,20 @@ NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const NimBLEUUID &uu return nullptr; } // getDescriptorByUUID +/** + * @brief Return the BLE Descriptor for the given handle. + * @param [in] handle The handle of the descriptor. + * @return A pointer to the descriptor object or nullptr if not found. + */ +NimBLEDescriptor *NimBLECharacteristic::getDescriptorByHandle(uint16_t handle) { + for (auto &it : m_dscVec) { + if (it->getHandle() == handle) { + return it; + } + } + return nullptr; +} + /** * @brief Get the handle of the characteristic. diff --git a/lib/libesp32/NimBLE-Arduino/src/NimBLECharacteristic.h b/lib/libesp32/NimBLE-Arduino/src/NimBLECharacteristic.h index 1c7418aef..9bb9d079b 100644 --- a/lib/libesp32/NimBLE-Arduino/src/NimBLECharacteristic.h +++ b/lib/libesp32/NimBLE-Arduino/src/NimBLECharacteristic.h @@ -59,6 +59,17 @@ class NimBLECharacteristicCallbacks; */ class NimBLECharacteristic { public: + + uint16_t getHandle(); + NimBLEUUID getUUID(); + std::string toString(); + + void setCallbacks(NimBLECharacteristicCallbacks* pCallbacks); + + void indicate(); + void notify(bool is_notification = true); + size_t getSubscribedCount(); + NimBLEDescriptor* createDescriptor(const char* uuid, uint32_t properties = NIMBLE_PROPERTY::READ | @@ -72,9 +83,10 @@ public: NimBLEDescriptor* getDescriptorByUUID(const char* uuid); NimBLEDescriptor* getDescriptorByUUID(const NimBLEUUID &uuid); - NimBLEUUID getUUID(); - std::string getValue(time_t *timestamp = nullptr); + NimBLEDescriptor* getDescriptorByHandle(uint16_t handle); + std::string getValue(time_t *timestamp = nullptr); + size_t getDataLength(); /** * @brief A template to convert the characteristic data to . * @tparam T The type to convert the data to. @@ -92,25 +104,20 @@ public: return *((T *)pData); } - size_t getDataLength(); - void indicate(); - void notify(bool is_notification = true); - void setCallbacks(NimBLECharacteristicCallbacks* pCallbacks); void setValue(const uint8_t* data, size_t size); void setValue(const std::string &value); - /** * @brief Convenience template to set the characteristic value to val. * @param [in] s The value to set. */ template - void setValue(const T &s) { + void setValue(const T &s) { setValue((uint8_t*)&s, sizeof(T)); } - std::string toString(); - uint16_t getHandle(); - size_t getSubscribedCount(); + + + private: diff --git a/lib/libesp32/NimBLE-Arduino/src/NimBLEDescriptor.cpp b/lib/libesp32/NimBLE-Arduino/src/NimBLEDescriptor.cpp index e8f7f9f8b..95c3291f3 100644 --- a/lib/libesp32/NimBLE-Arduino/src/NimBLEDescriptor.cpp +++ b/lib/libesp32/NimBLE-Arduino/src/NimBLEDescriptor.cpp @@ -122,11 +122,17 @@ uint8_t* NimBLEDescriptor::getValue() { return m_value.attr_value; } // getValue +/** + * @brief Get the value of this descriptor as a string. + * @return A std::string instance containing a copy of the descriptor's value. + */ +std::string NimBLEDescriptor::getStringValue() { + return std::string((char *) m_value.attr_value, m_value.attr_len); +} int NimBLEDescriptor::handleGapEvent(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, - void *arg) -{ + void *arg) { const ble_uuid_t *uuid; int rc; NimBLEDescriptor* pDescriptor = (NimBLEDescriptor*)arg; diff --git a/lib/libesp32/NimBLE-Arduino/src/NimBLEDescriptor.h b/lib/libesp32/NimBLE-Arduino/src/NimBLEDescriptor.h index 16b6edceb..76318b729 100644 --- a/lib/libesp32/NimBLE-Arduino/src/NimBLEDescriptor.h +++ b/lib/libesp32/NimBLE-Arduino/src/NimBLEDescriptor.h @@ -44,20 +44,23 @@ class NimBLEDescriptorCallbacks; class NimBLEDescriptor { public: uint16_t getHandle(); - size_t getLength(); NimBLEUUID getUUID(); - uint8_t* getValue(); - void setCallbacks(NimBLEDescriptorCallbacks* pCallbacks); - void setValue(const uint8_t* data, size_t size); - void setValue(const std::string &value); std::string toString(); + void setCallbacks(NimBLEDescriptorCallbacks* pCallbacks); + + size_t getLength(); + uint8_t* getValue(); + std::string getStringValue(); + + void setValue(const uint8_t* data, size_t size); + void setValue(const std::string &value); /** * @brief Convenience template to set the descriptor value to val. * @param [in] s The value to set. */ template - void setValue(const T &s) { + void setValue(const T &s) { setValue((uint8_t*)&s, sizeof(T)); } diff --git a/lib/libesp32/NimBLE-Arduino/src/NimBLEDevice.cpp b/lib/libesp32/NimBLE-Arduino/src/NimBLEDevice.cpp index f34a522f7..dc9caf3d5 100644 --- a/lib/libesp32/NimBLE-Arduino/src/NimBLEDevice.cpp +++ b/lib/libesp32/NimBLE-Arduino/src/NimBLEDevice.cpp @@ -62,6 +62,8 @@ std::list NimBLEDevice::m_cList; std::list NimBLEDevice::m_ignoreList; NimBLESecurityCallbacks* NimBLEDevice::m_securityCallbacks = nullptr; uint8_t NimBLEDevice::m_own_addr_type = BLE_OWN_ADDR_PUBLIC; +uint16_t NimBLEDevice::m_scanDuplicateSize = CONFIG_BTDM_SCAN_DUPL_CACHE_SIZE; +uint8_t NimBLEDevice::m_scanFilterMode = CONFIG_BTDM_SCAN_DUPL_TYPE; /** @@ -303,7 +305,7 @@ void NimBLEDevice::stopAdvertising() { /** - * @brief Set the transmission power. + * @brief Get the transmission power. * @param [in] powerType The power level to set, can be one of: * * ESP_BLE_PWR_TYPE_CONN_HDL0 = 0, For connection handle 0 * * ESP_BLE_PWR_TYPE_CONN_HDL1 = 1, For connection handle 1 @@ -342,7 +344,7 @@ void NimBLEDevice::stopAdvertising() { default: return BLE_HS_ADV_TX_PWR_LVL_AUTO; } -} // setPower +} // getPower /** @@ -400,6 +402,53 @@ void NimBLEDevice::stopAdvertising() { } +/** + * @brief Set the duplicate filter cache size for filtering scanned devices. + * @param [in] cacheSize The number of advertisements filtered before the cache is reset.\n + * Range is 10-1000, a larger value will reduce how often the same devices are reported. + * @details Must only be called before calling NimBLEDevice::init. + */ +/*STATIC*/ +void NimBLEDevice::setScanDuplicateCacheSize(uint16_t cacheSize) { + if(initialized) { + NIMBLE_LOGE(LOG_TAG, "Cannot change scan cache size while initialized"); + return; + } else if(cacheSize > 1000 || cacheSize <10) { + NIMBLE_LOGE(LOG_TAG, "Invalid scan cache size; min=10 max=1000"); + return; + } + + m_scanDuplicateSize = cacheSize; +} + + +/** + * @brief Set the duplicate filter mode for filtering scanned devices. + * @param [in] mode One of three possible options: + * * CONFIG_BTDM_SCAN_DUPL_TYPE_DEVICE (0) (default)\n + Filter by device address only, advertisements from the same address will be reported only once. + * * CONFIG_BTDM_SCAN_DUPL_TYPE_DATA (1)\n + Filter by data only, advertisements with the same data will only be reported once,\n + even from different addresses. + * * CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE (2)\n + Filter by address and data, advertisements from the same address will be reported only once,\n + except if the data in the advertisement has changed, then it will be reported again. + * @details Must only be called before calling NimBLEDevice::init. + */ +/*STATIC*/ +void NimBLEDevice::setScanFilterMode(uint8_t mode) { + if(initialized) { + NIMBLE_LOGE(LOG_TAG, "Cannot change scan duplicate type while initialized"); + return; + } else if(mode > 2) { + NIMBLE_LOGE(LOG_TAG, "Invalid scan duplicate type"); + return; + } + + m_scanFilterMode = mode; +} + + /** * @brief Host reset, we pass the message so we don't make calls until resynced. * @param [in] reason The reason code for the reset. @@ -499,8 +548,17 @@ void NimBLEDevice::stopAdvertising() { ESP_ERROR_CHECK(errRc); - ESP_ERROR_CHECK(esp_nimble_hci_and_controller_init()); + esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT); + esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); + bt_cfg.mode = ESP_BT_MODE_BLE; + bt_cfg.ble_max_conn = CONFIG_BT_NIMBLE_MAX_CONNECTIONS; + bt_cfg.normal_adv_size = m_scanDuplicateSize; + bt_cfg.scan_duplicate_type = m_scanFilterMode; + + ESP_ERROR_CHECK(esp_bt_controller_init(&bt_cfg)); + ESP_ERROR_CHECK(esp_bt_controller_enable(ESP_BT_MODE_BLE)); + ESP_ERROR_CHECK(esp_nimble_hci_init()); nimble_port_init(); // Setup callbacks for host events diff --git a/lib/libesp32/NimBLE-Arduino/src/NimBLEDevice.h b/lib/libesp32/NimBLE-Arduino/src/NimBLEDevice.h index 2d586bb42..27549ed60 100644 --- a/lib/libesp32/NimBLE-Arduino/src/NimBLEDevice.h +++ b/lib/libesp32/NimBLE-Arduino/src/NimBLEDevice.h @@ -123,6 +123,8 @@ public: static bool isIgnored(const NimBLEAddress &address); static void addIgnored(const NimBLEAddress &address); static void removeIgnored(const NimBLEAddress &address); + static void setScanDuplicateCacheSize(uint16_t cacheSize); + static void setScanFilterMode(uint8_t type); #if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER) static NimBLEAdvertising* getAdvertising(); @@ -184,6 +186,8 @@ private: static ble_gap_event_listener m_listener; static gap_event_handler m_customGapHandler; static uint8_t m_own_addr_type; + static uint16_t m_scanDuplicateSize; + static uint8_t m_scanFilterMode; }; diff --git a/lib/libesp32/NimBLE-Arduino/src/NimBLEHIDDevice.cpp b/lib/libesp32/NimBLE-Arduino/src/NimBLEHIDDevice.cpp index a06b75360..37d0f52f5 100644 --- a/lib/libesp32/NimBLE-Arduino/src/NimBLEHIDDevice.cpp +++ b/lib/libesp32/NimBLE-Arduino/src/NimBLEHIDDevice.cpp @@ -103,7 +103,7 @@ void NimBLEHIDDevice::manufacturer(std::string name) { /** * @brief Sets the Plug n Play characterisc value. * @param [in] sig The vendor ID source number. - * @param [in[ vid The vendor ID number. + * @param [in] vid The vendor ID number. * @param [in] pid The product ID number. * @param [in] version The produce version number. */ @@ -128,8 +128,8 @@ void NimBLEHIDDevice::hidInfo(uint8_t country, uint8_t flags) { * @return pointer to new input report characteristic */ NimBLECharacteristic* NimBLEHIDDevice::inputReport(uint8_t reportID) { - NimBLECharacteristic* inputReportCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4d, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::NOTIFY); - NimBLEDescriptor* inputReportDescriptor = inputReportCharacteristic->createDescriptor((uint16_t) 0x2908); + NimBLECharacteristic* inputReportCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4d, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ_ENC); + NimBLEDescriptor* inputReportDescriptor = inputReportCharacteristic->createDescriptor((uint16_t) 0x2908, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::READ_ENC); uint8_t desc1_val[] = { reportID, 0x01 }; inputReportDescriptor->setValue((uint8_t*) desc1_val, 2); @@ -144,7 +144,7 @@ NimBLECharacteristic* NimBLEHIDDevice::inputReport(uint8_t reportID) { */ NimBLECharacteristic* NimBLEHIDDevice::outputReport(uint8_t reportID) { NimBLECharacteristic* outputReportCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4d, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::WRITE_NR | NIMBLE_PROPERTY::READ_ENC | NIMBLE_PROPERTY::WRITE_ENC); - NimBLEDescriptor* outputReportDescriptor = outputReportCharacteristic->createDescriptor((uint16_t) 0x2908); + NimBLEDescriptor* outputReportDescriptor = outputReportCharacteristic->createDescriptor((uint16_t) 0x2908, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::READ_ENC | NIMBLE_PROPERTY::WRITE_ENC); uint8_t desc1_val[] = { reportID, 0x02 }; outputReportDescriptor->setValue((uint8_t*) desc1_val, 2); @@ -159,7 +159,7 @@ NimBLECharacteristic* NimBLEHIDDevice::outputReport(uint8_t reportID) { */ NimBLECharacteristic* NimBLEHIDDevice::featureReport(uint8_t reportID) { NimBLECharacteristic* featureReportCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4d, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::READ_ENC | NIMBLE_PROPERTY::WRITE_ENC); - NimBLEDescriptor* featureReportDescriptor = featureReportCharacteristic->createDescriptor((uint16_t) 0x2908); + NimBLEDescriptor* featureReportDescriptor = featureReportCharacteristic->createDescriptor((uint16_t) 0x2908, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::READ_ENC | NIMBLE_PROPERTY::WRITE_ENC); uint8_t desc1_val[] = { reportID, 0x03 }; featureReportDescriptor->setValue((uint8_t*) desc1_val, 2); diff --git a/lib/libesp32/NimBLE-Arduino/src/NimBLEScan.cpp b/lib/libesp32/NimBLE-Arduino/src/NimBLEScan.cpp index 122ff3332..00aeab03c 100644 --- a/lib/libesp32/NimBLE-Arduino/src/NimBLEScan.cpp +++ b/lib/libesp32/NimBLE-Arduino/src/NimBLEScan.cpp @@ -38,9 +38,9 @@ NimBLEScan::NimBLEScan() { m_scan_params.filter_duplicates = 0; // If set, the controller ignores all but the first advertisement from each device. m_pAdvertisedDeviceCallbacks = nullptr; m_ignoreResults = false; - m_wantDuplicates = false; m_pTaskData = nullptr; m_duration = BLE_HS_FOREVER; // make sure this is non-zero in the event of a host reset + m_maxResults = 0xFF; } @@ -64,7 +64,7 @@ NimBLEScan::~NimBLEScan() { case BLE_GAP_EVENT_DISC: { if(pScan->m_ignoreResults) { - NIMBLE_LOGE(LOG_TAG, "Scan op in progress - ignoring results"); + NIMBLE_LOGI(LOG_TAG, "Scan op in progress - ignoring results"); return 0; } @@ -88,34 +88,49 @@ NimBLEScan::~NimBLEScan() { // If we haven't seen this device before; create a new instance and insert it in the vector. // Otherwise just update the relevant parameters of the already known device. - if(advertisedDevice == nullptr){ + if(advertisedDevice == nullptr && event->disc.event_type != BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP){ + // Check if we have reach the scan results limit, ignore this one if so. + // We still need to store each device when maxResults is 0 to be able to append the scan results + if(pScan->m_maxResults > 0 && pScan->m_maxResults < 0xFF && + (pScan->m_scanResults.m_advertisedDevicesVector.size() >= pScan->m_maxResults)) + { + return 0; + } advertisedDevice = new NimBLEAdvertisedDevice(); advertisedDevice->setAddress(advertisedAddress); advertisedDevice->setAdvType(event->disc.event_type); pScan->m_scanResults.m_advertisedDevicesVector.push_back(advertisedDevice); - NIMBLE_LOGI(LOG_TAG, "NEW DEVICE FOUND: %s", advertisedAddress.toString().c_str()); - } - else{ - NIMBLE_LOGI(LOG_TAG, "UPDATING PREVIOUSLY FOUND DEVICE: %s", advertisedAddress.toString().c_str()); - } - advertisedDevice->setRSSI(event->disc.rssi); - if(event->disc.length_data > 0) { - advertisedDevice->parseAdvertisement(event->disc.data, event->disc.length_data); + NIMBLE_LOGI(LOG_TAG, "New advertiser: %s", advertisedAddress.toString().c_str()); + } else if(advertisedDevice != nullptr) { + NIMBLE_LOGI(LOG_TAG, "Updated advertiser: %s", advertisedAddress.toString().c_str()); + } else { + // Scan response from unknown device + return 0; } + advertisedDevice->m_timestamp = time(nullptr); + advertisedDevice->setRSSI(event->disc.rssi); + advertisedDevice->setPayload(event->disc.data, event->disc.length_data, + event->disc.event_type == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP); if (pScan->m_pAdvertisedDeviceCallbacks) { - if(pScan->m_wantDuplicates || !advertisedDevice->m_callbackSent) { - // If not active scanning report the result to the listener. - if(pScan->m_scan_params.passive || event->disc.event_type == BLE_HCI_ADV_TYPE_ADV_NONCONN_IND) { - advertisedDevice->m_callbackSent = true; - pScan->m_pAdvertisedDeviceCallbacks->onResult(advertisedDevice); + // If not active scanning or scan response is not available + // report the result to the callback now. + if(pScan->m_scan_params.passive || + (advertisedDevice->getAdvType() != BLE_HCI_ADV_TYPE_ADV_IND && + advertisedDevice->getAdvType() != BLE_HCI_ADV_TYPE_ADV_SCAN_IND)) + { + advertisedDevice->m_callbackSent = true; + pScan->m_pAdvertisedDeviceCallbacks->onResult(advertisedDevice); - // Otherwise wait for the scan response so we can report all of the data at once. - } else if (event->disc.event_type == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP) { - advertisedDevice->m_callbackSent = true; - pScan->m_pAdvertisedDeviceCallbacks->onResult(advertisedDevice); - } + // Otherwise, wait for the scan response so we can report the complete data. + } else if (event->disc.event_type == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP) { + advertisedDevice->m_callbackSent = true; + pScan->m_pAdvertisedDeviceCallbacks->onResult(advertisedDevice); + } + // If not storing results and we have invoked the callback, delete the device. + if(pScan->m_maxResults == 0 && advertisedDevice->m_callbackSent) { + pScan->erase(advertisedAddress); } } @@ -123,7 +138,21 @@ NimBLEScan::~NimBLEScan() { } case BLE_GAP_EVENT_DISC_COMPLETE: { NIMBLE_LOGD(LOG_TAG, "discovery complete; reason=%d", - event->disc_complete.reason); + event->disc_complete.reason); + + // If a device advertised with scan reponse available and it was not received + // the callback would not have been invoked, so do it here. + if(pScan->m_pAdvertisedDeviceCallbacks) { + for(auto &it : pScan->m_scanResults.m_advertisedDevicesVector) { + if(!it->m_callbackSent) { + pScan->m_pAdvertisedDeviceCallbacks->onResult(it); + } + } + } + + if(pScan->m_maxResults == 0) { + pScan->clearResults(); + } if (pScan->m_scanCompleteCB != nullptr) { pScan->m_scanCompleteCB(pScan->m_scanResults); @@ -145,15 +174,11 @@ NimBLEScan::~NimBLEScan() { /** * @brief Should we perform an active or passive scan? - * The default is a passive scan. An active scan means that we will wish a scan response. + * The default is a passive scan. An active scan means that we will request a scan response. * @param [in] active If true, we perform an active scan otherwise a passive scan. */ void NimBLEScan::setActiveScan(bool active) { - if (active) { - m_scan_params.passive = 0; - } else { - m_scan_params.passive = 1; - } + m_scan_params.passive = !active; } // setActiveScan @@ -202,6 +227,16 @@ void NimBLEScan::setFilterPolicy(uint8_t filter) { } // setFilterPolicy +/** + * @brief Sets the max number of results to store. + * @param [in] maxResults The number of results to limit storage to\n + * 0 == none (callbacks only) 0xFF == unlimited, any other value is the limit. + */ +void NimBLEScan::setMaxResults(uint8_t maxResults) { + m_maxResults = maxResults; +} + + /** * @brief Set the call backs to be invoked. * @param [in] pAdvertisedDeviceCallbacks Call backs to be invoked. @@ -209,7 +244,7 @@ void NimBLEScan::setFilterPolicy(uint8_t filter) { */ void NimBLEScan::setAdvertisedDeviceCallbacks(NimBLEAdvertisedDeviceCallbacks* pAdvertisedDeviceCallbacks, bool wantDuplicates) { - m_wantDuplicates = wantDuplicates; + setDuplicateFilter(!wantDuplicates); m_pAdvertisedDeviceCallbacks = pAdvertisedDeviceCallbacks; } // setAdvertisedDeviceCallbacks @@ -342,10 +377,14 @@ bool NimBLEScan::stop() { int rc = ble_gap_disc_cancel(); if (rc != 0 && rc != BLE_HS_EALREADY) { - NIMBLE_LOGE(LOG_TAG, "Failed to cancel scan; rc=%d\n", rc); + NIMBLE_LOGE(LOG_TAG, "Failed to cancel scan; rc=%d", rc); return false; } + if(m_maxResults == 0) { + clearResults(); + } + if (rc != BLE_HS_EALREADY && m_scanCompleteCB != nullptr) { m_scanCompleteCB(m_scanResults); } @@ -365,7 +404,7 @@ bool NimBLEScan::stop() { * @details After disconnecting, it may be required in the case we were connected to a device without a public address. */ void NimBLEScan::erase(const NimBLEAddress &address) { - NIMBLE_LOGI(LOG_TAG, "erase device: %s", address.toString().c_str()); + NIMBLE_LOGD(LOG_TAG, "erase device: %s", address.toString().c_str()); for(auto it = m_scanResults.m_advertisedDevicesVector.begin(); it != m_scanResults.m_advertisedDevicesVector.end(); ++it) { if((*it)->getAddress() == address) { diff --git a/lib/libesp32/NimBLE-Arduino/src/NimBLEScan.h b/lib/libesp32/NimBLE-Arduino/src/NimBLEScan.h index 9007a7dd8..57e743009 100644 --- a/lib/libesp32/NimBLE-Arduino/src/NimBLEScan.h +++ b/lib/libesp32/NimBLE-Arduino/src/NimBLEScan.h @@ -73,6 +73,7 @@ public: bool stop(); void clearResults(); NimBLEScanResults getResults(); + void setMaxResults(uint8_t maxResults); void erase(const NimBLEAddress &address); @@ -89,10 +90,10 @@ private: void (*m_scanCompleteCB)(NimBLEScanResults scanResults); ble_gap_disc_params m_scan_params; bool m_ignoreResults; - bool m_wantDuplicates; NimBLEScanResults m_scanResults; uint32_t m_duration; ble_task_data_t *m_pTaskData; + uint8_t m_maxResults; }; #endif // #if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER) diff --git a/lib/libesp32/NimBLE-Arduino/src/NimBLEServer.cpp b/lib/libesp32/NimBLE-Arduino/src/NimBLEServer.cpp index fd5d8266b..423e87967 100644 --- a/lib/libesp32/NimBLE-Arduino/src/NimBLEServer.cpp +++ b/lib/libesp32/NimBLE-Arduino/src/NimBLEServer.cpp @@ -104,28 +104,47 @@ NimBLEService* NimBLEServer::createService(const NimBLEUUID &uuid, uint32_t numH /** * @brief Get a %BLE Service by its UUID - * @param [in] uuid The UUID of the new service. - * @return A reference to the service object. + * @param [in] uuid The UUID of the service. + * @param instanceId The index of the service to return (used when multiple services have the same UUID). + * @return A pointer to the service object or nullptr if not found. */ -NimBLEService* NimBLEServer::getServiceByUUID(const char* uuid) { - return getServiceByUUID(NimBLEUUID(uuid)); +NimBLEService* NimBLEServer::getServiceByUUID(const char* uuid, uint16_t instanceId) { + return getServiceByUUID(NimBLEUUID(uuid), instanceId); } // getServiceByUUID /** * @brief Get a %BLE Service by its UUID - * @param [in] uuid The UUID of the new service. - * @return A reference to the service object. + * @param [in] uuid The UUID of the service. + * @param instanceId The index of the service to return (used when multiple services have the same UUID). + * @return A pointer to the service object or nullptr if not found. */ -NimBLEService* NimBLEServer::getServiceByUUID(const NimBLEUUID &uuid) { +NimBLEService* NimBLEServer::getServiceByUUID(const NimBLEUUID &uuid, uint16_t instanceId) { + uint16_t position = 0; for (auto &it : m_svcVec) { if (it->getUUID() == uuid) { - return it; + if (position == instanceId){ + return it; + } + position++; } } return nullptr; } // getServiceByUUID +/** + * @brief Get a %BLE Service by its handle + * @param handle The handle of the service. + * @return A pointer to the service object or nullptr if not found. + */ +NimBLEService *NimBLEServer::getServiceByHandle(uint16_t handle) { + for (auto &it : m_svcVec) { + if (it->getHandle() == handle) { + return it; + } + } + return nullptr; +} /** * @brief Retrieve the advertising object that can be used to advertise the existence of the server. @@ -646,7 +665,7 @@ void NimBLEServer::updateConnParams(uint16_t conn_handle, if(rc != 0) { NIMBLE_LOGE(LOG_TAG, "Update params error: %d, %s", rc, NimBLEUtils::returnCodeToString(rc)); } -} // updateConnParams +}// updateConnParams /** Default callback handlers */ diff --git a/lib/libesp32/NimBLE-Arduino/src/NimBLEServer.h b/lib/libesp32/NimBLE-Arduino/src/NimBLEServer.h index bedf9cf58..aaaf287d2 100644 --- a/lib/libesp32/NimBLE-Arduino/src/NimBLEServer.h +++ b/lib/libesp32/NimBLE-Arduino/src/NimBLEServer.h @@ -49,8 +49,9 @@ public: void startAdvertising(); void stopAdvertising(); void start(); - NimBLEService* getServiceByUUID(const char* uuid); - NimBLEService* getServiceByUUID(const NimBLEUUID &uuid); + NimBLEService* getServiceByUUID(const char* uuid, uint16_t instanceId = 0); + NimBLEService* getServiceByUUID(const NimBLEUUID &uuid, uint16_t instanceId = 0); + NimBLEService* getServiceByHandle(uint16_t handle); int disconnect(uint16_t connID, uint8_t reason = BLE_ERR_REM_USER_CONN_TERM); void updateConnParams(uint16_t conn_handle, diff --git a/lib/libesp32/NimBLE-Arduino/src/NimBLEService.cpp b/lib/libesp32/NimBLE-Arduino/src/NimBLEService.cpp index 3420da2c7..a830eec95 100644 --- a/lib/libesp32/NimBLE-Arduino/src/NimBLEService.cpp +++ b/lib/libesp32/NimBLE-Arduino/src/NimBLEService.cpp @@ -233,9 +233,9 @@ NimBLECharacteristic* NimBLEService::createCharacteristic(const char* uuid, uint */ NimBLECharacteristic* NimBLEService::createCharacteristic(const NimBLEUUID &uuid, uint32_t properties) { NimBLECharacteristic* pCharacteristic = new NimBLECharacteristic(uuid, properties, this); - // Check that we don't add the same characteristic twice. + if (getCharacteristic(uuid) != nullptr) { - NIMBLE_LOGW(LOG_TAG, "<< Adding a duplicate characteristic with UUID: %s", + NIMBLE_LOGD(LOG_TAG, "<< Adding a duplicate characteristic with UUID: %s", std::string(uuid).c_str()); } @@ -249,28 +249,72 @@ NimBLECharacteristic* NimBLEService::createCharacteristic(const NimBLEUUID &uuid /** * @brief Get a pointer to the characteristic object with the specified UUID. * @param [in] uuid The UUID of the characteristic. + * @param instanceId The index of the characteristic to return (used when multiple characteristics have the same UUID). * @return A pointer to the characteristic object or nullptr if not found. */ -NimBLECharacteristic* NimBLEService::getCharacteristic(const char* uuid) { - return getCharacteristic(NimBLEUUID(uuid)); +NimBLECharacteristic* NimBLEService::getCharacteristic(const char* uuid, uint16_t instanceId) { + return getCharacteristic(NimBLEUUID(uuid), instanceId); } - /** * @brief Get a pointer to the characteristic object with the specified UUID. * @param [in] uuid The UUID of the characteristic. + * @param instanceId The index of the characteristic to return (used when multiple characteristics have the same UUID). * @return A pointer to the characteristic object or nullptr if not found. */ -NimBLECharacteristic* NimBLEService::getCharacteristic(const NimBLEUUID &uuid) { +NimBLECharacteristic* NimBLEService::getCharacteristic(const NimBLEUUID &uuid, uint16_t instanceId) { + uint16_t position = 0; for (auto &it : m_chrVec) { if (it->getUUID() == uuid) { - return it; + if (position == instanceId) { + return it; + } + position++; } } - return nullptr; } +/** + * @brief Get a pointer to the characteristic object with the specified handle. + * @param handle The handle of the characteristic. + * @return A pointer to the characteristic object or nullptr if not found. + */ +NimBLECharacteristic *NimBLEService::getCharacteristicByHandle(uint16_t handle) { + for (auto &it : m_chrVec) { + if (it->getHandle() == handle) { + return it; + } + } + return nullptr; +} + +/** + * @return A vector containing pointers to each characteristic associated with this service. + */ +std::vector NimBLEService::getCharacteristics() { + return m_chrVec; +} + +/** + * @return A vector containing pointers to each characteristic with the provided UUID associated with this service. + */ +std::vector NimBLEService::getCharacteristics(const char *uuid) { + return getCharacteristics(NimBLEUUID(uuid)); +} + +/** + * @return A vector containing pointers to each characteristic with the provided UUID associated with this service. + */ +std::vector NimBLEService::getCharacteristics(const NimBLEUUID &uuid) { + std::vector result; + for (auto &it : m_chrVec) { + if (it->getUUID() == uuid) { + result.push_back(it); + } + } + return result; +} /** * @brief Return a string representation of this service. @@ -295,7 +339,7 @@ std::string NimBLEService::toString() { */ NimBLEServer* NimBLEService::getServer() { return m_pServer; -} // getServer +}// getServer #endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) #endif // CONFIG_BT_ENABLED diff --git a/lib/libesp32/NimBLE-Arduino/src/NimBLEService.h b/lib/libesp32/NimBLE-Arduino/src/NimBLEService.h index 191d97fa5..1203d3e3b 100644 --- a/lib/libesp32/NimBLE-Arduino/src/NimBLEService.h +++ b/lib/libesp32/NimBLE-Arduino/src/NimBLEService.h @@ -35,6 +35,16 @@ class NimBLECharacteristic; */ class NimBLEService { public: + + NimBLEServer* getServer(); + + NimBLEUUID getUUID(); + uint16_t getHandle(); + std::string toString(); + void dump(); + + bool start(); + NimBLECharacteristic* createCharacteristic(const char* uuid, uint32_t properties = NIMBLE_PROPERTY::READ | @@ -45,14 +55,14 @@ public: NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE); - void dump(); - NimBLECharacteristic* getCharacteristic(const char* uuid); - NimBLECharacteristic* getCharacteristic(const NimBLEUUID &uuid); - NimBLEUUID getUUID(); - NimBLEServer* getServer(); - bool start(); - std::string toString(); - uint16_t getHandle(); + NimBLECharacteristic* getCharacteristic(const char* uuid, uint16_t instanceId = 0); + NimBLECharacteristic* getCharacteristic(const NimBLEUUID &uuid, uint16_t instanceId = 0); + NimBLECharacteristic* getCharacteristicByHandle(uint16_t handle); + + std::vector getCharacteristics(); + std::vector getCharacteristics(const char* uuid); + std::vector getCharacteristics(const NimBLEUUID &uuid); + private: NimBLEService(const char* uuid, uint16_t numHandles, NimBLEServer* pServer); diff --git a/lib/libesp32/NimBLE-Arduino/src/NimBLEUUID.cpp b/lib/libesp32/NimBLE-Arduino/src/NimBLEUUID.cpp index 21ff27047..ea58ae7b2 100644 --- a/lib/libesp32/NimBLE-Arduino/src/NimBLEUUID.cpp +++ b/lib/libesp32/NimBLE-Arduino/src/NimBLEUUID.cpp @@ -65,29 +65,42 @@ static const char* LOG_TAG = "NimBLEUUID"; *this = NimBLEUUID(first, second, third, (uint64_t(fourth) << 48) + fifth); } else { - NIMBLE_LOGE(LOG_TAG,"ERROR: UUID value not 2, 4, 16 or 36 bytes"); m_valueSet = false; } } // NimBLEUUID(std::string) /** - * @brief Create a UUID from 16 bytes of memory. + * @brief Create a UUID from 2, 4, 16 bytes of memory. * @param [in] pData The pointer to the start of the UUID. * @param [in] size The size of the data. * @param [in] msbFirst Is the MSB first in pData memory? */ NimBLEUUID::NimBLEUUID(const uint8_t* pData, size_t size, bool msbFirst) { - if (size != 16) { - NIMBLE_LOGE(LOG_TAG,"ERROR: UUID length not 16 bytes"); - return; - } - m_uuid.u.type = BLE_UUID_TYPE_128; + uint8_t *uuidValue = nullptr; + switch(size) { + case 2: + uuidValue = (uint8_t*)&m_uuid.u16.value; + m_uuid.u.type = BLE_UUID_TYPE_16; + break; + case 4: + uuidValue = (uint8_t*)&m_uuid.u32.value; + m_uuid.u.type = BLE_UUID_TYPE_32; + break; + case 16: + uuidValue = m_uuid.u128.value; + m_uuid.u.type = BLE_UUID_TYPE_128; + break; + default: + m_valueSet = false; + NIMBLE_LOGE(LOG_TAG, "Invalid UUID size"); + return; + } if (msbFirst) { - std::reverse_copy(pData, pData + 16, m_uuid.u128.value); + std::reverse_copy(pData, pData + size, uuidValue); } else { - memcpy(m_uuid.u128.value, pData, 16); + memcpy(uuidValue, pData, size); } m_valueSet = true; } // NimBLEUUID diff --git a/lib/libesp32/NimBLE-Arduino/src/esp-hci/src/esp_nimble_hci.c b/lib/libesp32/NimBLE-Arduino/src/esp-hci/src/esp_nimble_hci.c index 98c133fa5..9af13c355 100644 --- a/lib/libesp32/NimBLE-Arduino/src/esp-hci/src/esp_nimble_hci.c +++ b/lib/libesp32/NimBLE-Arduino/src/esp-hci/src/esp_nimble_hci.c @@ -523,10 +523,6 @@ esp_err_t esp_nimble_hci_and_controller_init(void) esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT); esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); - /* Added to ensure BLE only mode */ - bt_cfg.mode = ESP_BT_MODE_BLE; - /* Added to set max connections from nimconfig */ - bt_cfg.ble_max_conn = CONFIG_BT_NIMBLE_MAX_CONNECTIONS; if ((ret = esp_bt_controller_init(&bt_cfg)) != ESP_OK) { return ret; diff --git a/lib/libesp32/NimBLE-Arduino/src/nimconfig.h b/lib/libesp32/NimBLE-Arduino/src/nimconfig.h index d90921fa1..5ad95ddb9 100644 --- a/lib/libesp32/NimBLE-Arduino/src/nimconfig.h +++ b/lib/libesp32/NimBLE-Arduino/src/nimconfig.h @@ -1,145 +1,156 @@ -/** @file - * - * IGNORE THIS FILE IF USING ESP-IDF, USE MENUCONFIG TO SET NIMBLE OPTIONS. - * - * The config options here are for Arduino use only. - */ - -#pragma once + #pragma once #include "sdkconfig.h" - -/* - * For ESP-IDF compatibility - * Some versions of ESP-IDF used the config name format "CONFIG_NIMBLE_". - * This converts them to "CONFIG_BT_NIMBLE_" format used in the latest IDF. - */ - -/* Detect if using ESP-IDF or Arduino (Arduino won't have these defines in sdkconfig) - * - * Note: We do not use #ifdef CONFIG_BT_NIMBLE_ENABLED since we cannot enable NimBLE when using - * Arduino as a component and the esp-nimble-compnent, so we check if other config options are defined. - * We also need to use a config parameter that must be present and not likely defined in the command line. - */ -#if defined(CONFIG_BT_NIMBLE_GAP_DEVICE_NAME_MAX_LEN) || defined(CONFIG_NIMBLE_GAP_DEVICE_NAME_MAX_LEN) - -#if defined(CONFIG_NIMBLE_ENABLED) && !defined(CONFIG_BT_NIMBLE_ENABLED) -#define CONFIG_BT_NIMBLE_ENABLED -#endif - -#if defined(CONFIG_NIMBLE_ROLE_OBSERVER) && !defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER) -#define CONFIG_BT_NIMBLE_ROLE_OBSERVER -#endif - -#if defined(CONFIG_NIMBLE_ROLE_BROADCASTER) && !defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER) -#define CONFIG_BT_NIMBLE_ROLE_BROADCASTER -#endif - -#if defined(CONFIG_NIMBLE_ROLE_CENTRAL) && !defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL) -#define CONFIG_BT_NIMBLE_ROLE_CENTRAL -#endif - -#if defined(CONFIG_NIMBLE_ROLE_PERIPHERAL) && !defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) -#define CONFIG_BT_NIMBLE_ROLE_PERIPHERAL -#endif - -#if defined(CONFIG_NIMBLE_DEBUG) && !defined(CONFIG_BT_NIMBLE_DEBUG) -#define CONFIG_BT_NIMBLE_DEBUG -#endif - -#else // Using Arduino +#include "nimconfig_rename.h" /*********************************************** - * Arduino config options start here + * Arduino user-config options start here **********************************************/ -/** @brief Comment out if not using NimBLE Client functions \n - * Reduces flash size by approx. 7kB. - */ -#ifndef CONFIG_BT_NIMBLE_ROLE_CENTRAL_DISABLED -#define CONFIG_BT_NIMBLE_ROLE_CENTRAL -#endif +/** @brief Un-comment to change the number of simultaneous connections (esp controller max is 9) */ +// #define CONFIG_BT_NIMBLE_MAX_CONNECTIONS 3 -/** @brief Comment out if not using NimBLE Scan functions \n - * Reduces flash size by approx. 26kB. - */ -#ifndef CONFIG_BT_NIMBLE_ROLE_OBSERVER_DISABLED -#define CONFIG_BT_NIMBLE_ROLE_OBSERVER -#endif +/** @brief Un-comment to change the default MTU size */ +// #define CONFIG_BT_NIMBLE_ATT_PREFERRED_MTU 255 -/** @brief Comment out if not using NimBLE Server functions \n - * Reduces flash size by approx. 16kB. - */ -#ifndef CONFIG_BT_NIMBLE_ROLE_PERIPHERAL_DISABLED -#define CONFIG_BT_NIMBLE_ROLE_PERIPHERAL -#endif +/** @brief Un-comment to change default device name */ +// #define CONFIG_BT_NIMBLE_SVC_GAP_DEVICE_NAME "nimble" -/** @brief Comment out if not using NimBLE Advertising functions \n - * Reduces flash size by approx. 5kB. - */ -#ifndef CONFIG_BT_NIMBLE_ROLE_BROADCASTER_DISABLED -#define CONFIG_BT_NIMBLE_ROLE_BROADCASTER -#endif - -/* Uncomment to see debug log messages from the NimBLE host +/** @brief Un-comment to see debug log messages from the NimBLE host * Uses approx. 32kB of flash memory. */ // #define CONFIG_BT_NIMBLE_DEBUG -/* Uncomment to see NimBLE host return codes as text debug log messages. +/** @brief Un-comment to see NimBLE host return codes as text debug log messages. * Uses approx. 7kB of flash memory. */ // #define CONFIG_NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT -/* Uncomment to see GAP event codes as text in debug log messages. +/** @brief Un-comment to see GAP event codes as text in debug log messages. * Uses approx. 1kB of flash memory. */ // #define CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT -/* Uncomment to see advertisment types as text while scanning in debug log messages. +/** @brief Un-comment to see advertisment types as text while scanning in debug log messages. * Uses approx. 250 bytes of flash memory. */ // #define CONFIG_NIMBLE_CPP_ENABLE_ADVERTISMENT_TYPE_TEXT -/** @brief Sets the core NimBLE host runs on */ +/** @brief Un-comment to change the default GAP appearance */ +// #define CONFIG_BT_NIMBLE_SVC_GAP_APPEARANCE 0x0 + + /** @brief Un-comment if not using NimBLE Client functions \n + * Reduces flash size by approx. 7kB. + */ +// #define CONFIG_BT_NIMBLE_ROLE_CENTRAL_DISABLED + +/** @brief Un-comment if not using NimBLE Scan functions \n + * Reduces flash size by approx. 26kB. + */ +// #define CONFIG_BT_NIMBLE_ROLE_OBSERVER_DISABLED + +/** @brief Un-comment if not using NimBLE Server functions \n + * Reduces flash size by approx. 16kB. + */ +// #define CONFIG_BT_NIMBLE_ROLE_PERIPHERAL_DISABLED + +/** @brief Un-comment if not using NimBLE Advertising functions \n + * Reduces flash size by approx. 5kB. + */ +// #define CONFIG_BT_NIMBLE_ROLE_BROADCASTER_DISABLED + +/** @brief Un-comment to change the number of devices allowed to store/bond with */ +// #define CONFIG_BT_NIMBLE_MAX_BONDS 3 + +/** @brief Un-comment to change the maximum number of CCCD subscriptions to store */ +// #define CONFIG_BT_NIMBLE_MAX_CCCDS 8 + +/** @brief Un-comment to change the random address refresh time (in seconds) */ +// #define CONFIG_BT_NIMBLE_RPA_TIMEOUT 900 + +/** + * @brief Un-comment to change the number of MSYS buffers available. + * @details MSYS is a system level mbuf registry. For prepare write & prepare \n + * responses MBUFs are allocated out of msys_1 pool. This may need to be increased if\n + * you are sending large blocks of data with a low MTU. E.g: 512 bytes with 23 MTU will fail. + */ +// #define CONFIG_BT_NIMBLE_MSYS1_BLOCK_COUNT 12 + +/** @brief Un-comment to use external PSRAM for the NimBLE host */ +// #define CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL 1 + +/** @brief Un-comment to change the core NimBLE host runs on */ +// #define CONFIG_BT_NIMBLE_PINNED_TO_CORE 0 + +/** @brief Un-comment to change the stack size for the NimBLE host task */ +// #define CONFIG_BT_NIMBLE_TASK_STACK_SIZE 4096 + +/********************************** + End Arduino user-config +**********************************/ + +/* This section should not be altered */ +#ifndef CONFIG_BT_NIMBLE_ROLE_CENTRAL_DISABLED +#define CONFIG_BT_NIMBLE_ROLE_CENTRAL +#endif + +#ifndef CONFIG_BT_NIMBLE_ROLE_OBSERVER_DISABLED +#define CONFIG_BT_NIMBLE_ROLE_OBSERVER +#endif + +#ifndef CONFIG_BT_NIMBLE_ROLE_PERIPHERAL_DISABLED +#define CONFIG_BT_NIMBLE_ROLE_PERIPHERAL +#endif + +#ifndef CONFIG_BT_NIMBLE_ROLE_BROADCASTER_DISABLED +#define CONFIG_BT_NIMBLE_ROLE_BROADCASTER +#endif + #ifndef CONFIG_BT_NIMBLE_PINNED_TO_CORE #define CONFIG_BT_NIMBLE_PINNED_TO_CORE 0 #endif -/** @brief Sets the stack size for the NimBLE host task */ #ifndef CONFIG_BT_NIMBLE_TASK_STACK_SIZE #define CONFIG_BT_NIMBLE_TASK_STACK_SIZE 4096 #endif -/** - * @brief Sets the memory pool where NimBLE will be loaded - * @details By default NimBLE is loaded in internal ram.\n - * To use external PSRAM you must change this to `#define CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL 1` - */ #ifndef CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL #define CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_INTERNAL 1 #endif -/** @brief Sets the number of simultaneous connections (esp controller max is 9) */ #ifndef CONFIG_BT_NIMBLE_MAX_CONNECTIONS #define CONFIG_BT_NIMBLE_MAX_CONNECTIONS 3 #endif -/** @brief Sets the number of devices allowed to store/bond with */ #ifndef CONFIG_BT_NIMBLE_MAX_BONDS #define CONFIG_BT_NIMBLE_MAX_BONDS 3 #endif -/** @brief Sets the maximum number of CCCD subscriptions to store */ #ifndef CONFIG_BT_NIMBLE_MAX_CCCDS #define CONFIG_BT_NIMBLE_MAX_CCCDS 8 #endif -/** @brief Default device name */ #ifndef CONFIG_BT_NIMBLE_SVC_GAP_DEVICE_NAME #define CONFIG_BT_NIMBLE_SVC_GAP_DEVICE_NAME "nimble" #endif +#ifndef CONFIG_BT_NIMBLE_ATT_PREFERRED_MTU +#define CONFIG_BT_NIMBLE_ATT_PREFERRED_MTU 255 +#endif + +#ifndef CONFIG_BT_NIMBLE_SVC_GAP_APPEARANCE +#define CONFIG_BT_NIMBLE_SVC_GAP_APPEARANCE 0x0 +#endif + +#ifndef CONFIG_BT_NIMBLE_MSYS1_BLOCK_COUNT +#define CONFIG_BT_NIMBLE_MSYS1_BLOCK_COUNT 12 +#endif + +#ifndef CONFIG_BT_NIMBLE_RPA_TIMEOUT +#define CONFIG_BT_NIMBLE_RPA_TIMEOUT 900 +#endif + + /** @brief Set if CCCD's and bond data should be stored in NVS */ #define CONFIG_BT_NIMBLE_NVS_PERSIST 1 @@ -152,12 +163,6 @@ /** @brief Max device name length (bytes) */ #define CONFIG_BT_NIMBLE_GAP_DEVICE_NAME_MAX_LEN 31 -/** @brief Default MTU size */ -#define CONFIG_BT_NIMBLE_ATT_PREFERRED_MTU 256 - -/** @brief Default GAP appearance */ -#define CONFIG_BT_NIMBLE_SVC_GAP_APPEARANCE 0x0 - /** @brief ACL Buffer count */ #define CONFIG_BT_NIMBLE_ACL_BUF_COUNT 12 @@ -173,21 +178,9 @@ /** @brief Number of low priority HCI event buffers */ #define CONFIG_BT_NIMBLE_HCI_EVT_LO_BUF_COUNT 8 -/** - * @brief Sets the number of MSYS buffers available. - * @details MSYS is a system level mbuf registry. For prepare write & prepare \n - * responses MBUFs are allocated out of msys_1 pool. This may need to be increased if\n - * you are sending large blocks of data with a low MTU. E.g: 512 bytes with 23 MTU will fail. - */ -#define CONFIG_BT_NIMBLE_MSYS1_BLOCK_COUNT 12 - -/** @brief Random address refresh time in seconds */ -#define CONFIG_BT_NIMBLE_RPA_TIMEOUT 900 - /** @brief Maximum number of connection oriented channels */ #define CONFIG_BT_NIMBLE_L2CAP_COC_MAX_NUM 0 -/* These should not be altered */ #define CONFIG_BT_NIMBLE_HS_FLOW_CTRL 1 #define CONFIG_BT_NIMBLE_HS_FLOW_CTRL_ITVL 1000 #define CONFIG_BT_NIMBLE_HS_FLOW_CTRL_THRESH 2 @@ -197,14 +190,9 @@ #define CONFIG_BT_ENABLED #endif +#ifndef CONFIG_BTDM_CONTROLLER_MODE_BLE_ONLY #define CONFIG_BTDM_CONTROLLER_MODE_BLE_ONLY - -#endif // #if defined(CONFIG_BT_NIMBLE_TASK_STACK_SIZE) || defined(CONFIG_NIMBLE_TASK_STACK_SIZE) - -/********************************** - End Arduino config -**********************************/ - +#endif /* Cannot use client without scan */ #if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL) && !defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER) @@ -216,26 +204,3 @@ #define CONFIG_BT_NIMBLE_ROLE_BROADCASTER #endif - - -#ifdef _DOXYGEN_ -/** @brief Uncomment to see debug log messages from the NimBLE host \n - * Uses approx. 32kB of flash memory. - */ -#define CONFIG_BT_NIMBLE_DEBUG - -/** @brief Uncomment to see NimBLE host return codes as text debug log messages. \n - * Uses approx. 7kB of flash memory. - */ -#define CONFIG_NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT - -/** @brief Uncomment to see GAP event codes as text in debug log messages. \n - * Uses approx. 1kB of flash memory. - */ -#define CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT - -/** @brief Uncomment to see advertisment types as text while scanning in debug log messages. \n - * Uses approx. 250 bytes of flash memory. - */ -#define CONFIG_NIMBLE_CPP_ENABLE_ADVERTISMENT_TYPE_TEXT -#endif // _DOXYGEN_ diff --git a/lib/libesp32/NimBLE-Arduino/src/nimconfig_rename.h b/lib/libesp32/NimBLE-Arduino/src/nimconfig_rename.h new file mode 100644 index 000000000..3b96c1fec --- /dev/null +++ b/lib/libesp32/NimBLE-Arduino/src/nimconfig_rename.h @@ -0,0 +1,53 @@ +/* + * For ESP-IDF compatibility + * Some versions of ESP-IDF used the config name format "CONFIG_NIMBLE_". + * This converts them to "CONFIG_BT_NIMBLE_" format used in the latest IDF. + */ + +#if defined(CONFIG_NIMBLE_ENABLED) && !defined(CONFIG_BT_NIMBLE_ENABLED) +#define CONFIG_BT_NIMBLE_ENABLED +#endif + +#if defined(CONFIG_NIMBLE_ROLE_OBSERVER) && !defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER) +#define CONFIG_BT_NIMBLE_ROLE_OBSERVER +#endif + +#if defined(CONFIG_NIMBLE_ROLE_BROADCASTER) && !defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER) +#define CONFIG_BT_NIMBLE_ROLE_BROADCASTER +#endif + +#if defined(CONFIG_NIMBLE_ROLE_CENTRAL) && !defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL) +#define CONFIG_BT_NIMBLE_ROLE_CENTRAL +#endif + +#if defined(CONFIG_NIMBLE_ROLE_PERIPHERAL) && !defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) +#define CONFIG_BT_NIMBLE_ROLE_PERIPHERAL +#endif + +#if defined(CONFIG_NIMBLE_DEBUG) && !defined(CONFIG_BT_NIMBLE_DEBUG) +#define CONFIG_BT_NIMBLE_DEBUG +#endif + +#if defined(CONFIG_SCAN_DUPLICATE_BY_DEVICE_ADDR) && !defined(CONFIG_BTDM_SCAN_DUPL_TYPE_DEVICE) +#define CONFIG_BTDM_SCAN_DUPL_TYPE_DEVICE CONFIG_SCAN_DUPLICATE_BY_DEVICE_ADDR +#endif + +#if defined(CONFIG_SCAN_DUPLICATE_BY_ADV_DATA ) && !defined(CONFIG_BTDM_SCAN_DUPL_TYPE_DATA) +#define CONFIG_BTDM_SCAN_DUPL_TYPE_DATA CONFIG_SCAN_DUPLICATE_BY_ADV_DATA +#endif + +#if defined(CONFIG_SCAN_DUPLICATE_BY_ADV_DATA_AND_DEVICE_ADDR) && !defined(CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE) +#define CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE CONFIG_SCAN_DUPLICATE_BY_ADV_DATA_AND_DEVICE_ADDR +#endif + +#if defined(CONFIG_SCAN_DUPLICATE_TYPE) && !defined(CONFIG_BTDM_SCAN_DUPL_TYPE) +#define CONFIG_BTDM_SCAN_DUPL_TYPE CONFIG_SCAN_DUPLICATE_TYPE +#endif + +#if defined(CONFIG_DUPLICATE_SCAN_CACHE_SIZE) && !defined(CONFIG_BTDM_SCAN_DUPL_CACHE_SIZE) +#define CONFIG_BTDM_SCAN_DUPL_CACHE_SIZE CONFIG_DUPLICATE_SCAN_CACHE_SIZE +#endif + +#if defined(CONFIG_NIMBLE_MAX_CONNECTIONS ) && !defined(CONFIG_BT_NIMBLE_MAX_CONNECTIONS) +#define CONFIG_BT_NIMBLE_MAX_CONNECTIONS CONFIG_NIMBLE_MAX_CONNECTIONS +#endif