diff --git a/src/.gitignore b/src/.gitignore
new file mode 100644
index 0000000..ce66cbf
--- /dev/null
+++ b/src/.gitignore
@@ -0,0 +1,3 @@
+build/
+sdkconfig
+sdkconfig.old
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644
index 0000000..bda6977
--- /dev/null
+++ b/src/CMakeLists.txt
@@ -0,0 +1,6 @@
+# The following lines of boilerplate have to be in your project's
+# CMakeLists in this exact order for cmake to work correctly
+cmake_minimum_required(VERSION 3.5)
+
+include($ENV{IDF_PATH}/tools/cmake/project.cmake)
+project(app-template)
diff --git a/src/Makefile b/src/Makefile
new file mode 100644
index 0000000..9f2c327
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,9 @@
+#
+# This is a project Makefile. It is assumed the directory this Makefile resides in is a
+# project subdirectory.
+#
+
+PROJECT_NAME := app-template
+
+include $(IDF_PATH)/make/project.mk
+
diff --git a/src/components/GPIO_drv/.cproject b/src/components/GPIO_drv/.cproject
new file mode 100644
index 0000000..71886d5
--- /dev/null
+++ b/src/components/GPIO_drv/.cproject
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/components/GPIO_drv/.project b/src/components/GPIO_drv/.project
new file mode 100644
index 0000000..c83198f
--- /dev/null
+++ b/src/components/GPIO_drv/.project
@@ -0,0 +1,20 @@
+
+
+ GPIO_drv
+
+
+
+
+
+ org.eclipse.cdt.core.cBuilder
+ clean,full,incremental,
+
+
+
+
+
+ org.eclipse.cdt.core.cnature
+ org.eclipse.cdt.core.ccnature
+ org.eclipse.cdt.cmake.core.cmakeNature
+
+
diff --git a/src/components/GPIO_drv/CMakeLists.txt b/src/components/GPIO_drv/CMakeLists.txt
new file mode 100644
index 0000000..801d577
--- /dev/null
+++ b/src/components/GPIO_drv/CMakeLists.txt
@@ -0,0 +1,3 @@
+idf_component_register(SRCS "GPIO_drv.cpp"
+ INCLUDE_DIRS "."
+ )
\ No newline at end of file
diff --git a/src/components/GPIO_drv/GPIO_drv.cpp b/src/components/GPIO_drv/GPIO_drv.cpp
new file mode 100644
index 0000000..febe13b
--- /dev/null
+++ b/src/components/GPIO_drv/GPIO_drv.cpp
@@ -0,0 +1,48 @@
+#include "GPIO_drv.hpp"
+#include
+#include "esp_log.h"
+
+bool GPIO_drv::isr_service_installed = false;
+
+GPIO_drv::GPIO_drv()
+ : clbk_ptr(nullptr)
+{
+}
+
+GPIO_drv::~GPIO_drv()
+{
+}
+
+void GPIO_drv::init(gpio_num_t but, gpio_mode_t mode, gpio_pullup_t pu, gpio_pulldown_t pd)
+{
+ button = but;
+ gpio_config_t io_conf;
+ io_conf.intr_type = GPIO_INTR_DISABLE;
+ io_conf.mode = mode;
+ io_conf.pin_bit_mask = (1ULL << button);
+ io_conf.pull_down_en = pd;
+ io_conf.pull_up_en = pu;
+ gpio_config(&io_conf);
+}
+
+void GPIO_drv::enableINT(gpio_int_type_t type, Callback ptr)
+{
+ gpio_set_intr_type(button, type);
+ if (!isr_service_installed)
+ {
+ gpio_install_isr_service(0);
+ isr_service_installed = true;
+ }
+ gpio_isr_handler_add(button, ptr, (void*)button);
+ gpio_intr_enable(button);
+}
+
+void GPIO_drv::setLvl(Lvl lvl)
+{
+ gpio_set_level(button, static_cast(lvl));
+}
+
+Lvl GPIO_drv::getLvl()
+{
+ return static_cast(gpio_get_level(button));
+}
diff --git a/src/components/GPIO_drv/GPIO_drv.hpp b/src/components/GPIO_drv/GPIO_drv.hpp
new file mode 100644
index 0000000..8ff9a1f
--- /dev/null
+++ b/src/components/GPIO_drv/GPIO_drv.hpp
@@ -0,0 +1,32 @@
+#pragma once
+#include
+#include "driver/gpio.h"
+
+using Callback = void(*)(void *);
+
+enum class Lvl {reset, set};
+
+class GPIO_drv
+{
+public:
+ GPIO_drv();
+
+ virtual ~GPIO_drv();
+
+ void init(gpio_num_t but,
+ gpio_mode_t mode,
+ gpio_pullup_t pu = GPIO_PULLUP_DISABLE,
+ gpio_pulldown_t pd = GPIO_PULLDOWN_DISABLE);
+
+ void enableINT(gpio_int_type_t type, Callback ptr);
+
+ void setLvl(Lvl lvl);
+ Lvl getLvl();
+ inline gpio_num_t getGpioNum(void) {return button;}
+
+private:
+ gpio_num_t button;
+ Callback clbk_ptr;
+ static bool isr_service_installed;
+};
+
diff --git a/src/components/SPI_drv/.cproject b/src/components/SPI_drv/.cproject
new file mode 100644
index 0000000..71886d5
--- /dev/null
+++ b/src/components/SPI_drv/.cproject
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/components/SPI_drv/.project b/src/components/SPI_drv/.project
new file mode 100644
index 0000000..db20241
--- /dev/null
+++ b/src/components/SPI_drv/.project
@@ -0,0 +1,20 @@
+
+
+ SPI_drv
+
+
+
+
+
+ org.eclipse.cdt.core.cBuilder
+ clean,full,incremental,
+
+
+
+
+
+ org.eclipse.cdt.core.cnature
+ org.eclipse.cdt.core.ccnature
+ org.eclipse.cdt.cmake.core.cmakeNature
+
+
diff --git a/src/components/SPI_drv/CMakeLists.txt b/src/components/SPI_drv/CMakeLists.txt
new file mode 100644
index 0000000..3394022
--- /dev/null
+++ b/src/components/SPI_drv/CMakeLists.txt
@@ -0,0 +1,4 @@
+idf_component_register(SRCS "SPI_drv.cpp"
+ INCLUDE_DIRS "."
+ REQUIRES log
+ )
\ No newline at end of file
diff --git a/src/components/SPI_drv/SPI_drv.cpp b/src/components/SPI_drv/SPI_drv.cpp
new file mode 100644
index 0000000..5044e73
--- /dev/null
+++ b/src/components/SPI_drv/SPI_drv.cpp
@@ -0,0 +1,147 @@
+#include "SPI_drv.hpp"
+#include
+#include
+//#include
+
+//#define DEBUG 1
+
+namespace
+{
+ static constexpr char LOG_TAG[] = "SPI";
+}
+
+SPI_drv::SPI_drv()
+ : m_handle(nullptr)
+{
+}
+
+void SPI_drv::init(spi_host_device_t host, int freq, gpio_num_t cs_pin, bool useMiso, uint8_t spiMode, uint32_t flags)
+{
+ int misoPin;
+ if (useMiso) misoPin = (host == VSPI_HOST) ? 19 : 12;
+ else misoPin = -1;
+
+ spi_bus_config_t bus_config = {};
+ bus_config.sclk_io_num = (host == VSPI_HOST) ? 18 : 14; // CLK
+ bus_config.mosi_io_num = (host == VSPI_HOST) ? 23 : 13; // MOSI
+ bus_config.miso_io_num = misoPin; // MISO
+ bus_config.quadwp_io_num = -1; // Not used
+ bus_config.quadhd_io_num = -1; // Not used
+ bus_config.flags = (SPICOMMON_BUSFLAG_SCLK | SPICOMMON_BUSFLAG_MOSI);
+
+ esp_err_t errRc = spi_bus_initialize(
+ host,
+ &bus_config,
+ host // DMA Channel
+ );
+
+ if (errRc != ESP_OK) {
+ ESP_LOGE(LOG_TAG, "spi_bus_initialize(): rc=%d", errRc);
+ abort();
+ }
+
+ spi_device_interface_config_t dev_config = {};
+
+
+ dev_config.clock_speed_hz = freq;
+ dev_config.spics_io_num = cs_pin;
+ dev_config.flags |= SPI_DEVICE_NO_DUMMY;
+ dev_config.queue_size = 1;
+ /*добавляем фазу передачи команды длиной 8 бит */
+ //dev_config.command_bits = 8;
+ //dev_config.input_delay_ns = 10;
+ dev_config.mode = spiMode; //SPI mode, representing a pair of (CPOL, CPHA) configuration: 3 - (1, 1)
+ // 2 - (1, 0)
+ dev_config.cs_ena_pretrans = 0;
+ dev_config.cs_ena_posttrans = 0;
+ dev_config.duty_cycle_pos = 128;
+ //dev_config.flags |= (SPI_DEVICE_BIT_LSBFIRST);
+ dev_config.flags |= flags;
+
+
+ //ESP_LOGI(LOG_TAG, "... Adding device bus.");
+ errRc = ::spi_bus_add_device(host, &dev_config, &m_handle);
+ if (errRc != ESP_OK) {
+ ESP_LOGE(LOG_TAG, "spi_bus_add_device(): rc=%d", errRc);
+ abort();
+ }
+}
+
+void SPI_drv::receive(std::uint8_t* rx_data, size_t dataLen)
+{
+
+ // spi_transaction_t t = {
+ // .cmd = CMD_READ | (addr & ADDR_MASK),
+ // .rxlength = 8,
+ // .flags = SPI_TRANS_USE_RXDATA,
+ // .user = ctx,
+ // };
+
+ //uint8_t buf[3] = {};
+
+ assert(rx_data != nullptr);
+ assert(dataLen > 0);
+
+ spi_transaction_t trans_desc = {};
+ trans_desc.length = dataLen * 8;
+ //trans_desc.tx_buffer = buf;
+ //trans_desc.cmd = 0x00;
+ trans_desc.rx_buffer = rx_data;
+ //trans_desc.rxlength = 0;
+ esp_err_t rc = spi_device_polling_transmit(m_handle, &trans_desc);
+ //esp_err_t rc = spi_device_transmit(m_handle, &trans_desc);
+ if (rc != ESP_OK) {
+ ESP_LOGE(LOG_TAG, "transfer:spi_device_transmit: %d", rc);
+ }
+}
+
+void SPI_drv::transfer(std::uint8_t* data, size_t dataLen) {
+ assert(data != nullptr);
+ assert(dataLen > 0);
+
+ spi_transaction_t trans_desc = {};
+ trans_desc.length = dataLen * 8;
+ trans_desc.tx_buffer = data;
+ esp_err_t rc = spi_device_polling_transmit(m_handle, &trans_desc);
+ //esp_err_t rc = spi_device_transmit(m_handle, &trans_desc);
+ if (rc != ESP_OK) {
+ ESP_LOGE(LOG_TAG, "transfer:spi_device_transmit: %d", rc);
+ }
+} // transmit
+
+void SPI_drv::cmd_write(std::uint16_t command, std::uint8_t* transfer_data, std::uint8_t byte2write){
+ spi_transaction_t trans_desc = {};
+ trans_desc.cmd = command;
+ trans_desc.length = (byte2write)*8;
+ trans_desc.tx_buffer = transfer_data;
+ esp_err_t rc = spi_device_polling_transmit(m_handle, &trans_desc);
+ //esp_err_t rc = spi_device_transmit(m_handle, &trans_desc);
+ if (rc != ESP_OK) {
+ ESP_LOGE(LOG_TAG, "transfer:spi_device_transmit: %d", rc);
+ }
+}
+
+void SPI_drv::cmd_read(std::uint16_t command, std::uint8_t* read_data,std::uint8_t byte2read){
+ spi_transaction_t trans_desc = {};
+ trans_desc.length = byte2read*8;
+ trans_desc.cmd = command;
+ //trans_desc.rxlength = 0;
+ //trans_desc.flags = SPI_TRANS_USE_RXDATA;
+ trans_desc.rx_buffer = read_data;
+
+
+
+ esp_err_t rc = spi_device_polling_transmit(m_handle, &trans_desc);
+ //esp_err_t rc = spi_device_transmit(m_handle, &trans_desc);
+ //*read_data = trans_desc.rx_data[0];
+ if (rc != ESP_OK) {
+ ESP_LOGE(LOG_TAG, "transfer:spi_device_transmit: %d", rc);
+ }
+
+}
+
+
+uint8_t SPI_drv::transferByte(std::uint8_t value) {
+ transfer(&value, 1);
+ return value;
+} // transferByte
\ No newline at end of file
diff --git a/src/components/SPI_drv/SPI_drv.hpp b/src/components/SPI_drv/SPI_drv.hpp
new file mode 100644
index 0000000..2ab2e3a
--- /dev/null
+++ b/src/components/SPI_drv/SPI_drv.hpp
@@ -0,0 +1,19 @@
+#pragma once
+#include
+#include
+#include
+
+class SPI_drv {
+public:
+ SPI_drv();
+
+ void init(spi_host_device_t host, int freq = 1000000, gpio_num_t cs_pin = GPIO_NUM_NC, bool useMiso = false, uint8_t spiMode = 0, uint32_t flags = 0);
+ void transfer(std::uint8_t* data, size_t dataLen);
+ void receive(std::uint8_t* rx_data, size_t dataLen);
+ std::uint8_t transferByte(std::uint8_t value);
+ void cmd_write(std::uint16_t command, std::uint8_t* transfer_data, std::uint8_t byte2write);
+ void cmd_read (std::uint16_t command, std::uint8_t* read_data,std::uint8_t byte2read);
+
+private:
+ spi_device_handle_t m_handle;
+};
\ No newline at end of file
diff --git a/src/components/esp-nimble-cpp-1.3.3/CHANGELOG.md b/src/components/esp-nimble-cpp-1.3.3/CHANGELOG.md
new file mode 100644
index 0000000..3dfcd1b
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/CHANGELOG.md
@@ -0,0 +1,251 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+## [1.3.3] - 2022-02-15
+
+### Changed
+- If attribute retrieval fails with a "not found" try again with the 16 bit version if a 128 bit base uuid is used.
+
+### Fixed
+- Memory leak when deleting client instance.
+- IDf version check for data length extension.
+- Memory leak when server services changed.
+- Compiler warnings for non-esp32 devices.
+
+## [1.3.2] - 2022-01-15
+
+### Fixed
+- Initialize advertising complete callback in NimBLEAdvertising constructor.
+- Clear client disconnect timer in constructor before initializing.
+- Fix missing data when reading large values.
+- Fix missing data in notifications when using a large MTU size and more than 270 bytes of data are sent.
+- Workaround fix added for cases when the task notification value is not cleared, causing various functions that should block not to block.
+
+### Added
+- `NimBLEClient::getLastError` : Gets the error code of the last function call that produces a return code from the stack.
+- `NimBLECharacteristic::notify` : Overload method to send notifications/indications with custom values.
+- Added conditional checks for ESP32 specific functions/values to support use of the library on non-esp32 devices.
+- Added an alias to use the callback name from the original library `onMtuChanged`.
+- `NimBLEClient::setDataLen` and `NimBLEServer::setDataLen`: Data length extension support (IDF version >= 4.3.2 only)
+- Config option to set logging level for esp-nimble-cpp
+
+### Changed
+- Critical section calls now use the NimBLE API instead of FreeRTOS directly. This removes the need for a `portMUX_TYPE` variable in the class definitions.
+- Removed unnecessary variables in `NimBLEService` and changed the constructor no no longer accept `numHandles` and `inst_id` parameters.
+
+## [1.3.1] - 2021-08-04
+
+### Fixed
+- Corrected a compiler/linker error when an application or a library uses bluetooth classic due to the redefinition of `btInUse`.
+
+## [1.3.0] - 2021-08-02
+
+### Added
+- `NimBLECharacteristic::removeDescriptor`: Dynamically remove a descriptor from a characterisic. Takes effect after all connections are closed and sends a service changed indication.
+- `NimBLEService::removeCharacteristic`: Dynamically remove a characteristic from a service. Takes effect after all connections are closed and sends a service changed indication
+- `NimBLEServerCallbacks::onMTUChange`: This is callback is called when the MTU is updated after connection with a client.
+- ESP32C3 support
+
+- Whitelist API:
+ - `NimBLEDevice::whiteListAdd`: Add a device to the whitelist.
+ - `NimBLEDevice::whiteListRemove`: Remove a device from the whitelist.
+ - `NimBLEDevice::onWhiteList`: Check if the device is on the whitelist.
+ - `NimBLEDevice::getWhiteListCount`: Gets the size of the whitelist
+ - `NimBLEDevice::getWhiteListAddress`: Get the address of a device on the whitelist by index value.
+
+- Bond management API:
+ - `NimBLEDevice::getNumBonds`: Gets the number of bonds stored.
+ - `NimBLEDevice::isBonded`: Checks if the device is bonded.
+ - `NimBLEDevice::deleteAllBonds`: Deletes all bonds.
+ - `NimBLEDevice::getBondedAddress`: Gets the address of a bonded device by the index value.
+
+- `NimBLECharacteristic::getCallbacks` to retrieve the current callback handler.
+- Connection Information class: `NimBLEConnInfo`.
+- `NimBLEScan::clearDuplicateCache`: This can be used to reset the cache of advertised devices so they will be immediately discovered again.
+
+### Changed
+- FreeRTOS files have been removed as they are not used by the library.
+- Services, characteristics and descriptors can now be created statically and added after.
+- Excess logging and some asserts removed.
+- Use ESP_LOGx macros to enable using local log level filtering.
+
+### Fixed
+- `NimBLECharacteristicCallbacks::onSubscribe` Is now called after the connection is added to the vector.
+- Corrected bonding failure when reinitializing the BLE stack.
+- Writing to a characterisic with a std::string value now correctly writes values with null characters.
+- Retrieving remote descriptors now uses the characterisic end handle correctly.
+- Missing data in long writes to remote descriptors.
+- Hanging on task notification when sending an indication from the characteristic callback.
+- BLE controller memory could be released when using Arduino as a component.
+- Complile errors with NimBLE release 1.3.0.
+
+## [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
+- `NimBLEDevice::setOwnAddrType` added to enable the use of random and random-resolvable addresses, by asukiaaa
+
+- New examples for securing and authenticating client/server connections, by mblasee.
+
+- `NimBLEAdvertising::SetMinPreferred` and `NimBLEAdvertising::SetMinPreferred` re-added.
+
+- Conditional checks added for command line config options in `nimconfig.h` to support custom configuration in platformio.
+
+- `NimBLEClient::setValue` Now takes an extra bool parameter `response` to enable the use of write with response (default = false).
+
+- `NimBLEClient::getCharacteristic(uint16_t handle)` Enabling the use of the characteristic handle to be used to find
+the NimBLERemoteCharacteristic object.
+
+- `NimBLEHIDDevice` class added by wakwak-koba.
+
+- `NimBLEServerCallbacks::onDisconnect` overloaded callback added to provide a ble_gap_conn_desc parameter for the application
+to obtain information about the disconnected client.
+
+- Conditional checks in `nimconfig.h` for command line defined macros to support platformio config settings.
+
+### Changed
+- `NimBLEAdvertising::start` now returns a bool value to indicate success/failure.
+
+- Some asserts were removed in `NimBLEAdvertising::start` and replaced with better return code handling and logging.
+
+- If a host reset event occurs, scanning and advertising will now only be restarted if their previous duration was indefinite.
+
+- `NimBLERemoteCharacteristic::subscribe` and `NimBLERemoteCharacteristic::registerForNotify` will now set the callback
+regardless of the existance of the CCCD and return true unless the descriptor write operation failed.
+
+- Advertising tx power level is now sent in the advertisement packet instead of scan response.
+
+- `NimBLEScan` When the scan ends the scan stopped flag is now set before calling the scan complete callback (if used)
+this allows the starting of a new scan from the callback function.
+
+### Fixed
+- Sometimes `NimBLEClient::connect` would hang on the task block if no event arrived to unblock.
+A time limit has been added to timeout appropriately.
+
+- When getting descriptors for a characterisic the end handle of the service was used as a proxy for the characteristic end
+handle. This would be rejected by some devices and has been changed to use the next characteristic handle as the end when possible.
+
+- An exception could occur when deleting a client instance if a notification arrived while the attribute vectors were being
+deleted. A flag has been added to prevent this.
+
+- An exception could occur after a host reset event when the host re-synced if the tasks that were stopped during the event did
+not finish processing. A yield has been added after re-syncing to allow tasks to finish before proceeding.
+
+- Occasionally the controller would fail to send a disconnected event causing the client to indicate it is connected
+and would be unable to reconnect. A timer has been added to reset the host/controller if it expires.
+
+- Occasionally the call to start scanning would get stuck in a loop on BLE_HS_EBUSY, this loop has been removed.
+
+- 16bit and 32bit UUID's in some cases were not discovered or compared correctly if the device
+advertised them as 16/32bit but resolved them to 128bits. Both are now checked.
+
+- `FreeRTOS` compile errors resolved in latest Ardruino core and IDF v3.3.
+
+- Multiple instances of `time()` called inside critical sections caused sporadic crashes, these have been moved out of critical regions.
+
+- Advertisement type now correctly set when using non-connectable (advertiser only) mode.
+
+- Advertising payload length correction, now accounts for appearance.
+
+- (Arduino) Ensure controller mode is set to BLE Only.
+
+
+## [1.0.2] - 2020-09-13
+
+### Changed
+
+- `NimBLEAdvertising::start` Now takes 2 optional parameters, the first is the duration to advertise for (in seconds), the second is a
+callback that is invoked when advertsing ends and takes a pointer to a `NimBLEAdvertising` object (similar to the `NimBLEScan::start` API).
+
+- (Arduino) Maximum BLE connections can now be altered by only changing the value of `CONFIG_BT_NIMBLE_MAX_CONNECTIONS` in `nimconfig.h`.
+Any changes to the controller max connection settings in `sdkconfig.h` will now have no effect when using this library.
+
+- (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
+
+- Empty `NimBLEAddress` constructor: `NimBLEAddress()` produces an address of 00:00:00:00:00:00 type 0.
+- Documentation of the difference of NimBLEAddress::getNative vs the original bluedroid library.
+
+### Changed
+
+- notify_callback typedef is now defined as std::function to enable the use of std::bind to call a class member function.
+
+### Fixed
+
+- Fix advertising start delay when first called.
+
+
+## [1.0.0] - 2020-08-22
+
+First stable release.
+
+All the original library functionality is complete and many extras added with full documentation.
diff --git a/src/components/esp-nimble-cpp-1.3.3/CMakeLists.txt b/src/components/esp-nimble-cpp-1.3.3/CMakeLists.txt
new file mode 100644
index 0000000..23b1aa5
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/CMakeLists.txt
@@ -0,0 +1,58 @@
+# The following lines of boilerplate have to be in your project's
+# CMakeLists in this exact order for cmake to work correctly
+cmake_minimum_required(VERSION 3.5)
+
+idf_build_get_property(__hack_component_targets __COMPONENT_TARGETS)
+
+if("esp-nimble-component" IN_LIST BUILD_COMPONENTS OR "__esp-nimble-component" IN_LIST __hack_component_targets)
+ list(APPEND ESP_NIMBLE_PRIV_REQUIRES
+ esp-nimble-component
+ )
+elseif("nimble" IN_LIST BUILD_COMPONENTS OR "__nimble" IN_LIST __hack_component_targets)
+ list(APPEND ESP_NIMBLE_PRIV_REQUIRES
+ nimble
+ )
+endif()
+
+if("arduino" IN_LIST BUILD_COMPONENTS OR __hack_component_targets MATCHES "__idf_arduino")
+ list(APPEND ESP_NIMBLE_PRIV_REQUIRES
+ arduino
+ )
+endif()
+
+idf_component_register(
+ REQUIRED_IDF_TARGETS
+ "esp32"
+ "esp32s3"
+ "esp32c3"
+ INCLUDE_DIRS
+ "src"
+ SRCS
+ "src/NimBLE2904.cpp"
+ "src/NimBLEAddress.cpp"
+ "src/NimBLEAdvertisedDevice.cpp"
+ "src/NimBLEAdvertising.cpp"
+ "src/NimBLEBeacon.cpp"
+ "src/NimBLECharacteristic.cpp"
+ "src/NimBLEClient.cpp"
+ "src/NimBLEDescriptor.cpp"
+ "src/NimBLEDevice.cpp"
+ "src/NimBLEEddystoneTLM.cpp"
+ "src/NimBLEEddystoneURL.cpp"
+ "src/NimBLEHIDDevice.cpp"
+ "src/NimBLERemoteCharacteristic.cpp"
+ "src/NimBLERemoteDescriptor.cpp"
+ "src/NimBLERemoteService.cpp"
+ "src/NimBLEScan.cpp"
+ "src/NimBLESecurity.cpp"
+ "src/NimBLEServer.cpp"
+ "src/NimBLEService.cpp"
+ "src/NimBLEUtils.cpp"
+ "src/NimBLEUUID.cpp"
+ REQUIRES
+ bt
+ nvs_flash
+ PRIV_REQUIRES
+ ${ESP_NIMBLE_PRIV_REQUIRES}
+)
+
diff --git a/src/components/esp-nimble-cpp-1.3.3/CMakeLists.txt_idf3 b/src/components/esp-nimble-cpp-1.3.3/CMakeLists.txt_idf3
new file mode 100644
index 0000000..c548f90
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/CMakeLists.txt_idf3
@@ -0,0 +1,56 @@
+# The following lines of boilerplate have to be in your project's
+# CMakeLists in this exact order for cmake to work correctly
+cmake_minimum_required(VERSION 3.5)
+
+set(SUPPORTED_TARGETS esp32)
+
+set(COMPONENT_SRCS
+ "src/NimBLE2904.cpp"
+ "src/NimBLEAddress.cpp"
+ "src/NimBLEAdvertisedDevice.cpp"
+ "src/NimBLEAdvertising.cpp"
+ "src/NimBLEBeacon.cpp"
+ "src/NimBLECharacteristic.cpp"
+ "src/NimBLEClient.cpp"
+ "src/NimBLEDescriptor.cpp"
+ "src/NimBLEDevice.cpp"
+ "src/NimBLEEddystoneTLM.cpp"
+ "src/NimBLEEddystoneURL.cpp"
+ "src/NimBLEHIDDevice.cpp"
+ "src/NimBLERemoteCharacteristic.cpp"
+ "src/NimBLERemoteDescriptor.cpp"
+ "src/NimBLERemoteService.cpp"
+ "src/NimBLEScan.cpp"
+ "src/NimBLESecurity.cpp"
+ "src/NimBLEServer.cpp"
+ "src/NimBLEService.cpp"
+ "src/NimBLEUtils.cpp"
+ "src/NimBLEUUID.cpp"
+)
+
+set(COMPONENT_ADD_INCLUDEDIRS
+ src
+)
+
+set(COMPONENT_PRIV_REQUIRES
+ nvs_flash
+ bt
+)
+
+if(COMPONENTS MATCHES "esp-nimble-component")
+ list(APPEND COMPONENT_PRIV_REQUIRES
+ esp-nimble-component
+ )
+elseif(COMPONENTS MATCHES "nimble")
+ list(APPEND COMPONENT_PRIV_REQUIRES
+ nimble
+ )
+endif()
+
+if(COMPONENTS MATCHES "arduino")
+ list(APPEND COMPONENT_PRIV_REQUIRES
+ arduino
+ )
+endif()
+
+register_component()
diff --git a/src/components/esp-nimble-cpp-1.3.3/Kconfig b/src/components/esp-nimble-cpp-1.3.3/Kconfig
new file mode 100644
index 0000000..b2a655d
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/Kconfig
@@ -0,0 +1,53 @@
+menu "ESP-NimBLE-CPP configuration"
+
+choice NIMBLE_CPP_LOG_LEVEL
+ prompt "NimBLE CPP log verbosity"
+ default NIMBLE_CPP_LOG_LEVEL_NONE
+ help
+ Select NimBLE CPP log verbosity level.
+
+ config NIMBLE_CPP_LOG_LEVEL_NONE
+ bool "No logs"
+ config NIMBLE_CPP_LOG_LEVEL_ERROR
+ bool "Error logs"
+ config NIMBLE_CPP_LOG_LEVEL_WARNING
+ bool "Warning logs"
+ config NIMBLE_CPP_LOG_LEVEL_INFO
+ bool "Info logs"
+ config NIMBLE_CPP_LOG_LEVEL_DEBUG
+ bool "Debug logs"
+endchoice #NIMBLE_CPP_LOG_LEVEL
+
+config NIMBLE_CPP_LOG_LEVEL
+ int
+ default 0 if NIMBLE_CPP_LOG_LEVEL_NONE
+ default 1 if NIMBLE_CPP_LOG_LEVEL_ERROR
+ default 2 if NIMBLE_CPP_LOG_LEVEL_WARNING
+ default 3 if NIMBLE_CPP_LOG_LEVEL_INFO
+ default 4 if NIMBLE_CPP_LOG_LEVEL_DEBUG
+
+config NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT
+ bool "Show NimBLE return codes as text in debug log."
+ default "n"
+ help
+ Enabling this option will display return code values as text
+ messages in the debug log. This will use approximately 8kB
+ of flash memory.
+
+config NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT
+ bool "Show NimBLE gap events as text in debug log."
+ default "n"
+ help
+ Enabling this option will display gap event codes as text
+ messages in the debug log. This will use approximately 1kB
+ of flash memory.
+
+config NIMBLE_CPP_ENABLE_ADVERTISMENT_TYPE_TEXT
+ bool "Show advertisment types as text in debug log."
+ default "n"
+ help
+ Enabling this option will display advertisment types recieved
+ while scanning as text messages in the debug log.
+ This will use approximately 250 bytes of flash memory.
+
+endmenu
diff --git a/src/components/esp-nimble-cpp-1.3.3/LICENSE b/src/components/esp-nimble-cpp-1.3.3/LICENSE
new file mode 100644
index 0000000..ff16276
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/LICENSE
@@ -0,0 +1,203 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "{}"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright {2020} {Ryan Powell}
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ This product partly derives from esp32-snippets; Copyright 2017 Neil Kolban.
\ No newline at end of file
diff --git a/src/components/esp-nimble-cpp-1.3.3/README.md b/src/components/esp-nimble-cpp-1.3.3/README.md
new file mode 100644
index 0000000..7f37eff
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/README.md
@@ -0,0 +1,70 @@
+[Latest release 
+](https://github.com/h2zero/esp-nimble-cpp/releases/latest/)
+
+Need help? Have questions or suggestions? Join the [](https://gitter.im/NimBLE-Arduino/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
+
+
+# esp-nimble-cpp
+
+NimBLE CPP library for use with ESP32 that attempts to maintain compatibility with the [nkolban cpp_uitls BLE API](https://github.com/nkolban/esp32-snippets/tree/master/cpp_utils).
+
+**An Arduino version of this library, including NimBLE, can be [found here.](https://github.com/h2zero/NimBLE-Arduino)**
+
+This library **significantly** reduces resource usage and improves performance for ESP32 BLE applications as compared
+with the bluedroid based library. The goal is to maintain, as much as reasonable, compatibility with the original
+library but refactored to use the NimBLE stack. In addition, this library will be more actively developed and maintained
+to provide improved capabilites and stability over the original.
+
+**Testing shows a nearly 50% reduction in flash use and approx. 100kB less ram consumed vs the original!**
+*Your results may vary*
+
+
+# What is NimBLE?
+NimBLE is a completely open source Bluetooth Low Energy stack produced by [Apache](https://github.com/apache/mynewt-nimble).
+It is more suited to resource constrained devices than bluedroid and has now been ported to the ESP32 by Espressif.
+
+
+# Installation
+
+### ESP-IDF v4.0+
+Download as .zip and extract or clone into the components folder in your esp-idf project.
+
+Run menuconfig, go to `Component config->Bluetooth` enable Bluetooth and in `Bluetooth host` NimBLE.
+Configure settings in `NimBLE Options`.
+`#include "NimBLEDevice.h"` in main.cpp.
+Call `NimBLEDevice::init("");` in `app_main`.
+
+
+### ESP-IDF v3.2 & v3.3
+The NimBLE component does not come with these versions of IDF (now included in 3.3.2 and above).
+A backport that works in these versions has been created and is [available here](https://github.com/h2zero/esp-nimble-component).
+Download or clone that repo into your project/components folder and run menuconfig.
+Configure settings in `main menu -> NimBLE Options`.
+
+`#include "NimBLEDevice.h"` in main.cpp.
+Call `NimBLEDevice::init("");` in `app_main`.
+
+
+# Using
+This library is intended to be compatible with the original ESP32 BLE functions and types with minor changes.
+
+If you have not used the original Bluedroid library please refer to the [New user guide](docs/New_user_guide.md).
+
+If you are familiar with the original library, see: [The migration guide](docs/Migration_guide.md) for details about breaking changes and migration.
+
+Also see [Improvements_and_updates](docs/Improvements_and_updates.md) for information about non-breaking changes.
+
+[Full API documentation and class list can be found here.](https://h2zero.github.io/esp-nimble-cpp/)
+
+
+## Using with Arduino as an IDF component and CMake
+When using this library along with Arduino and compiling with *CMake* you must add `add_compile_definitions(ARDUINO_ARCH_ESP32=1)`
+in your project/CMakeLists.txt after the line `include($ENV{IDF_PATH}/tools/cmake/project.cmake)` to prevent Arduino from releasing BLE memory.
+
+
+# Acknowledgments
+* [nkolban](https://github.com/nkolban) and [chegewara](https://github.com/chegewara) for the [original esp32 BLE library](https://github.com/nkolban/esp32-snippets/tree/master/cpp_utils) this project was derived from.
+* [beegee-tokyo](https://github.com/beegee-tokyo) for contributing your time to test/debug and contributing the beacon examples.
+* [Jeroen88](https://github.com/Jeroen88) for the amazing help debugging and improving the client code.
+
+
diff --git a/src/components/esp-nimble-cpp-1.3.3/component.mk b/src/components/esp-nimble-cpp-1.3.3/component.mk
new file mode 100644
index 0000000..5634368
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/component.mk
@@ -0,0 +1,2 @@
+COMPONENT_ADD_INCLUDEDIRS := src
+COMPONENT_SRCDIRS := src
\ No newline at end of file
diff --git a/src/components/esp-nimble-cpp-1.3.3/docs/Command_line_config.md b/src/components/esp-nimble-cpp-1.3.3/docs/Command_line_config.md
new file mode 100644
index 0000000..796eb1c
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/docs/Command_line_config.md
@@ -0,0 +1,124 @@
+# Arduino command line and platformio config options
+
+`CONFIG_BT_NIMBLE_MAX_CONNECTIONS`
+
+Sets the number of simultaneous connections (esp controller max is 9)
+- Default value is 3
+
+
+`CONFIG_BT_NIMBLE_ATT_PREFERRED_MTU`
+
+Sets the default MTU size.
+- Default value is 255
+
+
+`CONFIG_BT_NIMBLE_SVC_GAP_DEVICE_NAME`
+
+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_LOG_LEVEL`
+
+Define to set the debug log message level from the NimBLE CPP Wrapper.
+If not defined it will use the same value as the Arduino core debug level.
+Values: 0 = NONE, 1 = ERROR, 2 = WARNING, 3 = INFO, 4+ = DEBUG
+
+
+`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.
+- Default is 4096
+
+
diff --git a/src/components/esp-nimble-cpp-1.3.3/docs/Doxyfile b/src/components/esp-nimble-cpp-1.3.3/docs/Doxyfile
new file mode 100644
index 0000000..1d9a18b
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/docs/Doxyfile
@@ -0,0 +1,2669 @@
+# Doxyfile 1.9.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the configuration
+# file that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# https://www.gnu.org/software/libiconv/ for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = esp-nimble-cpp
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER = 1.3.2
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF =
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = .
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all generated output in the proper direction.
+# Possible values are: None, LTR, RTL and Context.
+# The default value is: None.
+
+OUTPUT_TEXT_DIRECTION = None
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line
+# such as
+# /***************
+# as being the beginning of a Javadoc-style comment "banner". If set to NO, the
+# Javadoc-style will behave just like regular comments and it will not be
+# interpreted by doxygen.
+# The default value is: NO.
+
+JAVADOC_BANNER = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# By default Python docstrings are displayed as preformatted text and doxygen's
+# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the
+# doxygen's special commands can be used and the contents of the docstring
+# documentation blocks is shown as doxygen documentation.
+# The default value is: YES.
+
+PYTHON_DOCSTRING = YES
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines (in the resulting output). You can put ^^ in the value part of an
+# alias to insert a newline as if a physical newline was in the original file.
+# When you need a literal { or } or , in the value part of an alias you have to
+# escape them by means of a backslash (\), this can lead to conflicts with the
+# commands \{ and \} for these it is advised to use the version @{ and @} or use
+# a double escape (\\{ and \\})
+
+ALIASES =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice
+# sources only. Doxygen will then generate output that is more tailored for that
+# language. For instance, namespaces will be presented as modules, types will be
+# separated into more groups, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_SLICE = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, JavaScript,
+# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, VHDL,
+# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:
+# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser
+# tries to guess whether the code is fixed or free formatted code, this is the
+# default for Fortran type files). For instance to make doxygen treat .inc files
+# as Fortran files (default is PHP), and .f files as C (default is Fortran),
+# use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen. When specifying no_extension you should add
+# * to the FILE_PATTERNS.
+#
+# Note see also the list of default file extension mappings.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See https://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up
+# to that level are automatically included in the table of contents, even if
+# they do not have an id attribute.
+# Note: This feature currently applies only to Markdown headings.
+# Minimum value: 0, maximum value: 99, default value: 5.
+# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
+
+TOC_INCLUDE_HEADINGS = 5
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use
+# during processing. When set to 0 doxygen will based this on the number of
+# cores available in the system. You can set it explicitly to a value larger
+# than 0 to get more control over the balance between CPU load and processing
+# speed. At this moment only the input processing can be done using multiple
+# threads. Since this is still an experimental feature the default is set to 1,
+# which efficively disables parallel processing. Please report any issues you
+# encounter. Generating dot graphs in parallel is controlled by the
+# DOT_NUM_THREADS setting.
+# Minimum value: 0, maximum value: 32, default value: 1.
+
+NUM_PROC_THREADS = 1
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual
+# methods of a class will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIV_VIRTUAL = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If this flag is set to YES, the name of an unnamed parameter in a declaration
+# will be determined by the corresponding definition. By default unnamed
+# parameters remain unnamed in the output.
+# The default value is: YES.
+
+RESOLVE_UNNAMED_PARAMS = YES
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = YES
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = YES
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# declarations. If set to NO, these declarations will be included in the
+# documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = YES
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = YES
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# With the correct setting of option CASE_SENSE_NAMES doxygen will better be
+# able to match the capabilities of the underlying filesystem. In case the
+# filesystem is case sensitive (i.e. it supports files in the same directory
+# whose names only differ in casing), the option must be set to YES to properly
+# deal with such files in case they appear in the input. For filesystems that
+# are not case sensitive the option should be be set to NO to properly deal with
+# output files written for symbols that only differ in casing, such as for two
+# classes, one named CLASS and the other named Class, and to also support
+# references to files without having to specify the exact matching casing. On
+# Windows (including Cygwin) and MacOS, users should typically set this option
+# to NO, whereas on Linux or other Unix flavors it should typically be set to
+# YES.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = NO
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if ... \endif and \cond
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = NO
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = NO
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation. If
+# EXTRACT_ALL is set to YES then this flag will automatically be disabled.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = NO
+
+# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
+# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
+# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but
+# at the end of the doxygen process doxygen will return with a non-zero status.
+# Possible values are: NO, YES and FAIL_ON_WARNINGS.
+# The default value is: NO.
+
+WARN_AS_ERROR = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = ../CHANGELOG.md \
+ . \
+ ../src
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see:
+# https://www.gnu.org/software/libiconv/) for the list of possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by doxygen.
+#
+# Note the list of default checked file patterns might differ from the list of
+# default file extension mappings.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
+# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
+# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
+# *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C comment),
+# *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, *.vhdl,
+# *.ucf, *.qsf and *.ice.
+
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.cxx \
+ *.cpp \
+ *.c++ \
+ *.java \
+ *.ii \
+ *.ixx \
+ *.ipp \
+ *.i++ \
+ *.inl \
+ *.idl \
+ *.ddl \
+ *.odl \
+ *.h \
+ *.hh \
+ *.hxx \
+ *.hpp \
+ *.h++ \
+ *.cs \
+ *.d \
+ *.php \
+ *.php4 \
+ *.php5 \
+ *.phtml \
+ *.inc \
+ *.m \
+ *.markdown \
+ *.md \
+ *.mm \
+ *.dox \
+ *.doc \
+ *.txt \
+ *.py \
+ *.pyw \
+ *.f90 \
+ *.f95 \
+ *.f03 \
+ *.f08 \
+ *.f18 \
+ *.f \
+ *.for \
+ *.vhd \
+ *.vhdl \
+ *.ucf \
+ *.qsf \
+ *.ice
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE = ../src/nimconfig_rename.h
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+#
+#
+# where is the value of the INPUT_FILTER tag, and is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE = index.md
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# entity all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see https://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
+# clang parser (see:
+# http://clang.llvm.org/) for more accurate parsing at the cost of reduced
+# performance. This can be particularly helpful with template rich C++ code for
+# which doxygen's built-in parser lacks the necessary type information.
+# Note: The availability of this option depends on whether or not doxygen was
+# generated with the -Duse_libclang=ON option for CMake.
+# The default value is: NO.
+
+CLANG_ASSISTED_PARSING = NO
+
+# If clang assisted parsing is enabled and the CLANG_ADD_INC_PATHS tag is set to
+# YES then doxygen will add the directory of each input to the include path.
+# The default value is: YES.
+
+CLANG_ADD_INC_PATHS = YES
+
+# If clang assisted parsing is enabled you can provide the compiler with command
+# line options that you would normally use when invoking the compiler. Note that
+# the include paths will already be set by doxygen for the files and directories
+# specified with INPUT and INCLUDE_PATH.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_OPTIONS =
+
+# If clang assisted parsing is enabled you can provide the clang parser with the
+# path to the directory containing a file called compile_commands.json. This
+# file is the compilation database (see:
+# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the
+# options used when the source files were built. This is equivalent to
+# specifying the -p option to a clang tool, such as clang-check. These options
+# will then be passed to the parser. Any options specified with CLANG_OPTIONS
+# will be added as well.
+# Note: The availability of this option depends on whether or not doxygen was
+# generated with the -Duse_libclang=ON option for CMake.
+
+CLANG_DATABASE_PATH =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = YES
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# https://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to YES can help to show when doxygen was last run and thus if the
+# documentation is up to date.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = NO
+
+# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
+# documentation will contain a main index with vertical navigation menus that
+# are dynamically created via JavaScript. If disabled, the navigation index will
+# consists of multiple levels of tabs that are statically embedded in every HTML
+# page. Disable this option to support browsers that do not have JavaScript,
+# like the Qt help browser.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_MENUS = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see:
+# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To
+# create a documentation set, doxygen will generate a Makefile in the HTML
+# output directory. Running make will produce the docset in that directory and
+# running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy
+# genXcode/_index.html for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see:
+# https://www.microsoft.com/en-us/download/details.aspx?id=21138) on Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the main .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location (absolute path
+# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to
+# run qhelpgenerator on the generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = YES
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg
+# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see
+# https://inkscape.org) to generate formulas as SVG images instead of PNGs for
+# the HTML output. These images will generally look nicer at scaled resolutions.
+# Possible values are: png (the default) and svg (looks nicer but requires the
+# pdf2svg or inkscape tool).
+# The default value is: png.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FORMULA_FORMAT = png
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANSPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands
+# to create new LaTeX commands to be used in formulas as building blocks. See
+# the section "Including formulas" for details.
+
+FORMULA_MACROFILE =
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# https://www.mathjax.org) which uses client side JavaScript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from https://www.mathjax.org before deployment.
+# The default value is: https://cdn.jsdelivr.net/npm/mathjax@2.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = https://cdn.jsdelivr.net/npm/mathjax@2
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see:
+# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use + S
+# (what the is depends on the OS and browser, but it is typically
+# , /, or both). Inside the search box use the to jump into the search results window, the results can be navigated
+# using the . Press to select an item or to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing +. Also here use the
+# to select a filter and or to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using JavaScript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see:
+# https://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see:
+# https://xapian.org/). See the section "External Indexing and Searching" for
+# details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when not enabling USE_PDFLATEX the default is latex when enabling
+# USE_PDFLATEX the default is pdflatex and when in the later case latex is
+# chosen this is overwritten by pdflatex. For specific output languages the
+# default can have been set differently, this depends on the implementation of
+# the output language.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME =
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# Note: This tag is used in the Makefile / make.bat.
+# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file
+# (.tex).
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to
+# generate index for LaTeX. In case there is no backslash (\) as first character
+# it will be automatically added in the LaTeX code.
+# Note: This tag is used in the generated output file (.tex).
+# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat.
+# The default value is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_MAKEINDEX_CMD = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. The package can be specified just
+# by its name or with the correct syntax as to be used with the LaTeX
+# \usepackage command. To get the times font for instance you can specify :
+# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
+# To use the option intlimits with the amsmath package you can specify:
+# EXTRA_PACKAGES=[intlimits]{amsmath}
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as
+# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX
+# files. Set this option to YES, to get a higher quality PDF documentation.
+#
+# See also section LATEX_CMD_NAME for selecting the engine.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# https://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_TIMESTAMP = NO
+
+# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
+# path from which the emoji images will be read. If a relative path is entered,
+# it will be relative to the LATEX_OUTPUT directory. If left blank the
+# LATEX_OUTPUT directory will be used.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EMOJI_DIRECTORY =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# configuration file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's configuration file. A template extensions file can be
+# generated using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = NO
+
+# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include
+# namespace members in file scope as well, matching the HTML output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_NS_MEMB_FILE_SCOPE = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures
+# the structure of the code including all documentation. Note that this feature
+# is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to Sqlite3 output
+#---------------------------------------------------------------------------
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED = _DOXYGEN_ \
+ CONFIG_BT_ENABLED \
+ CONFIG_BT_NIMBLE_ROLE_CENTRAL \
+ CONFIG_BT_NIMBLE_ROLE_OBSERVER \
+ CONFIG_BT_NIMBLE_ROLE_PERIPHERAL \
+ CONFIG_BT_NIMBLE_ROLE_BROADCASTER
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS = NO
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag UML_LOOK is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and
+# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS
+# tag is set to YES, doxygen will add type and arguments for attributes and
+# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen
+# will not generate fields with class member information in the UML graphs. The
+# class diagrams will look similar to the default class diagrams but using UML
+# notation for the relationships.
+# Possible values are: NO, YES and NONE.
+# The default value is: NO.
+# This tag requires that the tag UML_LOOK is set to YES.
+
+DOT_UML_DETAILS = NO
+
+# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters
+# to display on a single line. If the actual line length exceeds this threshold
+# significantly it will wrapped across multiple lines. Some heuristics are apply
+# to avoid ugly line breaks.
+# Minimum value: 0, maximum value: 1000, default value: 17.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_WRAP_THRESHOLD = 17
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command. Disabling a call graph can be
+# accomplished by means of the command \hidecallgraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command. Disabling a caller graph can be
+# accomplished by means of the command \hidecallergraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. For an explanation of the image formats see the section
+# output formats in the documentation of the dot tool (Graphviz (see:
+# http://www.graphviz.org/)).
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,
+# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
+# png:gdiplus:gdiplus.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+
+PLANTUML_JAR_PATH =
+
+# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a
+# configuration file for plantuml.
+
+PLANTUML_CFG_FILE =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate
+# files that are used to generate the various graphs.
+#
+# Note: This setting is not only used for dot files but also for msc and
+# plantuml temporary files.
+# The default value is: YES.
+
+DOT_CLEANUP = YES
diff --git a/src/components/esp-nimble-cpp-1.3.3/docs/Improvements_and_updates.md b/src/components/esp-nimble-cpp-1.3.3/docs/Improvements_and_updates.md
new file mode 100644
index 0000000..c3c1126
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/docs/Improvements_and_updates.md
@@ -0,0 +1,148 @@
+# Improvements and updates
+
+Many improvements have been made to this library vs the original, this is a brief overview of the most significant changes.
+Refer to the [class documentation](https://h2zero.github.io/esp-nimble-cpp/annotated.html) for futher information on class specifics.
+
+* [Server](#server)
+* [Advertising](#advertising)
+* [Client](#client)
+* [General](#general)
+
+
+
+# Server
+
+`NimBLECharacteristic::setValue(const T &s)`
+`NimBLEDescriptor::setValue(const T &s)`
+
+Now use a template to accomodate standard and custom types/values.
+
+**Example**
+```
+struct my_struct{
+ uint8_t one;
+ uint16_t two;
+ uint32_t four;
+ uint64_t eight;
+ float flt;
+}myStruct;
+
+ myStruct.one = 1;
+ myStruct.two = 2;
+ myStruct.four = 4;
+ myStruct.eight = 8;
+ myStruct.flt = 1234.56;
+
+ pCharacteristic->setValue(myStruct);
+ ```
+This will send the struct to the recieving client when read or a notification sent.
+
+`NimBLECharacteristic::getValue` now takes an optional timestamp parameter which will update it's value with
+the time the last value was recieved. In addition an overloaded template has been added to retrieve the value
+as a type specified by the user.
+
+**Example**
+```
+ time_t timestamp;
+ myStruct = pCharacteristic->getValue(×tamp); // timestamp optional
+```
+
+
+**Advertising will automatically start when a client disconnects.**
+
+A new method `NimBLEServer::advertiseOnDisconnect(bool)` has been implemented to control this, true(default) = enabled.
+
+
+`NimBLEServer::removeService` takes an additional parameter `bool deleteSvc` that if true will delete the service
+and all characteristics / descriptors belonging to it and invalidating any pointers to them.
+
+If false the service is only removed from visibility by clients. The pointers to the service and
+it's characteristics / descriptors will remain valid and the service can be re-added in the future
+using `NimBLEServer::addService`.
+
+
+
+# Advertising
+`NimBLEAdvertising::start`
+
+Now takes 2 optional parameters, the first is the duration to advertise for (in seconds), the second is a callback
+that is invoked when advertsing ends and takes a pointer to a `NimBLEAdvertising` object (similar to the `NimBLEScan::start` API).
+
+This provides an opportunity to update the advertisment data if desired.
+
+Also now returns a bool value to indicate if advertising successfully started or not.
+
+
+
+# Client
+
+`NimBLERemoteCharacteristic::readValue(time_t\*, bool)`
+`NimBLERemoteDescriptor::readValue(bool)`
+
+Have been added as templates to allow reading the values as any specified type.
+
+**Example**
+```
+struct my_struct{
+ uint8_t one;
+ uint16_t two;
+ uint32_t four;
+ uint64_t eight;
+ float flt;
+}myStruct;
+
+ time_t timestamp;
+ myStruct = pRemoteCharacteristic->readValue(×tamp); // timestamp optional
+```
+
+
+`NimBLERemoteCharacteristic::registerForNotify`
+Has been **deprecated** as now the internally stored characteristic value is updated when notification/indication is recieved.
+
+`NimBLERemoteCharacteristic::subscribe` and `NimBLERemoteCharacteristic::unsubscribe` have been implemented to replace it.
+A callback is no longer requred to get the most recent value unless timing is important. Instead, the application can call `NimBLERemoteCharacteristic::getValue` to
+get the last updated value any time.
+
+
+The `notifiy_callback` function is now defined as a `std::function` to take advantage of using `std::bind` to specifiy a class member function for the callback.
+
+Example:
+```
+using namespace std::placeholders;
+notify_callback callback = std::bind(&::, this, _1, _2, _3, _4);
+->subscribe(true, callback);
+```
+
+`NimBLERemoteCharacteristic::readValue` and `NimBLERemoteCharacteristic::getValue` take an optional timestamp parameter which will update it's value with
+the time the last value was recieved.
+
+> NimBLEClient::getService
+> NimBLERemoteService::getCharacteristic
+> NimBLERemoteCharacteristic::getDescriptor
+
+These methods will now check the respective vectors for the attribute object and, if not found, will retrieve (only)
+the specified attribute from the peripheral.
+
+These changes allow more control for the user to manage the resources used for the attributes.
+
+
+`NimBLEClient::connect()` can now be called without an address or advertised device parameter. This will connect to the
+device with the address previously set when last connected or set with `NimBLEDevice::setPeerAddress()`.
+
+
+# General
+To reduce resource use all instances of `std::map` have been replaced with `std::vector`.
+
+Use of `FreeRTOS::Semaphore` has been removed as it was consuming too much ram, the related files have been left in place to accomodate application use.
+
+Operators `==`, `!=` and `std::string` have been added to `NimBLEAddress` and `NimBLEUUID` for easier comparison and logging.
+
+New constructor for `NimBLEUUID(uint32_t, uint16_t, uint16_t, uint64_t)` added to lower memory use vs string construction. See: [#21](https://github.com/h2zero/NimBLE-Arduino/pull/21).
+
+Security/pairing operations are now handled in the respective `NimBLEClientCallbacks` and `NimBLEServerCallbacks` classes, `NimBLESecurity`(deprecated) remains for backward compatibility.
+
+Configuration options have been added to add or remove debugging information, when disabled (default) significatly reduces binary size.
+In ESP-IDF the options are in menuconfig: `Main menu -> ESP-NimBLE-cpp configuration`.
+For Arduino the options must be commented / uncommented in nimconfig.h.
+
+
diff --git a/src/components/esp-nimble-cpp-1.3.3/docs/Migration_guide.md b/src/components/esp-nimble-cpp-1.3.3/docs/Migration_guide.md
new file mode 100644
index 0000000..62406c6
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/docs/Migration_guide.md
@@ -0,0 +1,399 @@
+# Migrating from Bluedroid to NimBLE
+
+This guide describes the required changes to existing projects migrating from the original bluedroid API to NimBLE.
+
+**The changes listed here are only the required changes that must be made**, and a short overview of options for migrating existing applications.
+
+For more information on the improvements and additions please refer to the [class documentation](https://h2zero.github.io/esp-nimble-cpp/annotated.html) and [Improvements and updates](Improvements_and_updates.md)
+
+* [General Changes](#general-information)
+* [Server](#server-api)
+ * [Services](#services)
+ * [characteristics](#characteristics)
+ * [descriptors](#descriptors)
+ * [Security](#server-security)
+* [Advertising](#advertising-api)
+* [Client](#client-api)
+ * [Remote Services](#remote-services)
+ * [Remote characteristics](#remote-characteristics)
+ * [Security](#client-security)
+* [General Security](#security-api)
+* [Configuration](#arduino-configuration)
+
+
+
+## General Information
+
+### Header Files
+All classes are accessible by including `NimBLEDevice.h` in your application, no further headers need to be included.
+
+(Mainly for Arduino) You may choose to include `NimBLELog.h` in your appplication if you want to use the `NIMBLE_LOGx` macros for debugging.
+These macros are used the same way as the `ESP_LOGx` macros.
+
+
+### Class Names
+Class names remain the same as the original with the addition of a "Nim" prefix.
+For example `BLEDevice` is now `NimBLEDevice` and `BLEServer` is now `NimBLEServer` etc.
+
+For convienience definitions have been added to allow applications to use either name for all classes
+this means **no class names need to be changed in existing code** and makes migrating easier.
+
+
+### BLE Addresses
+`BLEAddress` (`NimBLEAddress`) When constructing an address the constructor now takes an *(optional)* `uint8_t type` paramameter
+to specify the address type. Default is (0) Public static address.
+
+For example `BLEAddress addr(11:22:33:44:55:66, 1)` will create the address object with an address type of: 1 (Random).
+
+As this paramameter is optional no changes to existing code are needed, it is mentioned here for information.
+
+`BLEAddress::getNative` (`NimBLEAddress::getNative`) returns a uint8_t pointer to the native address byte array.
+In this library the address bytes are stored in reverse order from the original library. This is due to the way
+the NimBLE stack expects addresses to be presented to it. All other functions such as `toString` are
+not affected as the endian change is made within them.
+
+
+
+## Server API
+Creating a `BLEServer` instance is the same as original, no changes required.
+For example `BLEDevice::createServer()` will work just as it did before.
+
+`BLEServerCallbacks` (`NimBLEServerCallbacks`) has new methods for handling security operations.
+**Note:** All callback methods have default implementations which allows the application to implement only the methods applicable.
+
+
+
+### Services
+Creating a `BLEService` (`NimBLEService`) instance is the same as original, no changes required.
+For example `BLEServer::createService(SERVICE_UUID)` will work just as it did before.
+
+
+### Characteristics
+`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`.
+
+#### Originally
+> BLECharacteristic::PROPERTY_READ |
+> BLECharacteristic::PROPERTY_WRITE
+
+#### Is Now
+> NIMBLE_PROPERTY::READ |
+> NIMBLE_PROPERTY::WRITE
+
+
+#### The full list of properties
+> NIMBLE_PROPERTY::READ
+> NIMBLE_PROPERTY::READ_ENC
+> NIMBLE_PROPERTY::READ_AUTHEN
+> NIMBLE_PROPERTY::READ_AUTHOR
+> NIMBLE_PROPERTY::WRITE
+> NIMBLE_PROPERTY::WRITE_NR
+> NIMBLE_PROPERTY::WRITE_ENC
+> NIMBLE_PROPERTY::WRITE_AUTHEN
+> NIMBLE_PROPERTY::WRITE_AUTHOR
+> NIMBLE_PROPERTY::BROADCAST
+> NIMBLE_PROPERTY::NOTIFY
+> NIMBLE_PROPERTY::INDICATE
+
+
+**Example:**
+```
+BLECharacteristic *pCharacteristic = pService->createCharacteristic(
+ CHARACTERISTIC_UUID,
+ BLECharacteristic::PROPERTY_READ |
+ BLECharacteristic::PROPERTY_WRITE
+ );
+
+```
+Needs to be changed to:
+```
+BLECharacteristic *pCharacteristic = pService->createCharacteristic(
+ CHARACTERISTIC_UUID,
+ NIMBLE_PROPERTY::READ |
+ NIMBLE_PROPERTY::WRITE
+ );
+```
+
+
+`BLECharacteristicCallbacks` (`NimBLECharacteristicCallbacks`) has a new method `NimBLECharacteristicCallbacks::onSubscribe`
+which is called when a client subscribes to notifications/indications.
+
+**Note:** All callback methods have default implementations which allows the application to implement only the methods applicable.
+
+
+> BLECharacteristic::getData
+
+**Has been removed from the API.**
+Originally this returned a `uint8_t*` to the internal data, which is volatile.
+To prevent possibly throwing exceptions this has been removed and `NimBLECharacteristic::getValue` should be used
+to get a copy of the data first which can then safely be accessed via pointer.
+
+**Example:**
+```
+std::string value = pCharacteristic->getValue();
+uint8_t *pData = (uint8_t*)value.data();
+```
+Alternatively use the `getValue` template:
+```
+my_struct_t myStruct = pChr->getValue();
+```
+
+
+
+### Descriptors
+The previous method `BLECharacteristic::addDescriptor()` has been removed.
+
+Descriptors are now created using the `NimBLECharacteristic::createDescriptor` method.
+
+BLE2902 or NimBLE2902 class has been removed.
+NimBLE automatically creates the 0x2902 descriptor if a characteristic has a notification or indication property assigned to it.
+
+It was no longer useful to have a class for the 0x2902 descriptor as a new callback `NimBLECharacteristicCallbacks::onSubscribe` was added
+to handle callback functionality and the client subscription status is handled internally.
+
+**Note:** Attempting to create a 0x2902 descriptor will trigger an assert to notify the error,
+allowing the creation of it would cause a fault in the NimBLE stack.
+
+All other descriptors are now created just as characteristics are by using the `NimBLECharacteristic::createDescriptor` method (except 0x2904, see below).
+Which are defined as:
+```
+NimBLEDescriptor* createDescriptor(const char* uuid,
+ uint32_t properties =
+ NIMBLE_PROPERTY::READ |
+ NIMBLE_PROPERTY::WRITE,
+ uint16_t max_len = 100);
+
+NimBLEDescriptor* createDescriptor(NimBLEUUID uuid,
+ uint32_t properties =
+ NIMBLE_PROPERTY::READ |
+ NIMBLE_PROPERTY::WRITE,
+ uint16_t max_len = 100);
+```
+##### Example
+```
+pDescriptor = pCharacteristic->createDescriptor("ABCD",
+ NIMBLE_PROPERTY::READ |
+ NIMBLE_PROPERTY::WRITE |
+ NIMBLE_PROPERTY::WRITE_ENC,
+ 25);
+```
+Would create a descriptor with the UUID 0xABCD, publicly readable but only writable if paired/bonded (encrypted) and has a max value length of 25 bytes.
+
+
+For the 0x2904, there is a special class that is created when you call `createDescriptor("2904").
+
+The pointer returned is of the base class `NimBLEDescriptor` but the call will create the derived class of `NimBLE2904` so you must cast the returned pointer to
+`NimBLE2904` to access the specific class methods.
+
+##### Example
+```
+p2904 = (NimBLE2904*)pCharacteristic->createDescriptor("2904");
+```
+
+
+
+### Server Security
+Security is set on the characteristic or descriptor properties by applying one of the following:
+> NIMBLE_PROPERTY::READ_ENC
+> NIMBLE_PROPERTY::READ_AUTHEN
+> NIMBLE_PROPERTY::READ_AUTHOR
+> NIMBLE_PROPERTY::WRITE_ENC
+> NIMBLE_PROPERTY::WRITE_AUTHEN
+> NIMBLE_PROPERTY::WRITE_AUTHOR
+
+When a peer wants to read or write a characteristic or descriptor with any of these properties applied
+it will trigger the pairing process. By default the "just-works" pairing will be performed automatically.
+This can be changed to use passkey authentication or numeric comparison. See [Security API](#security-api) for details.
+
+
+
+## Advertising API
+Advertising works the same as the original API except:
+> BLEAdvertising::setMinPreferred
+> BLEAdvertising::setMaxPreferred
+
+These methods were found to not provide useful functionality and consumed valuable advertising space (6 bytes of 31) if used unknowingly.
+If you wish to advertise these parameters you can still do so manually via `BLEAdvertisementData::addData` (`NimBLEAdvertisementData::addData`).
+
+
+Calling `NimBLEAdvertising::setAdvertisementData` will entirely replace any data set with `NimBLEAdvertising::addServiceUUID`, or
+`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.~~
+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)
+
+Now takes 2 optional parameters, the first is the duration to advertise for (in seconds), the second is a callback
+that is invoked when advertsing ends and takes a pointer to a `NimBLEAdvertising` object (similar to the `NimBLEScan::start` API).
+
+This provides an opportunity to update the advertisment data if desired.
+
+
+
+## Client API
+
+Client instances are created just as before with `BLEDevice::createClient` (`NimBLEDevice::createClient`).
+
+Multiple client instances can be created, up to the maximum number of connections set in the config file (default: 3).
+To delete a client instance you must use `NimBLEDevice::deleteClient`.
+
+`BLEClient::connect`(`NimBLEClient::connect`) Has had it's parameters altered.
+Defined as:
+> NimBLEClient::connect(bool deleteServices = true);
+> NimBLEClient::connect(NimBLEAdvertisedDevice\* device, bool deleteServices = true);
+> NimBLEClient::connect(NimBLEAddress address, bool deleteServices = true);
+
+The type parameter has been removed and a new bool parameter has been added to indicate if the client should
+delete the attribute database previously retrieved (if applicable) for the peripheral, default value is true.
+If set to false the client will use the attribute database it retrieved from the peripheral when previously connected.
+This allows for faster connections and power saving if the devices dropped connection and are reconnecting.
+
+
+> `BLEClient::getServices` (`NimBLEClient::getServices`)
+
+This method now takes an optional (bool) parameter to indicate if the services should be retrieved from the server (true) or
+the currently known database returned (false : default).
+Also now returns a pointer to `std::vector` instead of `std::map`.
+
+
+**Removed:** the automatic discovery of all peripheral attributes as they consumed time and resources for data
+the user may not be interested in.
+
+**Added:** `NimBLEClient::discoverAttributes` for the user to discover all the peripheral attributes
+to replace the the removed automatic functionality.
+
+
+
+### Remote Services
+`BLERemoteService` (`NimBLERemoteService`) Methods remain mostly unchanged with the exceptions of:
+
+> BLERemoteService::getCharacteristicsByHandle
+
+This method has been removed.
+
+
+> `BLERemoteService::getCharacteristics` (`NimBLERemoteService::getCharacteristics`)
+
+This method now takes an optional (bool) parameter to indicate if the characteristics should be retrieved from the server (true) or
+the currently known database returned (false : default).
+Also now returns a pointer to `std::vector` instead of `std::map`.
+
+
+
+### Remote Characteristics
+`BLERemoteCharacteristic` (`NimBLERemoteCharacteristic`) There have been a few changes to the methods in this class:
+
+> `BLERemoteCharacteristic::writeValue` (`NimBLERemoteCharacteristic::writeValue`)
+> `BLERemoteCharacteristic::registerForNotify` (`NimBLERemoteCharacteristic::registerForNotify`)
+
+Now return true or false to indicate success or failure so you can choose to disconnect or try again.
+
+
+> `BLERemoteCharacteristic::registerForNotify` (`NimBLERemoteCharacteristic::registerForNotify`)
+
+Is now **deprecated**.
+> `NimBLERemoteCharacteristic::subscribe`
+> `NimBLERemoteCharacteristic::unsubscribe`
+
+Are the new methods added to replace it.
+
+
+> `BLERemoteCharacteristic::readUInt8` (`NimBLERemoteCharacteristic::readUInt8`)
+> `BLERemoteCharacteristic::readUInt16` (`NimBLERemoteCharacteristic::readUInt16`)
+> `BLERemoteCharacteristic::readUInt32` (`NimBLERemoteCharacteristic::readUInt32`)
+> `BLERemoteCharacteristic::readFloat` (`NimBLERemoteCharacteristic::readFloat`)
+
+Are **deprecated** a template: NimBLERemoteCharacteristic::readValue(time_t\*, bool) has been added to replace them.
+
+
+> `BLERemoteCharacteristic::readRawData`
+
+**Has been removed from the API**
+Originally it stored an unnecessary copy of the data and was returning a `uint8_t` pointer to volatile internal data.
+The user application should use `NimBLERemoteCharacteristic::readValue` or `NimBLERemoteCharacteristic::getValue`.
+To obatain a copy of the data, then cast the returned std::string to the type required such as:
+```
+std::string value = pChr->readValue();
+uint8_t *data = (uint8_t*)value.data();
+```
+Alternatively use the `readValue` template:
+```
+my_struct_t myStruct = pChr->readValue();
+```
+
+
+> `BLERemoteCharacteristic::getDescriptors` (`NimBLERemoteCharacteristic::getDescriptors`)
+
+This method now takes an optional (bool) parameter to indicate if the descriptors should be retrieved from the server (true) or
+the currently known database returned (false : default).
+Also now returns a pointer to `std::vector` instead of `std::map`.
+
+
+
+### Client Security
+The client will automatically initiate security when the peripheral responds that it's required.
+The default configuration will use "just-works" pairing with no bonding, if you wish to enable bonding see below.
+
+
+
+## Security API
+Security operations have been moved to `BLEDevice` (`NimBLEDevice`).
+
+Also security callback methods are now incorporated in the `NimBLEServerCallbacks` / `NimBLEClientCallbacks` classes.
+However backward compatibility with the original `BLESecurity` (`NimBLESecurity`) class is retained to minimize application code changes.
+
+The callback methods are:
+
+> `bool onConfirmPIN(uint32_t pin)`
+
+Receives the pin when using numeric comparison authentication, `return true;` to accept.
+
+
+> `uint32_t onPassKeyRequest()`
+
+For server callback; return the passkey expected from the client.
+For client callback; return the passkey to send to the server.
+
+
+> `void onAuthenticationComplete(ble_gap_conn_desc\* desc)`
+
+Authentication complete, success or failed information is in `desc`.
+
+
+Security settings and IO capabilities are now set by the following methods of NimBLEDevice.
+> `NimBLEDevice::setSecurityAuth(bool bonding, bool mitm, bool sc)`
+> `NimBLEDevice::setSecurityAuth(uint8_t auth_req)`
+
+Sets the authorization mode for this device.
+
+
+> `NimBLEDevice::setSecurityIOCap(uint8_t iocap)`
+
+Sets the Input/Output capabilities of this device.
+
+
+> `NimBLEDevice::setSecurityInitKey(uint8_t init_key)`
+
+If we are the initiator of the security procedure this sets the keys we will distribute.
+
+
+> `NimBLEDevice::setSecurityRespKey(uint8_t resp_key)`
+
+Sets the keys we are willing to accept from the peer during pairing.
+
+
+
+## Arduino Configuration
+
+Unlike the original library pre-packaged in the esp32-arduino, this library has all the configuration
+options that are normally set in menuconfig available in the *src/nimconfig.h* file.
+
+This allows Arduino users to fully customize the build, such as increasing max connections
+or loading the BLE stack into external PSRAM.
+
+For details on the options, they are fully commented in *nimconfig.h*
+
diff --git a/src/components/esp-nimble-cpp-1.3.3/docs/New_user_guide.md b/src/components/esp-nimble-cpp-1.3.3/docs/New_user_guide.md
new file mode 100644
index 0000000..9f0eeee
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/docs/New_user_guide.md
@@ -0,0 +1,339 @@
+# New User Guide
+
+**Note:** If you are migrating an existing project from the original Bluedroid library please see the [Migration Guide.](Migration_guide.md)
+
+If you are a new user this will guide you through a simple server and client application.
+
+* [Creating a Server](#creating-a-server)
+* [Creating a Client](#creating-a-client)
+
+
+## Include Files
+At the top of your application file add `#include NimBLEDevice.h`, this is the only header required and provides access to all classes.
+
+
+## Using the Library
+In order to perform any BLE tasks you must first initialize the library, this prepares the NimBLE stack to be ready for commands.
+
+To do this you must call `NimBLEDevice::init("your device name here")`, the parameter passed is a character string containing the name you want to advertise.
+If you're not creating a server or do not want to advertise a name, simply pass an empty string for the parameter.
+
+This can be called any time you wish to use BLE functions and does not need to be called from app_main(IDF) or setup(Arduino) but usually is.
+
+
+
+## Creating a Server
+BLE servers perform 2 tasks, they advertise their existance for clients to find them and they provide services which contain information for the connecting client.
+
+After initializing the NimBLE stack we create a server by calling `NimBLEDevice::createServer()`, this will create a server instance and return a pointer to it.
+
+Once we have created the server we need to tell it the services it hosts.
+To do this we call `NimBLEServer::createService(const char* uuid)`. Which returns a pointer to an instance of `NimBLEService`.
+The `uuid` parameter is a hexadecimal string with the uuid we want to give the service, it can be 16, 32, or 128 bits.
+
+For this example we will keep it simple and use a 16 bit value: ABCD.
+
+
+**Example code:**
+```
+#include "NimBLEDevice.h"
+
+// void setup() in Arduino
+void app_main(void)
+{
+ NimBLEDevice::init("NimBLE");
+
+ NimBLEServer *pServer = NimBLEDevice::createServer();
+ NimBLEService *pService = pServer->createService("ABCD");
+}
+```
+
+Now we have NimBLE initialized, a server created and a service assigned to it.
+We can't do much with this yet so now we should add a characteristic to the service to provide some data.
+
+Next we call `NimBLEService::createCharacteristic` which returns a pointer to an instance of `NimBLECharacteristic`, and takes two parameters:
+A `uuid` to specify the UUID of the characteristic and a bitmask of the properties we want applied to it.
+
+Just as with the service UUID we will use a simple 16 bit value: 1234.
+The properties bitmask is a little more involved. It is a combination of NIMBLE_PROPERTY:: values.
+
+Here is the list of options:
+> NIMBLE_PROPERTY\::READ
+> NIMBLE_PROPERTY\::READ_ENC
+> NIMBLE_PROPERTY\::READ_AUTHEN
+> NIMBLE_PROPERTY\::READ_AUTHOR
+> NIMBLE_PROPERTY\::WRITE
+> NIMBLE_PROPERTY\::WRITE_NR
+> NIMBLE_PROPERTY\::WRITE_ENC
+> NIMBLE_PROPERTY\::WRITE_AUTHEN
+> NIMBLE_PROPERTY\::WRITE_AUTHOR
+> NIMBLE_PROPERTY\::BROADCAST
+> NIMBLE_PROPERTY\::NOTIFY
+> NIMBLE_PROPERTY\::INDICATE
+
+For this example we won't need to specify these as the default value is `NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE`
+which will allow reading and writing values to the characteristic without encryption or security.
+The function call will simply be `pService->createCharacteristic("1234");`
+
+
+**Our example code now is:**
+```
+#include "NimBLEDevice.h"
+
+// void setup() in Arduino
+void app_main(void)
+{
+ NimBLEDevice::init("NimBLE");
+
+ NimBLEServer *pServer = NimBLEDevice::createServer();
+ NimBLEService *pService = pServer->createService("ABCD");
+ NimBLECharacteristic *pCharacteristic = pService->createCharacteristic("1234");
+}
+```
+
+All that's left to do now is start the sevice, give the characteristic a value and start advertising for clients.
+
+Fist we start the service by calling `NimBLEService::start()`.
+
+Next we need to call `NimBLECharacteristic::setValue` to set the characteristic value that the client will read.
+There are many different types you can send as parameters for the value but for this example we will use a simple string.
+`pCharacteristic->setValue("Hello BLE");`
+
+Next we need to advertise for connections.
+To do this we create an instance of `NimBLEAdvertising` add our service to it (optional) and start advertisng.
+
+**The code for this will be:**
+```
+NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising(); // create advertising instance
+pAdvertising->addServiceUUID("ABCD"); // tell advertising the UUID of our service
+pAdvertising->start(); // start advertising
+```
+That's it, this will be enough to create a BLE server with a service and a characteristic and advertise for client connections.
+
+**The full example code:**
+```
+#include "NimBLEDevice.h"
+
+// void setup() in Arduino
+void app_main(void)
+{
+ NimBLEDevice::init("NimBLE");
+
+ NimBLEServer *pServer = NimBLEDevice::createServer();
+ NimBLEService *pService = pServer->createService("ABCD");
+ NimBLECharacteristic *pCharacteristic = pService->createCharacteristic("1234");
+
+ pService->start();
+ pCharacteristic->setValue("Hello BLE");
+
+ NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
+ pAdvertising->addServiceUUID("ABCD");
+ pAdvertising->start();
+}
+```
+
+Now if you scan with your phone using nRFConnect or any other BLE app you should see a device named "NimBLE" with a service of "ABCD".
+
+For more advanced features and options please see the server examples in the examples folder.
+
+
+
+## Creating a Client
+
+BLE clients perform 2 tasks, they scan for advertising servers and form connections to them to read and write to their characteristics/descriptors.
+
+After initializing the NimBLE stack we create a scan instance by calling `NimBLEDevice::getScan()`, this will create a `NimBLEScan` instance and return a pointer to it.
+
+Once we have created the scan we can start looking for advertising servers.
+
+To do this we call `NimBLEScan::start(duration)`, the duration parameter is a uint32_t that specifies the number of seconds to scan for,
+passing 0 will scan forever.
+
+In this example we will scan for 10 seconds. This is a blocking function (a non blocking overload is also available).
+This call returns an instance of `NimBLEScanResults` when the scan completes which can be parsed for advertisers we are interested in.
+
+**Example Code:**
+```
+#include "NimBLEDevice.h"
+
+// void setup() in Arduino
+void app_main(void)
+{
+ NimBLEDevice::init("");
+
+ NimBLEScan *pScan = NimBLEDevice::getScan();
+ NimBLEScanResults results = pScan->start(10);
+}
+```
+
+
+Now that we have scanned we need to check the results for any advertisers we are interested in connecting to.
+
+To do this we iterate through the results and check if any of the devices found are advertising the service we want `ABCD`.
+Each result in `NimBLEScanResults` is a `NimBLEAdvertisedDevice` instance that we can access data from.
+
+We will check each device found for the `ABCD` service by calling `NimBLEAdvertisedDevice::isAdvertisingService`.
+This takes an instance of `NimBLEUUID` as a parameter so we will need to create one.
+
+**The code for this looks like:**
+```
+NimBLEUUID serviceUuid("ABCD");
+
+for(int i = 0; i < results.getCount(); i++) {
+ NimBLEAdvertisedDevice device = results.getDevice(i);
+
+ if (device.isAdvertisingService(serviceUuid)) {
+ // create a client and connect
+ }
+}
+```
+
+
+Now that we can scan and parse advertisers we need to be able to create a `NimBLEClient` instance and use it to connect.
+
+To do this we call `NimBLEDevice::createClient` which creates the `NimBLEClient` instance and returns a pointer to it.
+
+After this we call `NimBLEClient::connect` to connect to the advertiser.
+This takes a pointer to the `NimBLEAdvertisedDevice` and returns `true` if successful.
+
+**Lets do that now:**
+```
+NimBLEUUID serviceUuid("ABCD");
+
+for(int i = 0; i < results.getCount(); i++) {
+ NimBLEAdvertisedDevice device = results.getDevice(i);
+
+ if (device.isAdvertisingService(serviceUuid)) {
+ NimBLEClient *pClient = NimBLEDevice::createClient();
+
+ if(pClient->connect(&device)) {
+ //success
+ } else {
+ // failed to connect
+ }
+ }
+}
+```
+As shown, the call to `NimBLEClient::connect` should have it's eturn value tested to make sure it succeeded before proceeding to get data.
+
+
+Next we need to access the servers data by asking it for the service and the characteristic we are interested in, then read the characteristic value.
+
+To do this we call `NimBLEClient::getService`, which takes as a parameter the UUID of the service and returns
+a pointer an instance to `NimBLERemoteService` or `nullptr` if the service was not found.
+
+Next we will call `NimBLERemoteService::getCharateristic` which takes as a parameter the UUID of the service and returns
+a pointer to an instance of `NimBLERemoteCharacteristic` or `nullptr` if not found.
+
+Finally we will read the characteristic value with `NimBLERemoteCharacteristic::readValue()`.
+
+**Here is what that looks like:**
+```
+NimBLEUUID serviceUuid("ABCD");
+
+for(int i = 0; i < results.getCount(); i++) {
+ NimBLEAdvertisedDevice device = results.getDevice(i);
+
+ if (device.isAdvertisingService(serviceUuid)) {
+ NimBLEClient *pClient = NimBLEDevice::createClient();
+
+ if (pClient->connect(&device)) {
+ NimBLERemoteService *pService = pClient->getService(serviceUuid);
+
+ if (pService != nullptr) {
+ NimBLERemoteCharacteristic *pCharacteristic = pService->getCharacteristic("1234");
+
+ if (pCharacteristic != nullptr) {
+ std::string value = pCharacteristic->readValue();
+ // print or do whatever you need with the value
+ }
+ }
+ } else {
+ // failed to connect
+ }
+ }
+}
+```
+
+
+The last thing we should do is clean up once we are done with the connection.
+Because multiple clients are supported and can be created we should delete them when finished with them to conserve resources.
+This is done by calling `NimBLEDevice::deleteClient`.
+
+**Lets add that now:**
+```
+NimBLEUUID serviceUuid("ABCD");
+
+for(int i = 0; i < results.getCount(); i++) {
+ NimBLEAdvertisedDevice device = results.getDevice(i);
+
+ if (device.isAdvertisingService(serviceUuid)) {
+ NimBLEClient *pClient = NimBLEDevice::createClient();
+
+ if (pClient->connect(&device)) {
+ NimBLERemoteService *pService = pClient->getService(serviceUuid);
+
+ if (pService != nullptr) {
+ NimBLERemoteCharacteristic *pCharacteristic = pService->getCharacteristic("1234");
+
+ if (pCharacteristic != nullptr) {
+ std::string value = pCharacteristic->readValue();
+ // print or do whatever you need with the value
+ }
+ }
+ } else {
+ // failed to connect
+ }
+
+ NimBLEDevice::deleteClient(pClient);
+ }
+}
+```
+Note that there is no need to disconnect as that will be done when deleting the client instance.
+
+
+**Here is the full example code:**
+```
+#include "NimBLEDevice.h"
+
+// void setup() in Arduino
+void app_main(void)
+{
+ NimBLEDevice::init("");
+
+ NimBLEScan *pScan = NimBLEDevice::getScan();
+ NimBLEScanResults results = pScan->start(10);
+
+ NimBLEUUID serviceUuid("ABCD");
+
+ for(int i = 0; i < results.getCount(); i++) {
+ NimBLEAdvertisedDevice device = results.getDevice(i);
+
+ if (device.isAdvertisingService(serviceUuid)) {
+ NimBLEClient *pClient = NimBLEDevice::createClient();
+
+ if (pClient->connect(&device)) {
+ NimBLERemoteService *pService = pClient->getService(serviceUuid);
+
+ if (pService != nullptr) {
+ NimBLERemoteCharacteristic *pCharacteristic = pService->getCharacteristic("1234");
+
+ if (pCharacteristic != nullptr) {
+ std::string value = pCharacteristic->readValue();
+ // print or do whatever you need with the value
+ }
+ }
+ } else {
+ // failed to connect
+ }
+
+ NimBLEDevice::deleteClient(pClient);
+ }
+ }
+}
+```
+
+
+For more advanced features and options please see the client examples in the examples folder.
+
+
diff --git a/src/components/esp-nimble-cpp-1.3.3/docs/Usage_tips.md b/src/components/esp-nimble-cpp-1.3.3/docs/Usage_tips.md
new file mode 100644
index 0000000..b8edde2
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/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/src/components/esp-nimble-cpp-1.3.3/docs/index.md b/src/components/esp-nimble-cpp-1.3.3/docs/index.md
new file mode 100644
index 0000000..bcf892b
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/docs/index.md
@@ -0,0 +1,85 @@
+# Overview
+
+This is a C++ BLE library for the ESP32 that uses the NimBLE host stack instead of bluedroid.
+The aim is to maintain, as much as reasonable, the original bluedroid C++ & Arduino BLE API by while adding new features
+and making improvements in performance, resource use, and stability.
+
+**Testing shows a nearly 50% reduction in flash use and approx. 100kB less ram consumed vs the original!**
+*Your results may vary*
+
+
+# What is NimBLE?
+NimBLE is a completely open source Bluetooth Low Energy stack produced by [Apache](https://github.com/apache/mynewt-nimble).
+It is more suited to resource constrained devices than bluedroid and has now been ported to the ESP32 by Espressif.
+
+
+# Arduino Installation
+**Arduino Library manager:** Go to `sketch` -> `Include Library` -> `Manage Libraries` and search for NimBLE and install.
+
+**Alternatively:** Download as .zip and extract to Arduino/libraries folder, or in Arduino IDE from Sketch menu -> Include library -> Add .Zip library.
+
+`#include "NimBLEDevice.h"` at the beginning of your sketch.
+
+Call `NimBLEDevice::init` in `setup`.
+
+Tested and working with esp32-arduino in Arduino IDE and platform IO.
+
+
+# ESP-IDF Installation
+### v4.0+
+Download as .zip and extract or clone into the components folder in your esp-idf project.
+
+Run menuconfig, go to `Component config->Bluetooth` enable Bluetooth and in `Bluetooth host` NimBLE.
+Configure settings in `NimBLE Options`.
+`#include "NimBLEDevice.h"` in main.cpp.
+Call `NimBLEDevice::init` in `app_main`.
+
+
+### v3.2 & v3.3
+The NimBLE component does not come with these versions of IDF (now included in 3.3.2 and above).
+A backport that works in these versions has been created and is [available here](https://github.com/h2zero/esp-nimble-component).
+Download or clone that repo into your project/components folder and run menuconfig.
+Configure settings in `main menu -> NimBLE Options`.
+
+`#include "NimBLEDevice.h"` in main.cpp.
+Call `NimBLEDevice::init` in `app_main`.
+
+
+# Using
+This library is intended to be compatible with the original ESP32 BLE functions and types with minor changes.
+
+If you have not used the original Bluedroid library please refer to the [New user guide](New_user_guide.md).
+
+If you are familiar with the original library, see: [The migration guide](Migration_guide.md) for details.
+
+Also see [Improvements and updates](Improvements_and_updates.md) for information about non-breaking changes.
+
+For more advanced usage see [Usage tips](Usage_tips.md) for more performance and optimization.
+
+
+### Arduino specific
+See the Refactored_original_examples in the examples folder for highlights of the differences with the original library.
+
+More advanced examples highlighting many available features are in examples/NimBLE_Server, NimBLE_Client.
+
+Beacon examples provided by [beegee-tokyo](https://github.com/beegee-tokyo) are in examples/BLE_Beacon_Scanner, BLE_EddystoneTLM_Beacon, BLE_EddystoneURL_Beacon.
+
+Change the settings in the nimconfig.h file to customize NimBLE to your project, such as increasing max connections (default is 3).
+
+
+### Arduino command line and platformio
+As an alternative to changing the configuration in nimconfig.h, Arduino command line and platformio.ini options are available.
+See the command line configuration options available in [Command line config](Command_line_config.md).
+
+
+# Need help? Have a question or suggestion?
+Come chat on [gitter](https://gitter.im/NimBLE-Arduino/community?utm_source=share-link&utm_medium=link&utm_campaign=share-link) or open an issue at [NimBLE-Arduino](https://github.com/h2zero/NimBLE-Arduino/issues) or [esp-nimble-cpp](https://github.com/h2zero/esp-nimble-cpp/issues)
+
+
+# Acknowledgments
+
+* [nkolban](https://github.com/nkolban) and [chegewara](https://github.com/chegewara) for the [original esp32 BLE library](https://github.com/nkolban/esp32-snippets/tree/master/cpp_utils) this project was derived from.
+* [beegee-tokyo](https://github.com/beegee-tokyo) for contributing your time to test/debug and contributing the beacon examples.
+* [Jeroen88](https://github.com/Jeroen88) for the amazing help debugging and improving the client code.
+
+
diff --git a/src/components/esp-nimble-cpp-1.3.3/examples/Advanced/NimBLE_Client/CMakeLists.txt b/src/components/esp-nimble-cpp-1.3.3/examples/Advanced/NimBLE_Client/CMakeLists.txt
new file mode 100644
index 0000000..7b68bed
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/examples/Advanced/NimBLE_Client/CMakeLists.txt
@@ -0,0 +1,7 @@
+# The following lines of boilerplate have to be in your project's
+# CMakeLists in this exact order for cmake to work correctly
+cmake_minimum_required(VERSION 3.5)
+
+include($ENV{IDF_PATH}/tools/cmake/project.cmake)
+set(SUPPORTED_TARGETS esp32)
+project(NimBLE_Client)
diff --git a/src/components/esp-nimble-cpp-1.3.3/examples/Advanced/NimBLE_Client/Makefile b/src/components/esp-nimble-cpp-1.3.3/examples/Advanced/NimBLE_Client/Makefile
new file mode 100644
index 0000000..d1a0fa2
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/examples/Advanced/NimBLE_Client/Makefile
@@ -0,0 +1,3 @@
+PROJECT_NAME := NimBLE_Client
+
+include $(IDF_PATH)/make/project.mk
diff --git a/src/components/esp-nimble-cpp-1.3.3/examples/Advanced/NimBLE_Client/main/CMakeLists.txt b/src/components/esp-nimble-cpp-1.3.3/examples/Advanced/NimBLE_Client/main/CMakeLists.txt
new file mode 100644
index 0000000..9be9075
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/examples/Advanced/NimBLE_Client/main/CMakeLists.txt
@@ -0,0 +1,4 @@
+set(COMPONENT_SRCS "main.cpp")
+set(COMPONENT_ADD_INCLUDEDIRS ".")
+
+register_component()
\ No newline at end of file
diff --git a/src/components/esp-nimble-cpp-1.3.3/examples/Advanced/NimBLE_Client/main/component.mk b/src/components/esp-nimble-cpp-1.3.3/examples/Advanced/NimBLE_Client/main/component.mk
new file mode 100644
index 0000000..a98f634
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/examples/Advanced/NimBLE_Client/main/component.mk
@@ -0,0 +1,4 @@
+#
+# "main" pseudo-component makefile.
+#
+# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
diff --git a/src/components/esp-nimble-cpp-1.3.3/examples/Advanced/NimBLE_Client/main/main.cpp b/src/components/esp-nimble-cpp-1.3.3/examples/Advanced/NimBLE_Client/main/main.cpp
new file mode 100644
index 0000000..1bf6ab1
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/examples/Advanced/NimBLE_Client/main/main.cpp
@@ -0,0 +1,372 @@
+
+/** NimBLE_Server Demo:
+ *
+ * Demonstrates many of the available features of the NimBLE client library.
+ *
+ * Created: on March 24 2020
+ * Author: H2zero
+ *
+*/
+#include
+
+extern "C" {void app_main(void);}
+
+void scanEndedCB(NimBLEScanResults results);
+
+static NimBLEAdvertisedDevice* advDevice;
+
+static bool doConnect = false;
+static uint32_t scanTime = 0; /** 0 = scan forever */
+
+
+/** None of these are required as they will be handled by the library with defaults. **
+ ** Remove as you see fit for your needs */
+class ClientCallbacks : public NimBLEClientCallbacks {
+ void onConnect(NimBLEClient* pClient) {
+ printf("Connected\n");
+ /** After connection we should change the parameters if we don't need fast response times.
+ * These settings are 150ms interval, 0 latency, 450ms timout.
+ * Timeout should be a multiple of the interval, minimum is 100ms.
+ * I find a multiple of 3-5 * the interval works best for quick response/reconnect.
+ * Min interval: 120 * 1.25ms = 150, Max interval: 120 * 1.25ms = 150, 0 latency, 45 * 10ms = 450ms timeout
+ */
+ pClient->updateConnParams(120,120,0,45);
+ };
+
+ void onDisconnect(NimBLEClient* pClient) {
+ printf("%s Disconnected - Starting scan\n", pClient->getPeerAddress().toString().c_str());
+ NimBLEDevice::getScan()->start(scanTime, scanEndedCB);
+ };
+
+ /********************* Security handled here **********************
+ ****** Note: these are the same return values as defaults ********/
+ uint32_t onPassKeyRequest(){
+ printf("Client Passkey Request\n");
+ /** return the passkey to send to the server */
+ return 123456;
+ };
+
+ bool onConfirmPIN(uint32_t pass_key){
+ printf("The passkey YES/NO number: %d\n", pass_key);
+ /** Return false if passkeys don't match. */
+ return true;
+ };
+
+ /** Pairing process complete, we can check the results in ble_gap_conn_desc */
+ void onAuthenticationComplete(ble_gap_conn_desc* desc){
+ if(!desc->sec_state.encrypted) {
+ printf("Encrypt connection failed - disconnecting\n");
+ /** Find the client with the connection handle provided in desc */
+ NimBLEDevice::getClientByID(desc->conn_handle)->disconnect();
+ return;
+ }
+ };
+};
+
+
+/** Define a class to handle the callbacks when advertisments are received */
+class AdvertisedDeviceCallbacks: public NimBLEAdvertisedDeviceCallbacks {
+
+ void onResult(NimBLEAdvertisedDevice* advertisedDevice) {
+ printf("Advertised Device found: %s\n", advertisedDevice->toString().c_str());
+ if(advertisedDevice->isAdvertisingService(NimBLEUUID("DEAD")))
+ {
+ printf("Found Our Service\n");
+ /** stop scan before connecting */
+ NimBLEDevice::getScan()->stop();
+ /** Save the device reference in a global for the client to use*/
+ advDevice = advertisedDevice;
+ /** Ready to connect now */
+ doConnect = true;
+ }
+ };
+};
+
+
+/** Notification / Indication receiving handler callback */
+void notifyCB(NimBLERemoteCharacteristic* pRemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify){
+ std::string str = (isNotify == true) ? "Notification" : "Indication";
+ str += " from ";
+ str += pRemoteCharacteristic->getRemoteService()->getClient()->getPeerAddress().toString();
+ str += ": Service = " + pRemoteCharacteristic->getRemoteService()->getUUID().toString();
+ str += ", Characteristic = " + pRemoteCharacteristic->getUUID().toString();
+ str += ", Value = " + std::string((char*)pData, length);
+ printf("%s\n", str.c_str());
+}
+
+/** Callback to process the results of the last scan or restart it */
+void scanEndedCB(NimBLEScanResults results){
+ printf("Scan Ended\n");
+}
+
+
+/** Create a single global instance of the callback class to be used by all clients */
+static ClientCallbacks clientCB;
+
+
+/** Handles the provisioning of clients and connects / interfaces with the server */
+bool connectToServer() {
+ NimBLEClient* pClient = nullptr;
+
+ /** Check if we have a client we should reuse first **/
+ if(NimBLEDevice::getClientListSize()) {
+ /** Special case when we already know this device, we send false as the
+ * second argument in connect() to prevent refreshing the service database.
+ * This saves considerable time and power.
+ */
+ pClient = NimBLEDevice::getClientByPeerAddress(advDevice->getAddress());
+ if(pClient){
+ if(!pClient->connect(advDevice, false)) {
+ printf("Reconnect failed\n");
+ return false;
+ }
+ printf("Reconnected client\n");
+ }
+ /** We don't already have a client that knows this device,
+ * we will check for a client that is disconnected that we can use.
+ */
+ else {
+ pClient = NimBLEDevice::getDisconnectedClient();
+ }
+ }
+
+ /** No client to reuse? Create a new one. */
+ if(!pClient) {
+ if(NimBLEDevice::getClientListSize() >= NIMBLE_MAX_CONNECTIONS) {
+ printf("Max clients reached - no more connections available\n");
+ return false;
+ }
+
+ pClient = NimBLEDevice::createClient();
+
+ printf("New client created\n");
+
+ pClient->setClientCallbacks(&clientCB, false);
+ /** Set initial connection parameters: These settings are 15ms interval, 0 latency, 120ms timout.
+ * These settings are safe for 3 clients to connect reliably, can go faster if you have less
+ * connections. Timeout should be a multiple of the interval, minimum is 100ms.
+ * Min interval: 12 * 1.25ms = 15, Max interval: 12 * 1.25ms = 15, 0 latency, 12 * 10ms = 120ms timeout
+ */
+ pClient->setConnectionParams(6,6,0,15);
+ /** Set how long we are willing to wait for the connection to complete (seconds), default is 30. */
+ pClient->setConnectTimeout(5);
+
+
+ if (!pClient->connect(advDevice)) {
+ /** Created a client but failed to connect, don't need to keep it as it has no data */
+ NimBLEDevice::deleteClient(pClient);
+ printf("Failed to connect, deleted client\n");
+ return false;
+ }
+ }
+
+ if(!pClient->isConnected()) {
+ if (!pClient->connect(advDevice)) {
+ printf("Failed to connect\n");
+ return false;
+ }
+ }
+
+ printf("Connected to: %s RSSI: %d\n",
+ pClient->getPeerAddress().toString().c_str(),
+ pClient->getRssi());
+
+ /** Now we can read/write/subscribe the charateristics of the services we are interested in */
+ NimBLERemoteService* pSvc = nullptr;
+ NimBLERemoteCharacteristic* pChr = nullptr;
+ NimBLERemoteDescriptor* pDsc = nullptr;
+
+ pSvc = pClient->getService("DEAD");
+ if(pSvc) { /** make sure it's not null */
+ pChr = pSvc->getCharacteristic("BEEF");
+ }
+
+ if(pChr) { /** make sure it's not null */
+ if(pChr->canRead()) {
+ printf("%s Value: %s\n",
+ pChr->getUUID().toString().c_str(),
+ pChr->readValue().c_str());
+ }
+
+ if(pChr->canWrite()) {
+ if(pChr->writeValue("Tasty")) {
+ printf("Wrote new value to: %s\n", pChr->getUUID().toString().c_str());
+ }
+ else {
+ /** Disconnect if write failed */
+ pClient->disconnect();
+ return false;
+ }
+
+ if(pChr->canRead()) {
+ printf("The value of: %s is now: %s\n",
+ pChr->getUUID().toString().c_str(),
+ pChr->readValue().c_str());
+ }
+ }
+
+ /** registerForNotify() has been deprecated and replaced with subscribe() / unsubscribe().
+ * Subscribe parameter defaults are: notifications=true, notifyCallback=nullptr, response=false.
+ * Unsubscribe parameter defaults are: response=false.
+ */
+ if(pChr->canNotify()) {
+ //if(!pChr->registerForNotify(notifyCB)) {
+ if(!pChr->subscribe(true, notifyCB)) {
+ /** Disconnect if subscribe failed */
+ pClient->disconnect();
+ return false;
+ }
+ }
+ else if(pChr->canIndicate()) {
+ /** Send false as first argument to subscribe to indications instead of notifications */
+ //if(!pChr->registerForNotify(notifyCB, false)) {
+ if(!pChr->subscribe(false, notifyCB)) {
+ /** Disconnect if subscribe failed */
+ pClient->disconnect();
+ return false;
+ }
+ }
+ }
+
+ else{
+ printf("DEAD service not found.\n");
+ }
+
+ pSvc = pClient->getService("BAAD");
+ if(pSvc) { /** make sure it's not null */
+ pChr = pSvc->getCharacteristic("F00D");
+ }
+
+ if(pChr) { /** make sure it's not null */
+ if(pChr->canRead()) {
+ printf("%s Value: %s\n",
+ pChr->getUUID().toString().c_str(),
+ pChr->readValue().c_str());
+ }
+
+ pDsc = pChr->getDescriptor(NimBLEUUID("C01D"));
+ if(pDsc) { /** make sure it's not null */
+ printf("Descriptor: %s Value: %s\n",
+ pDsc->getUUID().toString().c_str(),
+ pDsc->readValue().c_str());
+ }
+
+ if(pChr->canWrite()) {
+ if(pChr->writeValue("No tip!")) {
+ printf("Wrote new value to: %s\n", pChr->getUUID().toString().c_str());
+ }
+ else {
+ /** Disconnect if write failed */
+ pClient->disconnect();
+ return false;
+ }
+
+ if(pChr->canRead()) {
+ printf("The value of: %s is now: %s\n",
+ pChr->getUUID().toString().c_str(),
+ pChr->readValue().c_str());
+ }
+ }
+
+ /** registerForNotify() has been deprecated and replaced with subscribe() / unsubscribe().
+ * Subscribe parameter defaults are: notifications=true, notifyCallback=nullptr, response=false.
+ * Unsubscribe parameter defaults are: response=false.
+ */
+ if(pChr->canNotify()) {
+ //if(!pChr->registerForNotify(notifyCB)) {
+ if(!pChr->subscribe(true, notifyCB)) {
+ /** Disconnect if subscribe failed */
+ pClient->disconnect();
+ return false;
+ }
+ }
+ else if(pChr->canIndicate()) {
+ /** Send false as first argument to subscribe to indications instead of notifications */
+ //if(!pChr->registerForNotify(notifyCB, false)) {
+ if(!pChr->subscribe(false, notifyCB)) {
+ /** Disconnect if subscribe failed */
+ pClient->disconnect();
+ return false;
+ }
+ }
+ }
+
+ else{
+ printf("BAAD service not found.\n");
+ }
+
+ printf("Done with this device!\n");
+ return true;
+}
+
+void connectTask (void * parameter){
+ /** Loop here until we find a device we want to connect to */
+ for(;;) {
+ if(doConnect) {
+ doConnect = false;
+ /** Found a device we want to connect to, do it now */
+ if(connectToServer()) {
+ printf("Success! we should now be getting notifications, scanning for more!\n");
+ } else {
+ printf("Failed to connect, starting scan\n");
+ }
+
+ NimBLEDevice::getScan()->start(scanTime,scanEndedCB);
+ }
+ vTaskDelay(10/portTICK_PERIOD_MS);
+ }
+
+ vTaskDelete(NULL);
+}
+
+void app_main (void){
+ printf("Starting NimBLE Client\n");
+ /** Initialize NimBLE, no device name spcified as we are not advertising */
+ NimBLEDevice::init("");
+
+ /** Set the IO capabilities of the device, each option will trigger a different pairing method.
+ * BLE_HS_IO_KEYBOARD_ONLY - Passkey pairing
+ * BLE_HS_IO_DISPLAY_YESNO - Numeric comparison pairing
+ * BLE_HS_IO_NO_INPUT_OUTPUT - DEFAULT setting - just works pairing
+ */
+ //NimBLEDevice::setSecurityIOCap(BLE_HS_IO_KEYBOARD_ONLY); // use passkey
+ //NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_YESNO); //use numeric comparison
+
+ /** 2 different ways to set security - both calls achieve the same result.
+ * no bonding, no man in the middle protection, secure connections.
+ *
+ * These are the default values, only shown here for demonstration.
+ */
+ //NimBLEDevice::setSecurityAuth(false, false, true);
+ NimBLEDevice::setSecurityAuth(/*BLE_SM_PAIR_AUTHREQ_BOND | BLE_SM_PAIR_AUTHREQ_MITM |*/ BLE_SM_PAIR_AUTHREQ_SC);
+
+ /** Optional: set the transmit power, default is -3db */
+ NimBLEDevice::setPower(ESP_PWR_LVL_P9); /** 12db */
+
+ /** Optional: set any devices you don't want to get advertisments from */
+ // NimBLEDevice::addIgnored(NimBLEAddress ("aa:bb:cc:dd:ee:ff"));
+
+ /** create new scan */
+ NimBLEScan* pScan = NimBLEDevice::getScan();
+
+ /** create a callback that gets called when advertisers are found */
+ pScan->setAdvertisedDeviceCallbacks(new AdvertisedDeviceCallbacks());
+
+ /** Set scan interval (how often) and window (how long) in milliseconds */
+ pScan->setInterval(400);
+ pScan->setWindow(100);
+
+ /** Active scan will gather scan response data from advertisers
+ * but will use more energy from both devices
+ */
+ pScan->setActiveScan(true);
+ /** Start scanning for advertisers for the scan time specified (in seconds) 0 = forever
+ * Optional callback for when scanning stops.
+ */
+ pScan->start(scanTime, scanEndedCB);
+
+ printf("Scanning for peripherals\n");
+
+ xTaskCreate(connectTask, "connectTask", 5000, NULL, 1, NULL);
+}
+
diff --git a/src/components/esp-nimble-cpp-1.3.3/examples/Advanced/NimBLE_Server/CMakeLists.txt b/src/components/esp-nimble-cpp-1.3.3/examples/Advanced/NimBLE_Server/CMakeLists.txt
new file mode 100644
index 0000000..e24a91b
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/examples/Advanced/NimBLE_Server/CMakeLists.txt
@@ -0,0 +1,7 @@
+# The following lines of boilerplate have to be in your project's
+# CMakeLists in this exact order for cmake to work correctly
+cmake_minimum_required(VERSION 3.5)
+
+include($ENV{IDF_PATH}/tools/cmake/project.cmake)
+set(SUPPORTED_TARGETS esp32)
+project(NimBLE_Server)
diff --git a/src/components/esp-nimble-cpp-1.3.3/examples/Advanced/NimBLE_Server/Makefile b/src/components/esp-nimble-cpp-1.3.3/examples/Advanced/NimBLE_Server/Makefile
new file mode 100644
index 0000000..dd998b1
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/examples/Advanced/NimBLE_Server/Makefile
@@ -0,0 +1,3 @@
+PROJECT_NAME := NimBLE_Server
+
+include $(IDF_PATH)/make/project.mk
diff --git a/src/components/esp-nimble-cpp-1.3.3/examples/Advanced/NimBLE_Server/main/CMakeLists.txt b/src/components/esp-nimble-cpp-1.3.3/examples/Advanced/NimBLE_Server/main/CMakeLists.txt
new file mode 100644
index 0000000..9be9075
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/examples/Advanced/NimBLE_Server/main/CMakeLists.txt
@@ -0,0 +1,4 @@
+set(COMPONENT_SRCS "main.cpp")
+set(COMPONENT_ADD_INCLUDEDIRS ".")
+
+register_component()
\ No newline at end of file
diff --git a/src/components/esp-nimble-cpp-1.3.3/examples/Advanced/NimBLE_Server/main/component.mk b/src/components/esp-nimble-cpp-1.3.3/examples/Advanced/NimBLE_Server/main/component.mk
new file mode 100644
index 0000000..a98f634
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/examples/Advanced/NimBLE_Server/main/component.mk
@@ -0,0 +1,4 @@
+#
+# "main" pseudo-component makefile.
+#
+# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
diff --git a/src/components/esp-nimble-cpp-1.3.3/examples/Advanced/NimBLE_Server/main/main.cpp b/src/components/esp-nimble-cpp-1.3.3/examples/Advanced/NimBLE_Server/main/main.cpp
new file mode 100644
index 0000000..b8c4bb6
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/examples/Advanced/NimBLE_Server/main/main.cpp
@@ -0,0 +1,229 @@
+
+/** NimBLE_Server Demo:
+ *
+ * Demonstrates many of the available features of the NimBLE server library.
+ *
+ * Created: on March 22 2020
+ * Author: H2zero
+ *
+*/
+#include "NimBLEDevice.h"
+#include "NimBLELog.h"
+
+#include
+
+extern "C" {void app_main(void);}
+
+static NimBLEServer* pServer;
+
+/** None of these are required as they will be handled by the library with defaults. **
+ ** Remove as you see fit for your needs */
+class ServerCallbacks: public NimBLEServerCallbacks {
+ void onConnect(NimBLEServer* pServer) {
+ printf("Client connected\n");
+ NimBLEDevice::startAdvertising();
+ };
+ /** Alternative onConnect() method to extract details of the connection.
+ * See: src/ble_gap.h for the details of the ble_gap_conn_desc struct.
+ */
+ void onConnect(NimBLEServer* pServer, ble_gap_conn_desc* desc) {
+ printf("Client address: %s\n", NimBLEAddress(desc->peer_ota_addr).toString().c_str());
+ /** We can use the connection handle here to ask for different connection parameters.
+ * Args: connection handle, min connection interval, max connection interval
+ * latency, supervision timeout.
+ * Units; Min/Max Intervals: 1.25 millisecond increments.
+ * Latency: number of intervals allowed to skip.
+ * Timeout: 10 millisecond increments, try for 3x interval time for best results.
+ */
+ pServer->updateConnParams(desc->conn_handle, 24, 48, 0, 18);
+ };
+ void onDisconnect(NimBLEServer* pServer) {
+ printf("Client disconnected - start advertising\n");
+ NimBLEDevice::startAdvertising();
+ };
+ void onMTUChange(uint16_t MTU, ble_gap_conn_desc* desc) {
+ printf("MTU updated: %u for connection ID: %u\n", MTU, desc->conn_handle);
+ };
+
+/********************* Security handled here **********************
+****** Note: these are the same return values as defaults ********/
+ uint32_t onPassKeyRequest(){
+ printf("Server Passkey Request\n");
+ /** This should return a random 6 digit number for security
+ * or make your own static passkey as done here.
+ */
+ return 123456;
+ };
+
+ bool onConfirmPIN(uint32_t pass_key){
+ printf("The passkey YES/NO number: %d\n", pass_key);
+ /** Return false if passkeys don't match. */
+ return true;
+ };
+
+ void onAuthenticationComplete(ble_gap_conn_desc* desc){
+ /** Check that encryption was successful, if not we disconnect the client */
+ if(!desc->sec_state.encrypted) {
+ /** NOTE: createServer returns the current server reference unless one is not already created */
+ NimBLEDevice::createServer()->disconnect(desc->conn_handle);
+ printf("Encrypt connection failed - disconnecting client\n");
+ return;
+ }
+ printf("Starting BLE work!");
+ };
+};
+
+/** Handler class for characteristic actions */
+class CharacteristicCallbacks: public NimBLECharacteristicCallbacks {
+ void onRead(NimBLECharacteristic* pCharacteristic){
+ printf("%s : onRead(), value: %s\n",
+ pCharacteristic->getUUID().toString().c_str(),
+ pCharacteristic->getValue().c_str());
+ };
+
+ void onWrite(NimBLECharacteristic* pCharacteristic) {
+ printf("%s : onWrite(), value: %s\n",
+ pCharacteristic->getUUID().toString().c_str(),
+ pCharacteristic->getValue().c_str());
+ };
+ /** Called before notification or indication is sent,
+ * the value can be changed here before sending if desired.
+ */
+ void onNotify(NimBLECharacteristic* pCharacteristic) {
+ printf("Sending notification to clients\n");
+ };
+
+
+ /** The status returned in status is defined in NimBLECharacteristic.h.
+ * The value returned in code is the NimBLE host return code.
+ */
+ void onStatus(NimBLECharacteristic* pCharacteristic, Status status, int code) {
+ printf("Notification/Indication status code: %d , return code: %d, %s\n",
+ status,
+ code,
+ NimBLEUtils::returnCodeToString(code));
+ };
+};
+
+/** Handler class for descriptor actions */
+class DescriptorCallbacks : public NimBLEDescriptorCallbacks {
+ void onWrite(NimBLEDescriptor* pDescriptor) {
+ std::string dscVal((char*)pDescriptor->getValue(), pDescriptor->getLength());
+ printf("Descriptor witten value: %s\n", dscVal.c_str());
+ };
+
+ void onRead(NimBLEDescriptor* pDescriptor) {
+ printf("%s Descriptor read\n", pDescriptor->getUUID().toString().c_str());
+ };;
+};
+
+
+/** Define callback instances globally to use for multiple Charateristics \ Descriptors */
+static DescriptorCallbacks dscCallbacks;
+static CharacteristicCallbacks chrCallbacks;
+
+void notifyTask(void * parameter){
+ for(;;) {
+ if(pServer->getConnectedCount()) {
+ NimBLEService* pSvc = pServer->getServiceByUUID("BAAD");
+ if(pSvc) {
+ NimBLECharacteristic* pChr = pSvc->getCharacteristic("F00D");
+ if(pChr) {
+ pChr->notify(true);
+ }
+ }
+ }
+ vTaskDelay(2000/portTICK_PERIOD_MS);
+ }
+
+ vTaskDelete(NULL);
+}
+
+void app_main(void) {
+ printf("Starting NimBLE Server\n");
+
+ /** sets device name */
+ NimBLEDevice::init("NimBLE");
+
+ /** Set the IO capabilities of the device, each option will trigger a different pairing method.
+ * BLE_HS_IO_DISPLAY_ONLY - Passkey pairing
+ * BLE_HS_IO_DISPLAY_YESNO - Numeric comparison pairing
+ * BLE_HS_IO_NO_INPUT_OUTPUT - DEFAULT setting - just works pairing
+ */
+ //NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_ONLY); // use passkey
+ //NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_YESNO); //use numeric comparison
+
+ /** 2 different ways to set security - both calls achieve the same result.
+ * no bonding, no man in the middle protection, secure connections.
+ *
+ * These are the default values, only shown here for demonstration.
+ */
+ //NimBLEDevice::setSecurityAuth(false, false, true);
+ NimBLEDevice::setSecurityAuth(/*BLE_SM_PAIR_AUTHREQ_BOND | BLE_SM_PAIR_AUTHREQ_MITM |*/ BLE_SM_PAIR_AUTHREQ_SC);
+
+ pServer = NimBLEDevice::createServer();
+ pServer->setCallbacks(new ServerCallbacks());
+
+ NimBLEService* pDeadService = pServer->createService("DEAD");
+ NimBLECharacteristic* pBeefCharacteristic = pDeadService->createCharacteristic(
+ "BEEF",
+ NIMBLE_PROPERTY::READ |
+ NIMBLE_PROPERTY::WRITE |
+ /** Require a secure connection for read and write access */
+ NIMBLE_PROPERTY::READ_ENC | // only allow reading if paired / encrypted
+ NIMBLE_PROPERTY::WRITE_ENC // only allow writing if paired / encrypted
+ );
+
+ pBeefCharacteristic->setValue("Burger");
+ pBeefCharacteristic->setCallbacks(&chrCallbacks);
+
+ /** 2902 and 2904 descriptors are a special case, when createDescriptor is called with
+ * either of those uuid's it will create the associated class with the correct properties
+ * and sizes. However we must cast the returned reference to the correct type as the method
+ * only returns a pointer to the base NimBLEDescriptor class.
+ */
+ NimBLE2904* pBeef2904 = (NimBLE2904*)pBeefCharacteristic->createDescriptor("2904");
+ pBeef2904->setFormat(NimBLE2904::FORMAT_UTF8);
+ pBeef2904->setCallbacks(&dscCallbacks);
+
+
+ NimBLEService* pBaadService = pServer->createService("BAAD");
+ NimBLECharacteristic* pFoodCharacteristic = pBaadService->createCharacteristic(
+ "F00D",
+ NIMBLE_PROPERTY::READ |
+ NIMBLE_PROPERTY::WRITE |
+ NIMBLE_PROPERTY::NOTIFY
+ );
+
+ pFoodCharacteristic->setValue("Fries");
+ pFoodCharacteristic->setCallbacks(&chrCallbacks);
+
+ /** Custom descriptor: Arguments are UUID, Properties, max length in bytes of the value */
+ NimBLEDescriptor* pC01Ddsc = pFoodCharacteristic->createDescriptor(
+ "C01D",
+ NIMBLE_PROPERTY::READ |
+ NIMBLE_PROPERTY::WRITE|
+ NIMBLE_PROPERTY::WRITE_ENC, // only allow writing if paired / encrypted
+ 20
+ );
+ pC01Ddsc->setValue("Send it back!");
+ pC01Ddsc->setCallbacks(&dscCallbacks);
+
+ /** Start the services when finished creating all Characteristics and Descriptors */
+ pDeadService->start();
+ pBaadService->start();
+
+ NimBLEAdvertising* pAdvertising = NimBLEDevice::getAdvertising();
+ /** Add the services to the advertisment data **/
+ pAdvertising->addServiceUUID(pDeadService->getUUID());
+ pAdvertising->addServiceUUID(pBaadService->getUUID());
+ /** If your device is battery powered you may consider setting scan response
+ * to false as it will extend battery life at the expense of less data sent.
+ */
+ pAdvertising->setScanResponse(true);
+ pAdvertising->start();
+
+ printf("Advertising Started\n");
+
+ xTaskCreate(notifyTask, "notifyTask", 5000, NULL, 1, NULL);
+}
diff --git a/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_client/CMakeLists.txt b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_client/CMakeLists.txt
new file mode 100644
index 0000000..8f619c4
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_client/CMakeLists.txt
@@ -0,0 +1,7 @@
+# The following lines of boilerplate have to be in your project's
+# CMakeLists in this exact order for cmake to work correctly
+cmake_minimum_required(VERSION 3.5)
+
+include($ENV{IDF_PATH}/tools/cmake/project.cmake)
+set(SUPPORTED_TARGETS esp32)
+project(BLE_client)
diff --git a/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_client/Makefile b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_client/Makefile
new file mode 100644
index 0000000..d2e7b5a
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_client/Makefile
@@ -0,0 +1,3 @@
+PROJECT_NAME := BLE_client
+
+include $(IDF_PATH)/make/project.mk
diff --git a/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_client/main/CMakeLists.txt b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_client/main/CMakeLists.txt
new file mode 100644
index 0000000..9be9075
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_client/main/CMakeLists.txt
@@ -0,0 +1,4 @@
+set(COMPONENT_SRCS "main.cpp")
+set(COMPONENT_ADD_INCLUDEDIRS ".")
+
+register_component()
\ No newline at end of file
diff --git a/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_client/main/component.mk b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_client/main/component.mk
new file mode 100644
index 0000000..a98f634
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_client/main/component.mk
@@ -0,0 +1,4 @@
+#
+# "main" pseudo-component makefile.
+#
+# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
diff --git a/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_client/main/main.cpp b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_client/main/main.cpp
new file mode 100644
index 0000000..49e8ad4
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_client/main/main.cpp
@@ -0,0 +1,200 @@
+/**
+ * A BLE client example that is rich in capabilities.
+ * There is a lot new capabilities implemented.
+ * author unknown
+ * updated by chegewara
+ * updated for NimBLE by H2zero
+ */
+
+/** NimBLE differences highlighted in comment blocks **/
+
+/*******original********
+#include "BLEDevice.h"
+***********************/
+#include "NimBLEDevice.h"
+
+extern "C"{void app_main(void);}
+
+// The remote service we wish to connect to.
+static BLEUUID serviceUUID("4fafc201-1fb5-459e-8fcc-c5c9c331914b");
+// The characteristic of the remote service we are interested in.
+static BLEUUID charUUID("beb5483e-36e1-4688-b7f5-ea07361b26a8");
+
+static bool doConnect = false;
+static bool connected = false;
+static bool doScan = false;
+static BLERemoteCharacteristic* pRemoteCharacteristic;
+static BLEAdvertisedDevice* myDevice;
+
+static void notifyCallback(
+ BLERemoteCharacteristic* pBLERemoteCharacteristic,
+ uint8_t* pData,
+ size_t length,
+ bool isNotify) {
+ printf("Notify callback for characteristic %s of data length %d data: %s\n",
+ pBLERemoteCharacteristic->getUUID().toString().c_str(),
+ length,
+ (char*)pData);
+}
+
+/** None of these are required as they will be handled by the library with defaults. **
+ ** Remove as you see fit for your needs */
+class MyClientCallback : public BLEClientCallbacks {
+ void onConnect(BLEClient* pclient) {
+ }
+
+ void onDisconnect(BLEClient* pclient) {
+ connected = false;
+ printf("onDisconnect");
+ }
+/***************** New - Security handled here ********************
+****** Note: these are the same return values as defaults ********/
+ uint32_t onPassKeyRequest(){
+ printf("Client PassKeyRequest\n");
+ return 123456;
+ }
+ bool onConfirmPIN(uint32_t pass_key){
+ printf("The passkey YES/NO number: %d\n", pass_key);
+ return true;
+ }
+
+ void onAuthenticationComplete(ble_gap_conn_desc desc){
+ printf("Starting BLE work!\n");
+ }
+/*******************************************************************/
+};
+
+bool connectToServer() {
+ printf("Forming a connection to %s\n", myDevice->getAddress().toString().c_str());
+
+ BLEClient* pClient = BLEDevice::createClient();
+ printf(" - Created client\n");
+
+ pClient->setClientCallbacks(new MyClientCallback());
+
+ // Connect to the remove BLE Server.
+ pClient->connect(myDevice); // if you pass BLEAdvertisedDevice instead of address, it will be recognized type of peer device address (public or private)
+ printf(" - Connected to server\n");
+
+ // Obtain a reference to the service we are after in the remote BLE server.
+ BLERemoteService* pRemoteService = pClient->getService(serviceUUID);
+ if (pRemoteService == nullptr) {
+ printf("Failed to find our service UUID: %s\n", serviceUUID.toString().c_str());
+ pClient->disconnect();
+ return false;
+ }
+ printf(" - Found our service\n");
+
+
+ // Obtain a reference to the characteristic in the service of the remote BLE server.
+ pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID);
+ if (pRemoteCharacteristic == nullptr) {
+ printf("Failed to find our characteristic UUID: %s\n", charUUID.toString().c_str());
+ pClient->disconnect();
+ return false;
+ }
+ printf(" - Found our characteristic\n");
+
+ // Read the value of the characteristic.
+ if(pRemoteCharacteristic->canRead()) {
+ std::string value = pRemoteCharacteristic->readValue();
+ printf("The characteristic value was: %s\n", value.c_str());
+ }
+ /** registerForNotify() has been deprecated and replaced with subscribe() / unsubscribe().
+ * Subscribe parameter defaults are: notifications=true, notifyCallback=nullptr, response=false.
+ * Unsubscribe parameter defaults are: response=false.
+ */
+ if(pRemoteCharacteristic->canNotify()) {
+ //pRemoteCharacteristic->registerForNotify(notifyCallback);
+ pRemoteCharacteristic->subscribe(true, notifyCallback);
+ }
+
+ connected = true;
+ return true;
+}
+
+/**
+ * Scan for BLE servers and find the first one that advertises the service we are looking for.
+ */
+class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
+ /**
+ * Called for each advertising BLE server.
+ */
+
+/*** Only a reference to the advertised device is passed now
+ void onResult(BLEAdvertisedDevice advertisedDevice) { **/
+ void onResult(BLEAdvertisedDevice* advertisedDevice) {
+ printf("BLE Advertised Device found: %s\n", advertisedDevice->toString().c_str());
+
+ // We have found a device, let us now see if it contains the service we are looking for.
+/********************************************************************************
+ if (advertisedDevice.haveServiceUUID() && advertisedDevice.isAdvertisingService(serviceUUID)) {
+********************************************************************************/
+ if (advertisedDevice->haveServiceUUID() && advertisedDevice->isAdvertisingService(serviceUUID)) {
+
+ BLEDevice::getScan()->stop();
+/*******************************************************************
+ myDevice = new BLEAdvertisedDevice(advertisedDevice);
+*******************************************************************/
+ myDevice = advertisedDevice; /** Just save the reference now, no need to copy the object */
+ doConnect = true;
+ doScan = true;
+
+ } // Found our server
+ } // onResult
+}; // MyAdvertisedDeviceCallbacks
+
+
+// This is the Arduino main loop function.
+void connectTask (void * parameter){
+ for(;;) {
+ // If the flag "doConnect" is true then we have scanned for and found the desired
+ // BLE Server with which we wish to connect. Now we connect to it. Once we are
+ // connected we set the connected flag to be true.
+ if (doConnect == true) {
+ if (connectToServer()) {
+ printf("We are now connected to the BLE Server.\n");
+ } else {
+ printf("We have failed to connect to the server; there is nothin more we will do.\n");
+ }
+ doConnect = false;
+ }
+
+ // If we are connected to a peer BLE Server, update the characteristic each time we are reached
+ // with the current time since boot.
+ if (connected) {
+ char buf[256];
+ snprintf(buf, 256, "Time since boot: %lu", (unsigned long)(esp_timer_get_time() / 1000000ULL));
+ printf("Setting new characteristic value to %s\n", buf);
+
+ // Set the characteristic's value to be the array of bytes that is actually a string.
+ /*** Note: write value now returns true if successful, false otherwise - try again or disconnect ***/
+ pRemoteCharacteristic->writeValue((uint8_t*)buf, strlen(buf), false);
+ }else if(doScan){
+ BLEDevice::getScan()->start(0); // this is just eample to start scan after disconnect, most likely there is better way to do it in arduino
+ }
+
+ vTaskDelay(1000/portTICK_PERIOD_MS); // Delay a second between loops.
+ }
+
+ vTaskDelete(NULL);
+} // End of loop
+
+
+void app_main(void) {
+ printf("Starting BLE Client application...\n");
+ BLEDevice::init("");
+
+ // Retrieve a Scanner and set the callback we want to use to be informed when we
+ // have detected a new device. Specify that we want active scanning and start the
+ // scan to run for 5 seconds.
+ BLEScan* pBLEScan = BLEDevice::getScan();
+ pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
+ pBLEScan->setInterval(1349);
+ pBLEScan->setWindow(449);
+ pBLEScan->setActiveScan(true);
+
+ xTaskCreate(connectTask, "connectTask", 5000, NULL, 1, NULL);
+ pBLEScan->start(5, false);
+} // End of setup.
+
diff --git a/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_notify/CMakeLists.txt b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_notify/CMakeLists.txt
new file mode 100644
index 0000000..dbfacf5
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_notify/CMakeLists.txt
@@ -0,0 +1,7 @@
+# The following lines of boilerplate have to be in your project's
+# CMakeLists in this exact order for cmake to work correctly
+cmake_minimum_required(VERSION 3.5)
+
+include($ENV{IDF_PATH}/tools/cmake/project.cmake)
+set(SUPPORTED_TARGETS esp32)
+project(BLE_notify)
diff --git a/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_notify/Makefile b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_notify/Makefile
new file mode 100644
index 0000000..b895d99
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_notify/Makefile
@@ -0,0 +1,3 @@
+PROJECT_NAME := BLE_notify
+
+include $(IDF_PATH)/make/project.mk
diff --git a/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_notify/main/CMakeLists.txt b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_notify/main/CMakeLists.txt
new file mode 100644
index 0000000..9be9075
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_notify/main/CMakeLists.txt
@@ -0,0 +1,4 @@
+set(COMPONENT_SRCS "main.cpp")
+set(COMPONENT_ADD_INCLUDEDIRS ".")
+
+register_component()
\ No newline at end of file
diff --git a/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_notify/main/component.mk b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_notify/main/component.mk
new file mode 100644
index 0000000..a98f634
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_notify/main/component.mk
@@ -0,0 +1,4 @@
+#
+# "main" pseudo-component makefile.
+#
+# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
diff --git a/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_notify/main/main.cpp b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_notify/main/main.cpp
new file mode 100644
index 0000000..8382547
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_notify/main/main.cpp
@@ -0,0 +1,155 @@
+/*
+ Video: https://www.youtube.com/watch?v=oCMOYS71NIU
+ Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleNotify.cpp
+ Ported to Arduino ESP32 by Evandro Copercini
+ updated by chegewara
+ Refactored back to IDF by H2zero
+
+ Create a BLE server that, once we receive a connection, will send periodic notifications.
+ The service advertises itself as: 4fafc201-1fb5-459e-8fcc-c5c9c331914b
+ And has a characteristic of: beb5483e-36e1-4688-b7f5-ea07361b26a8
+
+ The design of creating the BLE server is:
+ 1. Create a BLE Server
+ 2. Create a BLE Service
+ 3. Create a BLE Characteristic on the Service
+ 4. Create a BLE Descriptor on the characteristic
+ 5. Start the service.
+ 6. Start advertising.
+
+ A connect hander associated with the server starts a background task that performs notification
+ every couple of seconds.
+*/
+
+/** NimBLE differences highlighted in comment blocks **/
+
+/*******original********
+#include
+#include
+#include
+#include
+***********************/
+#include
+
+extern "C" {void app_main(void);}
+
+BLEServer* pServer = NULL;
+BLECharacteristic* pCharacteristic = NULL;
+bool deviceConnected = false;
+bool oldDeviceConnected = false;
+uint32_t value = 0;
+
+// See the following for generating UUIDs:
+// https://www.uuidgenerator.net/
+
+#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
+#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
+
+/** None of these are required as they will be handled by the library with defaults. **
+ ** Remove as you see fit for your needs */
+class MyServerCallbacks: public BLEServerCallbacks {
+ void onConnect(BLEServer* pServer) {
+ deviceConnected = true;
+ };
+
+ void onDisconnect(BLEServer* pServer) {
+ deviceConnected = false;
+ }
+/***************** New - Security handled here ********************
+****** Note: these are the same return values as defaults ********/
+ uint32_t onPassKeyRequest(){
+ printf("Server PassKeyRequest\n");
+ return 123456;
+ }
+
+ bool onConfirmPIN(uint32_t pass_key){
+ printf("The passkey YES/NO number: %d\n", pass_key);
+ return true;
+ }
+
+ void onAuthenticationComplete(ble_gap_conn_desc desc){
+ printf("Starting BLE work!\n");
+ }
+/*******************************************************************/
+};
+
+void connectedTask (void * parameter){
+ for(;;) {
+ // notify changed value
+ if (deviceConnected) {
+ pCharacteristic->setValue((uint8_t*)&value, 4);
+ pCharacteristic->notify();
+ value++;
+ vTaskDelay(100/portTICK_PERIOD_MS); // bluetooth stack will go into congestion, if too many packets are sent
+ }
+ // disconnecting
+ if (!deviceConnected && oldDeviceConnected) {
+ vTaskDelay(500/portTICK_PERIOD_MS); // give the bluetooth stack the chance to get things ready
+ pServer->startAdvertising(); // restart advertising
+ printf("start advertising\n");
+ oldDeviceConnected = deviceConnected;
+ }
+ // connecting
+ if (deviceConnected && !oldDeviceConnected) {
+ // do stuff here on connecting
+ oldDeviceConnected = deviceConnected;
+ }
+
+ vTaskDelay(10/portTICK_PERIOD_MS); // Delay between loops to reset watchdog timer
+ }
+
+ vTaskDelete(NULL);
+}
+
+void app_main(void) {
+ // Create the BLE Device
+ BLEDevice::init("ESP32");
+
+ // Create the BLE Server
+ pServer = BLEDevice::createServer();
+ pServer->setCallbacks(new MyServerCallbacks());
+
+ // Create the BLE Service
+ BLEService *pService = pServer->createService(SERVICE_UUID);
+
+ // Create a BLE Characteristic
+ pCharacteristic = pService->createCharacteristic(
+ CHARACTERISTIC_UUID,
+ /******* Enum Type NIMBLE_PROPERTY now *******
+ BLECharacteristic::PROPERTY_READ |
+ BLECharacteristic::PROPERTY_WRITE |
+ BLECharacteristic::PROPERTY_NOTIFY |
+ BLECharacteristic::PROPERTY_INDICATE
+ );
+ **********************************************/
+ NIMBLE_PROPERTY::READ |
+ NIMBLE_PROPERTY::WRITE |
+ NIMBLE_PROPERTY::NOTIFY |
+ NIMBLE_PROPERTY::INDICATE
+ );
+
+ // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml
+ // Create a BLE Descriptor
+ /***************************************************
+ NOTE: DO NOT create a 2902 descriptor.
+ it will be created automatically if notifications
+ or indications are enabled on a characteristic.
+
+ pCharacteristic->addDescriptor(new BLE2902());
+ ****************************************************/
+ // Start the service
+ pService->start();
+
+ // Start advertising
+ BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
+ pAdvertising->addServiceUUID(SERVICE_UUID);
+ pAdvertising->setScanResponse(false);
+ /** This method had been removed **
+ pAdvertising->setMinPreferred(0x0); // set value to 0x00 to not advertise this parameter
+ **/
+
+ xTaskCreate(connectedTask, "connectedTask", 5000, NULL, 1, NULL);
+
+ BLEDevice::startAdvertising();
+ printf("Waiting a client connection to notify...\n");
+}
diff --git a/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_scan/CMakeLists.txt b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_scan/CMakeLists.txt
new file mode 100644
index 0000000..0f64bee
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_scan/CMakeLists.txt
@@ -0,0 +1,7 @@
+# The following lines of boilerplate have to be in your project's
+# CMakeLists in this exact order for cmake to work correctly
+cmake_minimum_required(VERSION 3.5)
+
+include($ENV{IDF_PATH}/tools/cmake/project.cmake)
+set(SUPPORTED_TARGETS esp32)
+project(BLE_scan)
diff --git a/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_scan/Makefile b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_scan/Makefile
new file mode 100644
index 0000000..ebca276
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_scan/Makefile
@@ -0,0 +1,3 @@
+PROJECT_NAME := BLE_scan
+
+include $(IDF_PATH)/make/project.mk
diff --git a/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_scan/main/CMakeLists.txt b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_scan/main/CMakeLists.txt
new file mode 100644
index 0000000..9be9075
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_scan/main/CMakeLists.txt
@@ -0,0 +1,4 @@
+set(COMPONENT_SRCS "main.cpp")
+set(COMPONENT_ADD_INCLUDEDIRS ".")
+
+register_component()
\ No newline at end of file
diff --git a/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_scan/main/component.mk b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_scan/main/component.mk
new file mode 100644
index 0000000..a98f634
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_scan/main/component.mk
@@ -0,0 +1,4 @@
+#
+# "main" pseudo-component makefile.
+#
+# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
diff --git a/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_scan/main/main.cpp b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_scan/main/main.cpp
new file mode 100644
index 0000000..5686dd9
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_scan/main/main.cpp
@@ -0,0 +1,52 @@
+/*
+ Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleScan.cpp
+ Ported to Arduino ESP32 by Evandro Copercini
+ Refactored back to IDF by H2zero
+*/
+
+/** NimBLE differences highlighted in comment blocks **/
+
+/*******original********
+#include
+#include
+#include
+#include
+***********************/
+
+#include
+
+extern "C"{void app_main(void);}
+
+int scanTime = 5; //In seconds
+BLEScan* pBLEScan;
+
+class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
+ void onResult(BLEAdvertisedDevice* advertisedDevice) {
+ printf("Advertised Device: %s \n", advertisedDevice->toString().c_str());
+ }
+};
+
+void scanTask (void * parameter){
+ for(;;) {
+ // put your main code here, to run repeatedly:
+ BLEScanResults foundDevices = pBLEScan->start(scanTime, false);
+ printf("Devices found: %d\n", foundDevices.getCount());
+ printf("Scan done!\n");
+ pBLEScan->clearResults(); // delete results fromBLEScan buffer to release memory
+ vTaskDelay(2000/portTICK_PERIOD_MS); // Delay a second between loops.
+ }
+
+ vTaskDelete(NULL);
+}
+
+void app_main(void) {
+ printf("Scanning...\n");
+
+ BLEDevice::init("");
+ pBLEScan = BLEDevice::getScan(); //create new scan
+ pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
+ pBLEScan->setActiveScan(true); //active scan uses more power, but get results faster
+ pBLEScan->setInterval(100);
+ pBLEScan->setWindow(99); // less or equal setInterval value
+ xTaskCreate(scanTask, "scanTask", 5000, NULL, 1, NULL);
+}
diff --git a/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_server/CMakeLists.txt b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_server/CMakeLists.txt
new file mode 100644
index 0000000..03b5365
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_server/CMakeLists.txt
@@ -0,0 +1,7 @@
+# The following lines of boilerplate have to be in your project's
+# CMakeLists in this exact order for cmake to work correctly
+cmake_minimum_required(VERSION 3.5)
+
+include($ENV{IDF_PATH}/tools/cmake/project.cmake)
+set(SUPPORTED_TARGETS esp32)
+project(BLE_server)
diff --git a/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_server/Makefile b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_server/Makefile
new file mode 100644
index 0000000..92dd6cd
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_server/Makefile
@@ -0,0 +1,3 @@
+PROJECT_NAME := BLE_server
+
+include $(IDF_PATH)/make/project.mk
diff --git a/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_server/main/CMakeLists.txt b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_server/main/CMakeLists.txt
new file mode 100644
index 0000000..9be9075
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_server/main/CMakeLists.txt
@@ -0,0 +1,4 @@
+set(COMPONENT_SRCS "main.cpp")
+set(COMPONENT_ADD_INCLUDEDIRS ".")
+
+register_component()
\ No newline at end of file
diff --git a/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_server/main/component.mk b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_server/main/component.mk
new file mode 100644
index 0000000..a98f634
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_server/main/component.mk
@@ -0,0 +1,4 @@
+#
+# "main" pseudo-component makefile.
+#
+# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
diff --git a/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_server/main/main.cpp b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_server/main/main.cpp
new file mode 100644
index 0000000..85c0a3e
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_server/main/main.cpp
@@ -0,0 +1,57 @@
+/*
+ Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleServer.cpp
+ Ported to Arduino ESP32 by Evandro Copercini
+ updates by chegewara
+ Refactored back to IDF by H2zero
+*/
+
+/** NimBLE differences highlighted in comment blocks **/
+
+/*******original********
+#include
+#include
+#include
+***********************/
+
+#include
+
+extern "C"{void app_main(void);}
+
+// See the following for generating UUIDs:
+// https://www.uuidgenerator.net/
+
+#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
+#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
+
+void app_main(void) {
+ printf("Starting BLE work!\n");
+
+ BLEDevice::init("Long name works now");
+ BLEServer *pServer = BLEDevice::createServer();
+ BLEService *pService = pServer->createService(SERVICE_UUID);
+ BLECharacteristic *pCharacteristic = pService->createCharacteristic(
+ CHARACTERISTIC_UUID,
+ /***** Enum Type NIMBLE_PROPERTY now *****
+ BLECharacteristic::PROPERTY_READ |
+ BLECharacteristic::PROPERTY_WRITE
+ );
+ *****************************************/
+ NIMBLE_PROPERTY::READ |
+ NIMBLE_PROPERTY::WRITE
+ );
+
+ pCharacteristic->setValue("Hello World says Neil");
+ pService->start();
+ // BLEAdvertising *pAdvertising = pServer->getAdvertising(); // this still is working for backward compatibility
+ BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
+ pAdvertising->addServiceUUID(SERVICE_UUID);
+ pAdvertising->setScanResponse(true);
+
+ /** These methods have been removed **
+ pAdvertising->setMinPreferred(0x06); // functions that help with iPhone connections issue
+ pAdvertising->setMinPreferred(0x12);
+ */
+
+ BLEDevice::startAdvertising();
+ printf("Characteristic defined! Now you can read it in your phone!\n");
+}
diff --git a/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_uart/CMakeLists.txt b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_uart/CMakeLists.txt
new file mode 100644
index 0000000..9060e47
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_uart/CMakeLists.txt
@@ -0,0 +1,7 @@
+# The following lines of boilerplate have to be in your project's
+# CMakeLists in this exact order for cmake to work correctly
+cmake_minimum_required(VERSION 3.5)
+
+include($ENV{IDF_PATH}/tools/cmake/project.cmake)
+set(SUPPORTED_TARGETS esp32)
+project(BLE_uart)
diff --git a/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_uart/Makefile b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_uart/Makefile
new file mode 100644
index 0000000..9323b57
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_uart/Makefile
@@ -0,0 +1,3 @@
+PROJECT_NAME := BLE_uart
+
+include $(IDF_PATH)/make/project.mk
diff --git a/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_uart/main/CMakeLists.txt b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_uart/main/CMakeLists.txt
new file mode 100644
index 0000000..9be9075
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_uart/main/CMakeLists.txt
@@ -0,0 +1,4 @@
+set(COMPONENT_SRCS "main.cpp")
+set(COMPONENT_ADD_INCLUDEDIRS ".")
+
+register_component()
\ No newline at end of file
diff --git a/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_uart/main/component.mk b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_uart/main/component.mk
new file mode 100644
index 0000000..a98f634
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_uart/main/component.mk
@@ -0,0 +1,4 @@
+#
+# "main" pseudo-component makefile.
+#
+# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
diff --git a/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_uart/main/main.cpp b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_uart/main/main.cpp
new file mode 100644
index 0000000..e0d9422
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/examples/basic/BLE_uart/main/main.cpp
@@ -0,0 +1,167 @@
+/*
+ Video: https://www.youtube.com/watch?v=oCMOYS71NIU
+ Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleNotify.cpp
+ Ported to Arduino ESP32 by Evandro Copercini
+ Refactored back to IDF by H2zero
+
+ Create a BLE server that, once we receive a connection, will send periodic notifications.
+ The service advertises itself as: 6E400001-B5A3-F393-E0A9-E50E24DCCA9E
+ Has a characteristic of: 6E400002-B5A3-F393-E0A9-E50E24DCCA9E - used for receiving data with "WRITE"
+ Has a characteristic of: 6E400003-B5A3-F393-E0A9-E50E24DCCA9E - used to send data with "NOTIFY"
+
+ The design of creating the BLE server is:
+ 1. Create a BLE Server
+ 2. Create a BLE Service
+ 3. Create a BLE Characteristic on the Service
+ 4. Create a BLE Descriptor on the characteristic
+ 5. Start the service.
+ 6. Start advertising.
+
+ In this example rxValue is the data received (only accessible inside that function).
+ And txValue is the data to be sent, in this example just a byte incremented every second.
+*/
+
+/** NimBLE differences highlighted in comment blocks **/
+
+/*******original********
+#include
+#include
+#include
+#include
+***********************/
+#include
+
+extern "C"{void app_main(void);}
+
+BLEServer *pServer = NULL;
+BLECharacteristic * pTxCharacteristic;
+bool deviceConnected = false;
+bool oldDeviceConnected = false;
+uint8_t txValue = 0;
+
+// See the following for generating UUIDs:
+// https://www.uuidgenerator.net/
+
+#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID
+#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
+#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
+
+
+/** None of these are required as they will be handled by the library with defaults. **
+ ** Remove as you see fit for your needs */
+class MyServerCallbacks: public BLEServerCallbacks {
+ void onConnect(BLEServer* pServer) {
+ deviceConnected = true;
+ };
+
+ void onDisconnect(BLEServer* pServer) {
+ deviceConnected = false;
+ }
+ /***************** New - Security handled here ********************
+ ****** Note: these are the same return values as defaults ********/
+ uint32_t onPassKeyRequest(){
+ printf("Server PassKeyRequest\n");
+ return 123456;
+ }
+
+ bool onConfirmPIN(uint32_t pass_key){
+ printf("The passkey YES/NO number: %d\n", pass_key);
+ return true;
+ }
+
+ void onAuthenticationComplete(ble_gap_conn_desc desc){
+ printf("Starting BLE work!\n");
+ }
+ /*******************************************************************/
+};
+
+class MyCallbacks: public BLECharacteristicCallbacks {
+ void onWrite(BLECharacteristic *pCharacteristic) {
+ std::string rxValue = pCharacteristic->getValue();
+
+ if (rxValue.length() > 0) {
+ printf("*********\n");
+ printf("Received Value: ");
+ for (int i = 0; i < rxValue.length(); i++)
+ printf("%d", rxValue[i]);
+
+ printf("\n*********\n");
+ }
+ }
+};
+
+void connectedTask (void * parameter){
+ for(;;) {
+ if (deviceConnected) {
+ pTxCharacteristic->setValue(&txValue, 1);
+ pTxCharacteristic->notify();
+ txValue++;
+ }
+
+ // disconnecting
+ if (!deviceConnected && oldDeviceConnected) {
+ pServer->startAdvertising(); // restart advertising
+ printf("start advertising\n");
+ oldDeviceConnected = deviceConnected;
+ }
+ // connecting
+ if (deviceConnected && !oldDeviceConnected) {
+ // do stuff here on connecting
+ oldDeviceConnected = deviceConnected;
+ }
+
+ vTaskDelay(10/portTICK_PERIOD_MS); // Delay between loops to reset watchdog timer
+ }
+
+ vTaskDelete(NULL);
+}
+
+void app_main(void) {
+ // Create the BLE Device
+ BLEDevice::init("UART Service");
+
+ // Create the BLE Server
+ pServer = BLEDevice::createServer();
+ pServer->setCallbacks(new MyServerCallbacks());
+
+ // Create the BLE Service
+ BLEService *pService = pServer->createService(SERVICE_UUID);
+
+ // Create a BLE Characteristic
+ pTxCharacteristic = pService->createCharacteristic(
+ CHARACTERISTIC_UUID_TX,
+ /******* Enum Type NIMBLE_PROPERTY now *******
+ BLECharacteristic::PROPERTY_NOTIFY
+ );
+ **********************************************/
+ NIMBLE_PROPERTY::NOTIFY
+ );
+
+ /***************************************************
+ NOTE: DO NOT create a 2902 descriptor
+ it will be created automatically if notifications
+ or indications are enabled on a characteristic.
+
+ pCharacteristic->addDescriptor(new BLE2902());
+ ****************************************************/
+
+ BLECharacteristic * pRxCharacteristic = pService->createCharacteristic(
+ CHARACTERISTIC_UUID_RX,
+ /******* Enum Type NIMBLE_PROPERTY now *******
+ BLECharacteristic::PROPERTY_WRITE
+ );
+ *********************************************/
+ NIMBLE_PROPERTY::WRITE
+ );
+
+ pRxCharacteristic->setCallbacks(new MyCallbacks());
+
+ // Start the service
+ pService->start();
+
+ xTaskCreate(connectedTask, "connectedTask", 5000, NULL, 1, NULL);
+
+ // Start advertising
+ pServer->getAdvertising()->start();
+ printf("Waiting a client connection to notify...\n");
+}
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/HIDKeyboardTypes.h b/src/components/esp-nimble-cpp-1.3.3/src/HIDKeyboardTypes.h
new file mode 100644
index 0000000..531437e
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/HIDKeyboardTypes.h
@@ -0,0 +1,402 @@
+/* Copyright (c) 2015 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Note: this file was pulled from different parts of the USBHID library, in mbed SDK
+ */
+
+#ifndef KEYBOARD_DEFS_H
+#define KEYBOARD_DEFS_H
+
+#define REPORT_ID_KEYBOARD 1
+#define REPORT_ID_VOLUME 3
+
+/* Modifiers */
+enum MODIFIER_KEY {
+ KEY_CTRL = 1,
+ KEY_SHIFT = 2,
+ KEY_ALT = 4,
+};
+
+
+enum MEDIA_KEY {
+ KEY_NEXT_TRACK, /*!< next Track Button */
+ KEY_PREVIOUS_TRACK, /*!< Previous track Button */
+ KEY_STOP, /*!< Stop Button */
+ KEY_PLAY_PAUSE, /*!< Play/Pause Button */
+ KEY_MUTE, /*!< Mute Button */
+ KEY_VOLUME_UP, /*!< Volume Up Button */
+ KEY_VOLUME_DOWN, /*!< Volume Down Button */
+};
+
+enum FUNCTION_KEY {
+ KEY_F1 = 128, /* F1 key */
+ KEY_F2, /* F2 key */
+ KEY_F3, /* F3 key */
+ KEY_F4, /* F4 key */
+ KEY_F5, /* F5 key */
+ KEY_F6, /* F6 key */
+ KEY_F7, /* F7 key */
+ KEY_F8, /* F8 key */
+ KEY_F9, /* F9 key */
+ KEY_F10, /* F10 key */
+ KEY_F11, /* F11 key */
+ KEY_F12, /* F12 key */
+
+ KEY_PRINT_SCREEN, /* Print Screen key */
+ KEY_SCROLL_LOCK, /* Scroll lock */
+ KEY_CAPS_LOCK, /* caps lock */
+ KEY_NUM_LOCK, /* num lock */
+ KEY_INSERT, /* Insert key */
+ KEY_HOME, /* Home key */
+ KEY_PAGE_UP, /* Page Up key */
+ KEY_PAGE_DOWN, /* Page Down key */
+
+ RIGHT_ARROW, /* Right arrow */
+ LEFT_ARROW, /* Left arrow */
+ DOWN_ARROW, /* Down arrow */
+ UP_ARROW, /* Up arrow */
+};
+
+typedef struct {
+ unsigned char usage;
+ unsigned char modifier;
+} KEYMAP;
+
+#ifdef US_KEYBOARD
+/* US keyboard (as HID standard) */
+#define KEYMAP_SIZE (152)
+const KEYMAP keymap[KEYMAP_SIZE] = {
+ {0, 0}, /* NUL */
+ {0, 0}, /* SOH */
+ {0, 0}, /* STX */
+ {0, 0}, /* ETX */
+ {0, 0}, /* EOT */
+ {0, 0}, /* ENQ */
+ {0, 0}, /* ACK */
+ {0, 0}, /* BEL */
+ {0x2a, 0}, /* BS */ /* Keyboard Delete (Backspace) */
+ {0x2b, 0}, /* TAB */ /* Keyboard Tab */
+ {0x28, 0}, /* LF */ /* Keyboard Return (Enter) */
+ {0, 0}, /* VT */
+ {0, 0}, /* FF */
+ {0, 0}, /* CR */
+ {0, 0}, /* SO */
+ {0, 0}, /* SI */
+ {0, 0}, /* DEL */
+ {0, 0}, /* DC1 */
+ {0, 0}, /* DC2 */
+ {0, 0}, /* DC3 */
+ {0, 0}, /* DC4 */
+ {0, 0}, /* NAK */
+ {0, 0}, /* SYN */
+ {0, 0}, /* ETB */
+ {0, 0}, /* CAN */
+ {0, 0}, /* EM */
+ {0, 0}, /* SUB */
+ {0, 0}, /* ESC */
+ {0, 0}, /* FS */
+ {0, 0}, /* GS */
+ {0, 0}, /* RS */
+ {0, 0}, /* US */
+ {0x2c, 0}, /* */
+ {0x1e, KEY_SHIFT}, /* ! */
+ {0x34, KEY_SHIFT}, /* " */
+ {0x20, KEY_SHIFT}, /* # */
+ {0x21, KEY_SHIFT}, /* $ */
+ {0x22, KEY_SHIFT}, /* % */
+ {0x24, KEY_SHIFT}, /* & */
+ {0x34, 0}, /* ' */
+ {0x26, KEY_SHIFT}, /* ( */
+ {0x27, KEY_SHIFT}, /* ) */
+ {0x25, KEY_SHIFT}, /* * */
+ {0x2e, KEY_SHIFT}, /* + */
+ {0x36, 0}, /* , */
+ {0x2d, 0}, /* - */
+ {0x37, 0}, /* . */
+ {0x38, 0}, /* / */
+ {0x27, 0}, /* 0 */
+ {0x1e, 0}, /* 1 */
+ {0x1f, 0}, /* 2 */
+ {0x20, 0}, /* 3 */
+ {0x21, 0}, /* 4 */
+ {0x22, 0}, /* 5 */
+ {0x23, 0}, /* 6 */
+ {0x24, 0}, /* 7 */
+ {0x25, 0}, /* 8 */
+ {0x26, 0}, /* 9 */
+ {0x33, KEY_SHIFT}, /* : */
+ {0x33, 0}, /* ; */
+ {0x36, KEY_SHIFT}, /* < */
+ {0x2e, 0}, /* = */
+ {0x37, KEY_SHIFT}, /* > */
+ {0x38, KEY_SHIFT}, /* ? */
+ {0x1f, KEY_SHIFT}, /* @ */
+ {0x04, KEY_SHIFT}, /* A */
+ {0x05, KEY_SHIFT}, /* B */
+ {0x06, KEY_SHIFT}, /* C */
+ {0x07, KEY_SHIFT}, /* D */
+ {0x08, KEY_SHIFT}, /* E */
+ {0x09, KEY_SHIFT}, /* F */
+ {0x0a, KEY_SHIFT}, /* G */
+ {0x0b, KEY_SHIFT}, /* H */
+ {0x0c, KEY_SHIFT}, /* I */
+ {0x0d, KEY_SHIFT}, /* J */
+ {0x0e, KEY_SHIFT}, /* K */
+ {0x0f, KEY_SHIFT}, /* L */
+ {0x10, KEY_SHIFT}, /* M */
+ {0x11, KEY_SHIFT}, /* N */
+ {0x12, KEY_SHIFT}, /* O */
+ {0x13, KEY_SHIFT}, /* P */
+ {0x14, KEY_SHIFT}, /* Q */
+ {0x15, KEY_SHIFT}, /* R */
+ {0x16, KEY_SHIFT}, /* S */
+ {0x17, KEY_SHIFT}, /* T */
+ {0x18, KEY_SHIFT}, /* U */
+ {0x19, KEY_SHIFT}, /* V */
+ {0x1a, KEY_SHIFT}, /* W */
+ {0x1b, KEY_SHIFT}, /* X */
+ {0x1c, KEY_SHIFT}, /* Y */
+ {0x1d, KEY_SHIFT}, /* Z */
+ {0x2f, 0}, /* [ */
+ {0x31, 0}, /* \ */
+ {0x30, 0}, /* ] */
+ {0x23, KEY_SHIFT}, /* ^ */
+ {0x2d, KEY_SHIFT}, /* _ */
+ {0x35, 0}, /* ` */
+ {0x04, 0}, /* a */
+ {0x05, 0}, /* b */
+ {0x06, 0}, /* c */
+ {0x07, 0}, /* d */
+ {0x08, 0}, /* e */
+ {0x09, 0}, /* f */
+ {0x0a, 0}, /* g */
+ {0x0b, 0}, /* h */
+ {0x0c, 0}, /* i */
+ {0x0d, 0}, /* j */
+ {0x0e, 0}, /* k */
+ {0x0f, 0}, /* l */
+ {0x10, 0}, /* m */
+ {0x11, 0}, /* n */
+ {0x12, 0}, /* o */
+ {0x13, 0}, /* p */
+ {0x14, 0}, /* q */
+ {0x15, 0}, /* r */
+ {0x16, 0}, /* s */
+ {0x17, 0}, /* t */
+ {0x18, 0}, /* u */
+ {0x19, 0}, /* v */
+ {0x1a, 0}, /* w */
+ {0x1b, 0}, /* x */
+ {0x1c, 0}, /* y */
+ {0x1d, 0}, /* z */
+ {0x2f, KEY_SHIFT}, /* { */
+ {0x31, KEY_SHIFT}, /* | */
+ {0x30, KEY_SHIFT}, /* } */
+ {0x35, KEY_SHIFT}, /* ~ */
+ {0,0}, /* DEL */
+
+ {0x3a, 0}, /* F1 */
+ {0x3b, 0}, /* F2 */
+ {0x3c, 0}, /* F3 */
+ {0x3d, 0}, /* F4 */
+ {0x3e, 0}, /* F5 */
+ {0x3f, 0}, /* F6 */
+ {0x40, 0}, /* F7 */
+ {0x41, 0}, /* F8 */
+ {0x42, 0}, /* F9 */
+ {0x43, 0}, /* F10 */
+ {0x44, 0}, /* F11 */
+ {0x45, 0}, /* F12 */
+
+ {0x46, 0}, /* PRINT_SCREEN */
+ {0x47, 0}, /* SCROLL_LOCK */
+ {0x39, 0}, /* CAPS_LOCK */
+ {0x53, 0}, /* NUM_LOCK */
+ {0x49, 0}, /* INSERT */
+ {0x4a, 0}, /* HOME */
+ {0x4b, 0}, /* PAGE_UP */
+ {0x4e, 0}, /* PAGE_DOWN */
+
+ {0x4f, 0}, /* RIGHT_ARROW */
+ {0x50, 0}, /* LEFT_ARROW */
+ {0x51, 0}, /* DOWN_ARROW */
+ {0x52, 0}, /* UP_ARROW */
+};
+
+#else
+/* UK keyboard */
+#define KEYMAP_SIZE (152)
+const KEYMAP keymap[KEYMAP_SIZE] = {
+ {0, 0}, /* NUL */
+ {0, 0}, /* SOH */
+ {0, 0}, /* STX */
+ {0, 0}, /* ETX */
+ {0, 0}, /* EOT */
+ {0, 0}, /* ENQ */
+ {0, 0}, /* ACK */
+ {0, 0}, /* BEL */
+ {0x2a, 0}, /* BS */ /* Keyboard Delete (Backspace) */
+ {0x2b, 0}, /* TAB */ /* Keyboard Tab */
+ {0x28, 0}, /* LF */ /* Keyboard Return (Enter) */
+ {0, 0}, /* VT */
+ {0, 0}, /* FF */
+ {0, 0}, /* CR */
+ {0, 0}, /* SO */
+ {0, 0}, /* SI */
+ {0, 0}, /* DEL */
+ {0, 0}, /* DC1 */
+ {0, 0}, /* DC2 */
+ {0, 0}, /* DC3 */
+ {0, 0}, /* DC4 */
+ {0, 0}, /* NAK */
+ {0, 0}, /* SYN */
+ {0, 0}, /* ETB */
+ {0, 0}, /* CAN */
+ {0, 0}, /* EM */
+ {0, 0}, /* SUB */
+ {0, 0}, /* ESC */
+ {0, 0}, /* FS */
+ {0, 0}, /* GS */
+ {0, 0}, /* RS */
+ {0, 0}, /* US */
+ {0x2c, 0}, /* */
+ {0x1e, KEY_SHIFT}, /* ! */
+ {0x1f, KEY_SHIFT}, /* " */
+ {0x32, 0}, /* # */
+ {0x21, KEY_SHIFT}, /* $ */
+ {0x22, KEY_SHIFT}, /* % */
+ {0x24, KEY_SHIFT}, /* & */
+ {0x34, 0}, /* ' */
+ {0x26, KEY_SHIFT}, /* ( */
+ {0x27, KEY_SHIFT}, /* ) */
+ {0x25, KEY_SHIFT}, /* * */
+ {0x2e, KEY_SHIFT}, /* + */
+ {0x36, 0}, /* , */
+ {0x2d, 0}, /* - */
+ {0x37, 0}, /* . */
+ {0x38, 0}, /* / */
+ {0x27, 0}, /* 0 */
+ {0x1e, 0}, /* 1 */
+ {0x1f, 0}, /* 2 */
+ {0x20, 0}, /* 3 */
+ {0x21, 0}, /* 4 */
+ {0x22, 0}, /* 5 */
+ {0x23, 0}, /* 6 */
+ {0x24, 0}, /* 7 */
+ {0x25, 0}, /* 8 */
+ {0x26, 0}, /* 9 */
+ {0x33, KEY_SHIFT}, /* : */
+ {0x33, 0}, /* ; */
+ {0x36, KEY_SHIFT}, /* < */
+ {0x2e, 0}, /* = */
+ {0x37, KEY_SHIFT}, /* > */
+ {0x38, KEY_SHIFT}, /* ? */
+ {0x34, KEY_SHIFT}, /* @ */
+ {0x04, KEY_SHIFT}, /* A */
+ {0x05, KEY_SHIFT}, /* B */
+ {0x06, KEY_SHIFT}, /* C */
+ {0x07, KEY_SHIFT}, /* D */
+ {0x08, KEY_SHIFT}, /* E */
+ {0x09, KEY_SHIFT}, /* F */
+ {0x0a, KEY_SHIFT}, /* G */
+ {0x0b, KEY_SHIFT}, /* H */
+ {0x0c, KEY_SHIFT}, /* I */
+ {0x0d, KEY_SHIFT}, /* J */
+ {0x0e, KEY_SHIFT}, /* K */
+ {0x0f, KEY_SHIFT}, /* L */
+ {0x10, KEY_SHIFT}, /* M */
+ {0x11, KEY_SHIFT}, /* N */
+ {0x12, KEY_SHIFT}, /* O */
+ {0x13, KEY_SHIFT}, /* P */
+ {0x14, KEY_SHIFT}, /* Q */
+ {0x15, KEY_SHIFT}, /* R */
+ {0x16, KEY_SHIFT}, /* S */
+ {0x17, KEY_SHIFT}, /* T */
+ {0x18, KEY_SHIFT}, /* U */
+ {0x19, KEY_SHIFT}, /* V */
+ {0x1a, KEY_SHIFT}, /* W */
+ {0x1b, KEY_SHIFT}, /* X */
+ {0x1c, KEY_SHIFT}, /* Y */
+ {0x1d, KEY_SHIFT}, /* Z */
+ {0x2f, 0}, /* [ */
+ {0x64, 0}, /* \ */
+ {0x30, 0}, /* ] */
+ {0x23, KEY_SHIFT}, /* ^ */
+ {0x2d, KEY_SHIFT}, /* _ */
+ {0x35, 0}, /* ` */
+ {0x04, 0}, /* a */
+ {0x05, 0}, /* b */
+ {0x06, 0}, /* c */
+ {0x07, 0}, /* d */
+ {0x08, 0}, /* e */
+ {0x09, 0}, /* f */
+ {0x0a, 0}, /* g */
+ {0x0b, 0}, /* h */
+ {0x0c, 0}, /* i */
+ {0x0d, 0}, /* j */
+ {0x0e, 0}, /* k */
+ {0x0f, 0}, /* l */
+ {0x10, 0}, /* m */
+ {0x11, 0}, /* n */
+ {0x12, 0}, /* o */
+ {0x13, 0}, /* p */
+ {0x14, 0}, /* q */
+ {0x15, 0}, /* r */
+ {0x16, 0}, /* s */
+ {0x17, 0}, /* t */
+ {0x18, 0}, /* u */
+ {0x19, 0}, /* v */
+ {0x1a, 0}, /* w */
+ {0x1b, 0}, /* x */
+ {0x1c, 0}, /* y */
+ {0x1d, 0}, /* z */
+ {0x2f, KEY_SHIFT}, /* { */
+ {0x64, KEY_SHIFT}, /* | */
+ {0x30, KEY_SHIFT}, /* } */
+ {0x32, KEY_SHIFT}, /* ~ */
+ {0,0}, /* DEL */
+
+ {0x3a, 0}, /* F1 */
+ {0x3b, 0}, /* F2 */
+ {0x3c, 0}, /* F3 */
+ {0x3d, 0}, /* F4 */
+ {0x3e, 0}, /* F5 */
+ {0x3f, 0}, /* F6 */
+ {0x40, 0}, /* F7 */
+ {0x41, 0}, /* F8 */
+ {0x42, 0}, /* F9 */
+ {0x43, 0}, /* F10 */
+ {0x44, 0}, /* F11 */
+ {0x45, 0}, /* F12 */
+
+ {0x46, 0}, /* PRINT_SCREEN */
+ {0x47, 0}, /* SCROLL_LOCK */
+ {0x39, 0}, /* CAPS_LOCK */
+ {0x53, 0}, /* NUM_LOCK */
+ {0x49, 0}, /* INSERT */
+ {0x4a, 0}, /* HOME */
+ {0x4b, 0}, /* PAGE_UP */
+ {0x4e, 0}, /* PAGE_DOWN */
+
+ {0x4f, 0}, /* RIGHT_ARROW */
+ {0x50, 0}, /* LEFT_ARROW */
+ {0x51, 0}, /* DOWN_ARROW */
+ {0x52, 0}, /* UP_ARROW */
+};
+#endif
+
+#endif
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/HIDTypes.h b/src/components/esp-nimble-cpp-1.3.3/src/HIDTypes.h
new file mode 100644
index 0000000..8ee31da
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/HIDTypes.h
@@ -0,0 +1,91 @@
+/* Copyright (c) 2010-2011 mbed.org, MIT License
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+* and associated documentation files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use, copy, modify, merge, publish,
+* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or
+* substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef USBCLASS_HID_TYPES
+#define USBCLASS_HID_TYPES
+
+#include
+
+/* */
+#define HID_VERSION_1_11 (0x0111)
+
+/* HID Class */
+#define HID_CLASS (3)
+#define HID_SUBCLASS_NONE (0)
+#define HID_PROTOCOL_NONE (0)
+
+/* Descriptors */
+#define HID_DESCRIPTOR (33)
+#define HID_DESCRIPTOR_LENGTH (0x09)
+#define REPORT_DESCRIPTOR (34)
+
+/* Class requests */
+#define GET_REPORT (0x1)
+#define GET_IDLE (0x2)
+#define SET_REPORT (0x9)
+#define SET_IDLE (0xa)
+
+/* HID Class Report Descriptor */
+/* Short items: size is 0, 1, 2 or 3 specifying 0, 1, 2 or 4 (four) bytes */
+/* of data as per HID Class standard */
+
+/* Main items */
+#define HIDINPUT(size) (0x80 | size)
+#define HIDOUTPUT(size) (0x90 | size)
+#define FEATURE(size) (0xb0 | size)
+#define COLLECTION(size) (0xa0 | size)
+#define END_COLLECTION(size) (0xc0 | size)
+
+/* Global items */
+#define USAGE_PAGE(size) (0x04 | size)
+#define LOGICAL_MINIMUM(size) (0x14 | size)
+#define LOGICAL_MAXIMUM(size) (0x24 | size)
+#define PHYSICAL_MINIMUM(size) (0x34 | size)
+#define PHYSICAL_MAXIMUM(size) (0x44 | size)
+#define UNIT_EXPONENT(size) (0x54 | size)
+#define UNIT(size) (0x64 | size)
+#define REPORT_SIZE(size) (0x74 | size) //bits
+#define REPORT_ID(size) (0x84 | size)
+#define REPORT_COUNT(size) (0x94 | size) //bytes
+#define PUSH(size) (0xa4 | size)
+#define POP(size) (0xb4 | size)
+
+/* Local items */
+#define USAGE(size) (0x08 | size)
+#define USAGE_MINIMUM(size) (0x18 | size)
+#define USAGE_MAXIMUM(size) (0x28 | size)
+#define DESIGNATOR_INDEX(size) (0x38 | size)
+#define DESIGNATOR_MINIMUM(size) (0x48 | size)
+#define DESIGNATOR_MAXIMUM(size) (0x58 | size)
+#define STRING_INDEX(size) (0x78 | size)
+#define STRING_MINIMUM(size) (0x88 | size)
+#define STRING_MAXIMUM(size) (0x98 | size)
+#define DELIMITER(size) (0xa8 | size)
+
+/* HID Report */
+/* Where report IDs are used the first byte of 'data' will be the */
+/* report ID and 'length' will include this report ID byte. */
+
+#define MAX_HID_REPORT_SIZE (64)
+
+typedef struct {
+ uint32_t length;
+ uint8_t data[MAX_HID_REPORT_SIZE];
+} HID_REPORT;
+
+#endif
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/NimBLE2904.cpp b/src/components/esp-nimble-cpp-1.3.3/src/NimBLE2904.cpp
new file mode 100644
index 0000000..282eff5
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/NimBLE2904.cpp
@@ -0,0 +1,86 @@
+/*
+ * NimBLE2904.cpp
+ *
+ * Created: on March 13, 2020
+ * Author H2zero
+ *
+ * Originally:
+ *
+ * BLE2904.cpp
+ *
+ * Created on: Dec 23, 2017
+ * Author: kolban
+ */
+
+/*
+ * See also:
+ * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.characteristic_presentation_format.xml
+ */
+#include "nimconfig.h"
+#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
+
+#include "NimBLE2904.h"
+
+
+NimBLE2904::NimBLE2904(NimBLECharacteristic* pCharacterisitic)
+: NimBLEDescriptor(NimBLEUUID((uint16_t) 0x2904),
+ BLE_GATT_CHR_F_READ,
+ sizeof(BLE2904_Data),
+ pCharacterisitic)
+{
+ m_data.m_format = 0;
+ m_data.m_exponent = 0;
+ m_data.m_namespace = 1; // 1 = Bluetooth SIG Assigned Numbers
+ m_data.m_unit = 0;
+ m_data.m_description = 0;
+ setValue((uint8_t*) &m_data, sizeof(m_data));
+} // BLE2904
+
+
+/**
+ * @brief Set the description.
+ */
+void NimBLE2904::setDescription(uint16_t description) {
+ m_data.m_description = description;
+ setValue((uint8_t*) &m_data, sizeof(m_data));
+}
+
+
+/**
+ * @brief Set the exponent.
+ */
+void NimBLE2904::setExponent(int8_t exponent) {
+ m_data.m_exponent = exponent;
+ setValue((uint8_t*) &m_data, sizeof(m_data));
+} // setExponent
+
+
+/**
+ * @brief Set the format.
+ */
+void NimBLE2904::setFormat(uint8_t format) {
+ m_data.m_format = format;
+ setValue((uint8_t*) &m_data, sizeof(m_data));
+} // setFormat
+
+
+/**
+ * @brief Set the namespace.
+ */
+void NimBLE2904::setNamespace(uint8_t namespace_value) {
+ m_data.m_namespace = namespace_value;
+ setValue((uint8_t*) &m_data, sizeof(m_data));
+} // setNamespace
+
+
+/**
+ * @brief Set the units for this value. It should be one of the encoded values defined here:
+ * https://www.bluetooth.com/specifications/assigned-numbers/units
+ * @param [in] unit The type of units of this characteristic as defined by assigned numbers.
+ */
+void NimBLE2904::setUnit(uint16_t unit) {
+ m_data.m_unit = unit;
+ setValue((uint8_t*) &m_data, sizeof(m_data));
+} // setUnit
+
+#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/NimBLE2904.h b/src/components/esp-nimble-cpp-1.3.3/src/NimBLE2904.h
new file mode 100644
index 0000000..29dde51
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/NimBLE2904.h
@@ -0,0 +1,83 @@
+/*
+ * NimBLE2904.h
+ *
+ * Created: on March 13, 2020
+ * Author H2zero
+ *
+ * Originally:
+ *
+ * BLE2904.h
+ *
+ * Created on: Dec 23, 2017
+ * Author: kolban
+ */
+
+#ifndef MAIN_NIMBLE2904_H_
+#define MAIN_NIMBLE2904_H_
+#include "nimconfig.h"
+#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
+
+#include "NimBLEDescriptor.h"
+
+struct BLE2904_Data {
+ uint8_t m_format;
+ int8_t m_exponent;
+ uint16_t m_unit; // See https://www.bluetooth.com/specifications/assigned-numbers/units
+ uint8_t m_namespace;
+ uint16_t m_description;
+
+} __attribute__((packed));
+
+
+/**
+ * @brief Descriptor for Characteristic Presentation Format.
+ *
+ * This is a convenience descriptor for the Characteristic Presentation Format which has a UUID of 0x2904.
+ *
+ * See also:
+ * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.characteristic_presentation_format.xml
+ */
+class NimBLE2904: public NimBLEDescriptor {
+public:
+ NimBLE2904(NimBLECharacteristic* pCharacterisitic = nullptr);
+ static const uint8_t FORMAT_BOOLEAN = 1;
+ static const uint8_t FORMAT_UINT2 = 2;
+ static const uint8_t FORMAT_UINT4 = 3;
+ static const uint8_t FORMAT_UINT8 = 4;
+ static const uint8_t FORMAT_UINT12 = 5;
+ static const uint8_t FORMAT_UINT16 = 6;
+ static const uint8_t FORMAT_UINT24 = 7;
+ static const uint8_t FORMAT_UINT32 = 8;
+ static const uint8_t FORMAT_UINT48 = 9;
+ static const uint8_t FORMAT_UINT64 = 10;
+ static const uint8_t FORMAT_UINT128 = 11;
+ static const uint8_t FORMAT_SINT8 = 12;
+ static const uint8_t FORMAT_SINT12 = 13;
+ static const uint8_t FORMAT_SINT16 = 14;
+ static const uint8_t FORMAT_SINT24 = 15;
+ static const uint8_t FORMAT_SINT32 = 16;
+ static const uint8_t FORMAT_SINT48 = 17;
+ static const uint8_t FORMAT_SINT64 = 18;
+ static const uint8_t FORMAT_SINT128 = 19;
+ static const uint8_t FORMAT_FLOAT32 = 20;
+ static const uint8_t FORMAT_FLOAT64 = 21;
+ static const uint8_t FORMAT_SFLOAT16 = 22;
+ static const uint8_t FORMAT_SFLOAT32 = 23;
+ static const uint8_t FORMAT_IEEE20601 = 24;
+ static const uint8_t FORMAT_UTF8 = 25;
+ static const uint8_t FORMAT_UTF16 = 26;
+ static const uint8_t FORMAT_OPAQUE = 27;
+
+ void setDescription(uint16_t);
+ void setExponent(int8_t exponent);
+ void setFormat(uint8_t format);
+ void setNamespace(uint8_t namespace_value);
+ void setUnit(uint16_t unit);
+
+private:
+ friend class NimBLECharacteristic;
+ BLE2904_Data m_data;
+}; // BLE2904
+
+#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
+#endif /* MAIN_NIMBLE2904_H_ */
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/NimBLEAddress.cpp b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEAddress.cpp
new file mode 100644
index 0000000..b8df5ac
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEAddress.cpp
@@ -0,0 +1,197 @@
+/*
+ * NimBLEAddress.cpp
+ *
+ * Created: on Jan 24 2020
+ * Author H2zero
+ *
+ * Originally:
+ *
+ * BLEAddress.cpp
+ *
+ * Created on: Jul 2, 2017
+ * Author: kolban
+ */
+#include "nimconfig.h"
+#if defined(CONFIG_BT_ENABLED)
+
+#include
+
+#include "NimBLEAddress.h"
+#include "NimBLEUtils.h"
+#include "NimBLELog.h"
+
+static const char* LOG_TAG = "NimBLEAddress";
+
+/*************************************************
+ * NOTE: NimBLE address bytes are in INVERSE ORDER!
+ * We will accomodate that fact in these methods.
+*************************************************/
+
+/**
+ * @brief Create an address from the native NimBLE representation.
+ * @param [in] address The native NimBLE address.
+ */
+NimBLEAddress::NimBLEAddress(ble_addr_t address) {
+ memcpy(m_address, address.val, 6);
+ m_addrType = address.type;
+} // NimBLEAddress
+
+
+/**
+ * @brief Create a blank address, i.e. 00:00:00:00:00:00, type 0.
+ */
+NimBLEAddress::NimBLEAddress() {
+ NimBLEAddress("");
+} // NimBLEAddress
+
+
+/**
+ * @brief Create an address from a hex string
+ *
+ * A hex string is of the format:
+ * ```
+ * 00:00:00:00:00:00
+ * ```
+ * which is 17 characters in length.
+ *
+ * @param [in] stringAddress The hex string representation of the address.
+ * @param [in] type The type of the address.
+ */
+NimBLEAddress::NimBLEAddress(const std::string &stringAddress, uint8_t type) {
+ m_addrType = type;
+
+ if (stringAddress.length() == 0) {
+ memset(m_address, 0, 6);
+ return;
+ }
+
+ if (stringAddress.length() == 6) {
+ std::reverse_copy(stringAddress.data(), stringAddress.data() + 6, m_address);
+ return;
+ }
+
+ if (stringAddress.length() != 17) {
+ memset(m_address, 0, sizeof m_address); // "00:00:00:00:00:00" represents an invalid address
+ NIMBLE_LOGD(LOG_TAG, "Invalid address '%s'", stringAddress.c_str());
+ return;
+ }
+
+ int data[6];
+ if(sscanf(stringAddress.c_str(), "%x:%x:%x:%x:%x:%x", &data[5], &data[4], &data[3], &data[2], &data[1], &data[0]) != 6) {
+ memset(m_address, 0, sizeof m_address); // "00:00:00:00:00:00" represents an invalid address
+ NIMBLE_LOGD(LOG_TAG, "Invalid address '%s'", stringAddress.c_str());
+ }
+ for(size_t index = 0; index < sizeof m_address; index++) {
+ m_address[index] = data[index];
+ }
+} // NimBLEAddress
+
+
+/**
+ * @brief Constructor for compatibility with bluedroid esp library using native ESP representation.
+ * @param [in] address A uint8_t[6] or esp_bd_addr_t containing the address.
+ * @param [in] type The type of the address.
+ */
+NimBLEAddress::NimBLEAddress(uint8_t address[6], uint8_t type) {
+ std::reverse_copy(address, address + sizeof m_address, m_address);
+ m_addrType = type;
+} // NimBLEAddress
+
+
+/**
+ * @brief Constructor for address using a hex value.\n
+ * Use the same byte order, so use 0xa4c1385def16 for "a4:c1:38:5d:ef:16"
+ * @param [in] address uint64_t containing the address.
+ * @param [in] type The type of the address.
+ */
+NimBLEAddress::NimBLEAddress(const uint64_t &address, uint8_t type) {
+ memcpy(m_address, &address, sizeof m_address);
+ m_addrType = type;
+} // NimBLEAddress
+
+
+/**
+ * @brief Determine if this address equals another.
+ * @param [in] otherAddress The other address to compare against.
+ * @return True if the addresses are equal.
+ */
+bool NimBLEAddress::equals(const NimBLEAddress &otherAddress) const {
+ return *this == otherAddress;
+} // equals
+
+
+/**
+ * @brief Get the native representation of the address.
+ * @return a pointer to the uint8_t[6] array of the address.
+ */
+const uint8_t *NimBLEAddress::getNative() const {
+ return m_address;
+} // getNative
+
+
+/**
+ * @brief Get the address type.
+ * @return The address type.
+ */
+uint8_t NimBLEAddress::getType() const {
+ return m_addrType;
+} // getType
+
+
+/**
+ * @brief Convert a BLE address to a string.
+ *
+ * A string representation of an address is in the format:
+ *
+ * ```
+ * xx:xx:xx:xx:xx:xx
+ * ```
+ *
+ * @return The string representation of the address.
+ * @deprecated Use std::string() operator instead.
+ */
+std::string NimBLEAddress::toString() const {
+ return std::string(*this);
+} // toString
+
+
+/**
+ * @brief Convienience operator to check if this address is equal to another.
+ */
+bool NimBLEAddress::operator ==(const NimBLEAddress & rhs) const {
+ return memcmp(rhs.m_address, m_address, sizeof m_address) == 0;
+} // operator ==
+
+
+/**
+ * @brief Convienience operator to check if this address is not equal to another.
+ */
+bool NimBLEAddress::operator !=(const NimBLEAddress & rhs) const {
+ return !this->operator==(rhs);
+} // operator !=
+
+
+/**
+ * @brief Convienience operator to convert this address to string representation.
+ * @details This allows passing NimBLEAddress to functions
+ * that accept std::string and/or or it's methods as a parameter.
+ */
+NimBLEAddress::operator std::string() const {
+ char buffer[18];
+ snprintf(buffer, sizeof(buffer), "%02x:%02x:%02x:%02x:%02x:%02x",
+ m_address[5], m_address[4], m_address[3],
+ m_address[2], m_address[1], m_address[0]);
+ return std::string(buffer);
+} // operator std::string
+
+
+/**
+ * @brief Convienience operator to convert the native address representation to uint_64.
+ */
+NimBLEAddress::operator uint64_t() const {
+ uint64_t address = 0;
+ memcpy(&address, m_address, sizeof m_address);
+ return address;
+} // operator uint64_t
+
+#endif
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/NimBLEAddress.h b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEAddress.h
new file mode 100644
index 0000000..a6e10a0
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEAddress.h
@@ -0,0 +1,62 @@
+/*
+ * NimBLEAddress.h
+ *
+ * Created: on Jan 24 2020
+ * Author H2zero
+ *
+ * Originally:
+ *
+ * BLEAddress.h
+ *
+ * Created on: Jul 2, 2017
+ * Author: kolban
+ */
+
+#ifndef COMPONENTS_NIMBLEADDRESS_H_
+#define COMPONENTS_NIMBLEADDRESS_H_
+#include "nimconfig.h"
+#if defined(CONFIG_BT_ENABLED)
+
+#if defined(CONFIG_NIMBLE_CPP_IDF)
+#include "nimble/ble.h"
+#else
+#include "nimble/nimble/include/nimble/ble.h"
+#endif
+
+/**** FIX COMPILATION ****/
+#undef min
+#undef max
+/**************************/
+
+#include
+#include
+
+/**
+ * @brief A %BLE device address.
+ *
+ * Every %BLE device has a unique address which can be used to identify it and form connections.
+ */
+class NimBLEAddress {
+public:
+ NimBLEAddress();
+ NimBLEAddress(ble_addr_t address);
+ NimBLEAddress(uint8_t address[6], uint8_t type = BLE_ADDR_PUBLIC);
+ NimBLEAddress(const std::string &stringAddress, uint8_t type = BLE_ADDR_PUBLIC);
+ NimBLEAddress(const uint64_t &address, uint8_t type = BLE_ADDR_PUBLIC);
+ bool equals(const NimBLEAddress &otherAddress) const;
+ const uint8_t* getNative() const;
+ std::string toString() const;
+ uint8_t getType() const;
+
+ bool operator ==(const NimBLEAddress & rhs) const;
+ bool operator !=(const NimBLEAddress & rhs) const;
+ operator std::string() const;
+ operator uint64_t() const;
+
+private:
+ uint8_t m_address[6];
+ uint8_t m_addrType;
+};
+
+#endif /* CONFIG_BT_ENABLED */
+#endif /* COMPONENTS_NIMBLEADDRESS_H_ */
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/NimBLEAdvertisedDevice.cpp b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEAdvertisedDevice.cpp
new file mode 100644
index 0000000..01dd75d
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEAdvertisedDevice.cpp
@@ -0,0 +1,785 @@
+/*
+ * NimBLEAdvertisedDevice.cpp
+ *
+ * Created: on Jan 24 2020
+ * Author H2zero
+ *
+ * Originally:
+ *
+ * BLEAdvertisedDevice.cpp
+ *
+ * Created on: Jul 3, 2017
+ * Author: kolban
+ */
+
+#include "nimconfig.h"
+#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
+
+#include "NimBLEDevice.h"
+#include "NimBLEAdvertisedDevice.h"
+#include "NimBLEUtils.h"
+#include "NimBLELog.h"
+
+static const char* LOG_TAG = "NimBLEAdvertisedDevice";
+
+
+/**
+ * @brief Constructor
+ */
+NimBLEAdvertisedDevice::NimBLEAdvertisedDevice() :
+ m_payload(62,0)
+{
+ m_advType = 0;
+ m_rssi = -9999;
+ m_callbackSent = false;
+ m_timestamp = 0;
+ m_advLength = 0;
+} // NimBLEAdvertisedDevice
+
+
+/**
+ * @brief Get the address of the advertising device.
+ * @return The address of the advertised device.
+ */
+NimBLEAddress NimBLEAdvertisedDevice::getAddress() {
+ return m_address;
+} // getAddress
+
+
+/**
+ * @brief Get the advertisement type.
+ * @return The advertising type the device is reporting:
+ * * BLE_HCI_ADV_TYPE_ADV_IND (0) - indirect advertising
+ * * BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD (1) - direct advertisng - high duty cycle
+ * * BLE_HCI_ADV_TYPE_ADV_SCAN_IND (2) - indirect scan response
+ * * BLE_HCI_ADV_TYPE_ADV_NONCONN_IND (3) - indirect advertisng - not connectable
+ * * BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_LD (4) - direct advertising - low duty cycle
+ */
+uint8_t NimBLEAdvertisedDevice::getAdvType() {
+ return m_advType;
+} // getAdvType
+
+
+/**
+ * @brief Get the appearance.
+ *
+ * A %BLE device can declare its own appearance. The appearance is how it would like to be shown to an end user
+ * typcially in the form of an icon.
+ *
+ * @return The appearance of the advertised device.
+ */
+uint16_t NimBLEAdvertisedDevice::getAppearance() {
+ 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() {
+ 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() {
+ 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
+
+
+/**
+ * @brief Get the RSSI.
+ * @return The RSSI of the advertised device.
+ */
+int NimBLEAdvertisedDevice::getRSSI() {
+ return m_rssi;
+} // getRSSI
+
+
+/**
+ * @brief Get the scan object that created this advertised device.
+ * @return The scan object.
+ */
+NimBLEScan* NimBLEAdvertisedDevice::getScan() {
+ return NimBLEDevice::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 index of the service data requested.
+ * @return The advertised service data or empty string if no data.
+ */
+std::string NimBLEAdvertisedDevice::getServiceData(uint8_t index) {
+ 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 "";
+} //getServiceData
+
+
+/**
+ * @brief Get the service data.
+ * @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) {
+ 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_LOGI(LOG_TAG, "No service data found");
+ return "";
+} //getServiceData
+
+
+/**
+ * @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) {
+ 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 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() {
+ 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 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) {
+ 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 NimBLEUUID("");
+} // getServiceUUID
+
+
+/**
+ * @brief Get the number of services advertised
+ * @return The count of services in the advertising packet.
+ */
+size_t NimBLEAdvertisedDevice::getServiceUUIDCount() {
+ 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) {
+ size_t count = getServiceUUIDCount();
+ for(size_t i = 0; i < count; i++) {
+ if(uuid == getServiceUUID(i)) {
+ return true;
+ }
+ }
+
+ return false;
+} // isAdvertisingService
+
+
+/**
+ * @brief Get the TX Power.
+ * @return The TX Power of the advertised device.
+ */
+int8_t NimBLEAdvertisedDevice::getTXPower() {
+ 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 findAdvField(BLE_HS_ADV_TYPE_APPEARANCE) > 0;
+} // haveAppearance
+
+
+/**
+ * @brief Does this advertisement have manufacturer data?
+ * @return True if there is manufacturer data present.
+ */
+bool NimBLEAdvertisedDevice::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 findAdvField(BLE_HS_ADV_TYPE_COMP_NAME) > 0 ||
+ findAdvField(BLE_HS_ADV_TYPE_INCOMP_NAME) > 0;
+} // haveName
+
+
+/**
+ * @brief Does this advertisement have a signal strength value?
+ * @return True if there is a signal strength value present.
+ */
+bool NimBLEAdvertisedDevice::haveRSSI() {
+ return m_rssi != -9999;
+} // haveRSSI
+
+
+/**
+ * @brief Does this advertisement have a service data value?
+ * @return True if there is a service data value present.
+ */
+bool NimBLEAdvertisedDevice::haveServiceData() {
+ return getServiceDataCount() > 0;
+} // haveServiceData
+
+
+/**
+ * @brief Does this advertisement have a service UUID value?
+ * @return True if there is a service UUID value present.
+ */
+bool NimBLEAdvertisedDevice::haveServiceUUID() {
+ return getServiceUUIDCount() > 0;
+} // haveServiceUUID
+
+
+/**
+ * @brief Does this advertisement have a transmission power value?
+ * @return True if there is a transmission power value present.
+ */
+bool NimBLEAdvertisedDevice::haveTXPower() {
+ return findAdvField(BLE_HS_ADV_TYPE_TX_PWR_LVL) > 0;
+} // haveTXPower
+
+
+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;
+ }
+
+ while (length > 1) {
+ field = (ble_hs_adv_field*)&m_payload[data];
+
+ if (field->length >= length) {
+ return count;
+ }
+
+ 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;
+
+ case BLE_HS_ADV_TYPE_INCOMP_UUIDS32:
+ case BLE_HS_ADV_TYPE_COMP_UUIDS32:
+ count += field->length / 4;
+ break;
+
+ case BLE_HS_ADV_TYPE_INCOMP_UUIDS128:
+ case BLE_HS_ADV_TYPE_COMP_UUIDS128:
+ count += field->length / 16;
+ break;
+
+ case BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR:
+ case BLE_HS_ADV_TYPE_RANDOM_TGT_ADDR:
+ count += field->length / 6;
+ break;
+
+ default:
+ count++;
+ break;
+ }
+
+ if(data_loc != nullptr) {
+ if(index == 0 || count >= index) {
+ break;
+ }
+ }
+ }
+
+ length -= 1 + field->length;
+ data += 1 + field->length;
+ }
+
+ if(data_loc != nullptr && field != nullptr) {
+ *data_loc = data;
+ }
+
+ return count;
+}
+
+
+/**
+ * @brief Set the address of the advertised device.
+ * @param [in] address The address of the advertised device.
+ */
+void NimBLEAdvertisedDevice::setAddress(NimBLEAddress address) {
+ m_address = address;
+} // setAddress
+
+
+/**
+ * @brief Set the adFlag for this device.
+ * @param [in] advType The advertisement flag data from the advertisement.
+ */
+void NimBLEAdvertisedDevice::setAdvType(uint8_t advType) {
+ m_advType = advType;
+} // setAdvType
+
+
+/**
+ * @brief Set the RSSI for this device.
+ * @param [in] rssi The RSSI of the discovered device.
+ */
+void NimBLEAdvertisedDevice::setRSSI(int rssi) {
+ m_rssi = rssi;
+} // setRSSI
+
+
+/**
+ * @brief Create a string representation of this device.
+ * @return A string representation of this device.
+ */
+std::string NimBLEAdvertisedDevice::toString() {
+ std::string res = "Name: " + getName() + ", Address: " + getAddress().toString();
+
+ if (haveAppearance()) {
+ char val[6];
+ snprintf(val, sizeof(val), "%d", getAppearance());
+ res += ", appearance: ";
+ res += val;
+ }
+
+ if (haveManufacturerData()) {
+ char *pHex = NimBLEUtils::buildHexData(nullptr, (uint8_t*)getManufacturerData().data(), getManufacturerData().length());
+ res += ", manufacturer data: ";
+ res += pHex;
+ free(pHex);
+ }
+
+ if (haveServiceUUID()) {
+ res += ", serviceUUID: " + getServiceUUID().toString();
+ }
+
+ if (haveTXPower()) {
+ char val[5];
+ snprintf(val, sizeof(val), "%d", getTXPower());
+ res += ", txPower: ";
+ res += val;
+ }
+
+ if(haveServiceData()) {
+ size_t count = getServiceDataCount();
+ res += "\nService Data:";
+ for(size_t i = 0; i < count; i++) {
+ res += "\nUUID: " + std::string(getServiceDataUUID(i));
+ res += ", Data: " + getServiceData(i);
+ }
+ }
+
+ return res;
+
+} // toString
+
+
+/**
+ * @brief Get the payload advertised by the device.
+ * @return The advertisement payload.
+ */
+uint8_t* NimBLEAdvertisedDevice::getPayload() {
+ 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(const 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:
+ * * BLE_ADDR_PUBLIC (0x00)
+ * * BLE_ADDR_RANDOM (0x01)
+ * * BLE_ADDR_PUBLIC_ID (0x02)
+ * * BLE_ADDR_RANDOM_ID (0x03)
+ */
+uint8_t NimBLEAdvertisedDevice::getAddressType() {
+ return m_address.getType();
+} // getAddressType
+
+
+/**
+ * @brief Get the timeStamp of when the device last advertised.
+ * @return The timeStamp of when the device was last seen.
+ */
+time_t NimBLEAdvertisedDevice::getTimestamp() {
+ return m_timestamp;
+} // getTimestamp
+
+
+/**
+ * @brief Get the length of the payload advertised by the device.
+ * @return The size of the payload in bytes.
+ */
+size_t NimBLEAdvertisedDevice::getPayloadLength() {
+ return m_payload.size();
+} // getPayloadLength
+
+#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
+
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/NimBLEAdvertisedDevice.h b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEAdvertisedDevice.h
new file mode 100644
index 0000000..39410e6
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEAdvertisedDevice.h
@@ -0,0 +1,177 @@
+/*
+ * NimBLEAdvertisedDevice.h
+ *
+ * Created: on Jan 24 2020
+ * Author H2zero
+ *
+ * Originally:
+ *
+ * BLEAdvertisedDevice.h
+ *
+ * Created on: Jul 3, 2017
+ * Author: kolban
+ */
+
+#ifndef COMPONENTS_NIMBLEADVERTISEDDEVICE_H_
+#define COMPONENTS_NIMBLEADVERTISEDDEVICE_H_
+#include "nimconfig.h"
+#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
+
+#include "NimBLEAddress.h"
+#include "NimBLEScan.h"
+#include "NimBLEUUID.h"
+
+#if defined(CONFIG_NIMBLE_CPP_IDF)
+#include "host/ble_hs_adv.h"
+#else
+#include "nimble/nimble/host/include/host/ble_hs_adv.h"
+#endif
+
+#include
+#include
+#include
+
+
+class NimBLEScan;
+/**
+ * @brief A representation of a %BLE advertised device found by a scan.
+ *
+ * When we perform a %BLE scan, the result will be a set of devices that are advertising. This
+ * class provides a model of a detected device.
+ */
+class NimBLEAdvertisedDevice {
+public:
+ NimBLEAdvertisedDevice();
+
+ 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 .
+ * @tparam T The type to convert the data to.
+ * @param [in] skipSizeCheck If true it will skip checking if the data size is less than sizeof() .
+ * @return The data converted to or NULL if skipSizeCheck is false and the data is
+ * less than sizeof() .
+ * @details Use: getManufacturerData(skipSizeCheck);
+ */
+ template
+ T getManufacturerData(bool skipSizeCheck = false) {
+ std::string data = getManufacturerData();
+ if(!skipSizeCheck && data.size() < sizeof(T)) return T();
+ const char *pData = data.data();
+ return *((T *)pData);
+ }
+
+ std::string getName();
+ int getRSSI();
+ NimBLEScan* getScan();
+ size_t getServiceDataCount();
+ std::string getServiceData(uint8_t index = 0);
+ std::string getServiceData(const NimBLEUUID &uuid);
+
+ /**
+ * @brief A template to convert the service data to .
+ * @tparam T The type to convert the data to.
+ * @param [in] index The vector index of the service data requested.
+ * @param [in] skipSizeCheck If true it will skip checking if the data size is less than sizeof() .
+ * @return The data converted to or NULL if skipSizeCheck is false and the data is
+ * less than sizeof() .
+ * @details Use: getServiceData(skipSizeCheck);
+ */
+ template
+ T getServiceData(uint8_t index = 0, bool skipSizeCheck = false) {
+ std::string data = getServiceData(index);
+ if(!skipSizeCheck && data.size() < sizeof(T)) return T();
+ const char *pData = data.data();
+ return *((T *)pData);
+ }
+
+ /**
+ * @brief A template to convert the service data to .
+ * @tparam T The type to convert the data to.
+ * @param [in] uuid The uuid of the service data requested.
+ * @param [in] skipSizeCheck If true it will skip checking if the data size is less than sizeof() .
+ * @return The data converted to or NULL if skipSizeCheck is false and the data is
+ * less than sizeof() .
+ * @details Use: getServiceData(skipSizeCheck);
+ */
+ template
+ T getServiceData(const NimBLEUUID &uuid, bool skipSizeCheck = false) {
+ std::string data = getServiceData(uuid);
+ if(!skipSizeCheck && data.size() < sizeof(T)) return T();
+ const char *pData = data.data();
+ return *((T *)pData);
+ }
+
+ 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);
+ bool haveAppearance();
+ bool haveManufacturerData();
+ bool haveName();
+ bool haveRSSI();
+ bool haveServiceData();
+ bool haveServiceUUID();
+ bool haveTXPower();
+ bool haveConnParams();
+ bool haveAdvInterval();
+ bool haveTargetAddress();
+ bool haveURI();
+ std::string toString();
+
+private:
+ friend class NimBLEScan;
+
+ void setAddress(NimBLEAddress address);
+ void setAdvType(uint8_t advType);
+ void setPayload(const 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;
+ int m_rssi;
+ time_t m_timestamp;
+ bool m_callbackSent;
+ uint8_t m_advLength;
+
+ std::vector m_payload;
+};
+
+/**
+ * @brief A callback handler for callbacks associated device scanning.
+ *
+ * When we are performing a scan as a %BLE client, we may wish to know when a new device that is advertising
+ * has been found. This class can be sub-classed and registered such that when a scan is performed and
+ * a new advertised device has been found, we will be called back to be notified.
+ */
+class NimBLEAdvertisedDeviceCallbacks {
+public:
+ virtual ~NimBLEAdvertisedDeviceCallbacks() {}
+ /**
+ * @brief Called when a new scan result is detected.
+ *
+ * As we are scanning, we will find new devices. When found, this call back is invoked with a reference to the
+ * device that was found. During any individual scan, a device will only be detected one time.
+ */
+ virtual void onResult(NimBLEAdvertisedDevice* advertisedDevice) = 0;
+};
+
+#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_OBSERVER */
+#endif /* COMPONENTS_NIMBLEADVERTISEDDEVICE_H_ */
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/NimBLEAdvertising.cpp b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEAdvertising.cpp
new file mode 100644
index 0000000..a804130
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEAdvertising.cpp
@@ -0,0 +1,1029 @@
+/*
+ * NimBLEAdvertising.cpp
+ *
+ * Created: on March 3, 2020
+ * Author H2zero
+ *
+ * Originally:
+ *
+ * BLEAdvertising.cpp
+ *
+ * This class encapsulates advertising a BLE Server.
+ * Created on: Jun 21, 2017
+ * Author: kolban
+ *
+ */
+#include "nimconfig.h"
+#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
+
+#if defined(CONFIG_NIMBLE_CPP_IDF)
+#include "services/gap/ble_svc_gap.h"
+#else
+#include "nimble/nimble/host/services/gap/include/services/gap/ble_svc_gap.h"
+#endif
+#include "NimBLEAdvertising.h"
+#include "NimBLEDevice.h"
+#include "NimBLEServer.h"
+#include "NimBLEUtils.h"
+#include "NimBLELog.h"
+
+static const char* LOG_TAG = "NimBLEAdvertising";
+
+
+/**
+ * @brief Construct a default advertising object.
+ */
+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 = NimBLEDevice::getPower();
+ m_advData.flags = (BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP);
+
+#if !defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
+ m_advParams.conn_mode = BLE_GAP_CONN_MODE_NON;
+#else
+ m_advParams.conn_mode = BLE_GAP_CONN_MODE_UND;
+#endif
+ m_advParams.disc_mode = BLE_GAP_DISC_MODE_GEN;
+ 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;
+ m_advCompCB = nullptr;
+} // reset
+
+
+/**
+ * @brief Add a service uuid to exposed list of services.
+ * @param [in] serviceUUID The UUID of the service to expose.
+ */
+void NimBLEAdvertising::addServiceUUID(const NimBLEUUID &serviceUUID) {
+ m_serviceUUIDs.push_back(serviceUUID);
+ m_advDataSet = false;
+} // addServiceUUID
+
+
+/**
+ * @brief Add a service uuid to exposed list of services.
+ * @param [in] serviceUUID The string representation of the service to expose.
+ */
+void NimBLEAdvertising::addServiceUUID(const char* serviceUUID) {
+ addServiceUUID(NimBLEUUID(serviceUUID));
+ m_advDataSet = false;
+} // addServiceUUID
+
+
+/**
+ * @brief Add a service uuid to exposed list of services.
+ * @param [in] serviceUUID The UUID of the service to expose.
+ */
+void NimBLEAdvertising::removeServiceUUID(const NimBLEUUID &serviceUUID) {
+ for(auto it = m_serviceUUIDs.begin(); it != m_serviceUUIDs.end(); ++it) {
+ if((*it) == serviceUUID) {
+ m_serviceUUIDs.erase(it);
+ break;
+ }
+ }
+ m_advDataSet = false;
+} // addServiceUUID
+
+
+/**
+ * @brief Set the device appearance in the advertising data.
+ * The codes for distinct appearances can be found here:\n
+ * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.gap.appearance.xml.
+ * @param [in] appearance The appearance of the device in the advertising data.
+ */
+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:
+ * * BLE_GAP_CONN_MODE_NON (0) - not connectable advertising
+ * * BLE_GAP_CONN_MODE_DIR (1) - directed connectable advertising
+ * * BLE_GAP_CONN_MODE_UND (2) - undirected connectable advertising
+ */
+void NimBLEAdvertising::setAdvertisementType(uint8_t adv_type){
+ m_advParams.conn_mode = adv_type;
+} // setAdvertisementType
+
+
+/**
+ * @brief Set the minimum advertising interval.
+ * @param [in] mininterval Minimum value for advertising interval in 0.625ms units, 0 = use default.
+ */
+void NimBLEAdvertising::setMinInterval(uint16_t mininterval) {
+ m_advParams.itvl_min = mininterval;
+} // setMinInterval
+
+
+/**
+ * @brief Set the maximum advertising interval.
+ * @param [in] maxinterval Maximum value for advertising interval in 0.625ms units, 0 = use default.
+ */
+void NimBLEAdvertising::setMaxInterval(uint16_t maxinterval) {
+ m_advParams.itvl_max = maxinterval;
+} // setMaxInterval
+
+
+/**
+ * @brief Set the advertised min connection interval preferred by this device.
+ * @param [in] mininterval the max interval value. Range = 0x0006 to 0x0C80.
+ * @details Values not within the range will cancel advertising of this data.\n
+ * Consumes 6 bytes of advertising space (combined with max interval).
+ */
+void NimBLEAdvertising::setMinPreferred(uint16_t mininterval) {
+ // invalid paramters, set the slave interval to null
+ if(mininterval < 0x0006 || mininterval > 0x0C80) {
+ m_advData.slave_itvl_range = nullptr;
+ return;
+ }
+
+ if(m_advData.slave_itvl_range == nullptr) {
+ m_advData.slave_itvl_range = m_slaveItvl;
+ }
+
+ m_slaveItvl[0] = mininterval;
+ m_slaveItvl[1] = mininterval >> 8;
+
+ uint16_t maxinterval = *(uint16_t*)(m_advData.slave_itvl_range+2);
+
+ // If mininterval is higher than the maxinterval make them the same
+ if(mininterval > maxinterval) {
+ m_slaveItvl[2] = m_slaveItvl[0];
+ m_slaveItvl[3] = m_slaveItvl[1];
+ }
+
+ m_advDataSet = false;
+} // setMinPreferred
+
+
+/**
+ * @brief Set the advertised max connection interval preferred by this device.
+ * @param [in] maxinterval the max interval value. Range = 0x0006 to 0x0C80.
+ * @details Values not within the range will cancel advertising of this data.\n
+ * Consumes 6 bytes of advertising space (combined with min interval).
+ */
+void NimBLEAdvertising::setMaxPreferred(uint16_t maxinterval) {
+ // invalid paramters, set the slave interval to null
+ if(maxinterval < 0x0006 || maxinterval > 0x0C80) {
+ m_advData.slave_itvl_range = nullptr;
+ return;
+ }
+ if(m_advData.slave_itvl_range == nullptr) {
+ m_advData.slave_itvl_range = m_slaveItvl;
+ }
+ m_slaveItvl[2] = maxinterval;
+ m_slaveItvl[3] = maxinterval >> 8;
+
+ uint16_t mininterval = *(uint16_t*)(m_advData.slave_itvl_range);
+
+ // If mininterval is higher than the maxinterval make them the same
+ if(mininterval > maxinterval) {
+ m_slaveItvl[0] = m_slaveItvl[2];
+ m_slaveItvl[1] = m_slaveItvl[3];
+ }
+
+ m_advDataSet = false;
+} // setMaxPreferred
+
+
+/**
+ * @brief Set if scan response is available.
+ * @param [in] set true = scan response available.
+ */
+void NimBLEAdvertising::setScanResponse(bool set) {
+ m_scanResp = set;
+ m_advDataSet = false;
+} // setScanResponse
+
+
+/**
+ * @brief Set the filtering for the scan filter.
+ * @param [in] scanRequestWhitelistOnly If true, only allow scan requests from those on the white list.
+ * @param [in] connectWhitelistOnly If true, only allow connections from those on the white list.
+ */
+void NimBLEAdvertising::setScanFilter(bool scanRequestWhitelistOnly, bool connectWhitelistOnly) {
+ NIMBLE_LOGD(LOG_TAG, ">> setScanFilter: scanRequestWhitelistOnly: %d, connectWhitelistOnly: %d",
+ scanRequestWhitelistOnly, connectWhitelistOnly);
+ if (!scanRequestWhitelistOnly && !connectWhitelistOnly) {
+ m_advParams.filter_policy = BLE_HCI_ADV_FILT_NONE;
+ NIMBLE_LOGD(LOG_TAG, "<< setScanFilter");
+ return;
+ }
+ if (scanRequestWhitelistOnly && !connectWhitelistOnly) {
+ m_advParams.filter_policy = BLE_HCI_ADV_FILT_SCAN;
+ NIMBLE_LOGD(LOG_TAG, "<< setScanFilter");
+ return;
+ }
+ if (!scanRequestWhitelistOnly && connectWhitelistOnly) {
+ m_advParams.filter_policy = BLE_HCI_ADV_FILT_CONN;
+ NIMBLE_LOGD(LOG_TAG, "<< setScanFilter");
+ return;
+ }
+ if (scanRequestWhitelistOnly && connectWhitelistOnly) {
+ m_advParams.filter_policy = BLE_HCI_ADV_FILT_BOTH;
+ NIMBLE_LOGD(LOG_TAG, "<< setScanFilter");
+ return;
+ }
+} // setScanFilter
+
+
+/**
+ * @brief Set the advertisement data that is to be published in a regular advertisement.
+ * @param [in] advertisementData The data to be advertised.
+ * @details The use of this function will replace any data set with addServiceUUID\n
+ * or setAppearance. If you wish for these to be advertised you must include them\n
+ * in the advertisementData parameter sent.
+ */
+
+void NimBLEAdvertising::setAdvertisementData(NimBLEAdvertisementData& advertisementData) {
+ NIMBLE_LOGD(LOG_TAG, ">> setAdvertisementData");
+ int rc = ble_gap_adv_set_data(
+ (uint8_t*)advertisementData.getPayload().data(),
+ advertisementData.getPayload().length());
+ if (rc != 0) {
+ NIMBLE_LOGE(LOG_TAG, "ble_gap_adv_set_data: %d %s",
+ rc, NimBLEUtils::returnCodeToString(rc));
+ }
+ m_customAdvData = true; // Set the flag that indicates we are using custom advertising data.
+ NIMBLE_LOGD(LOG_TAG, "<< setAdvertisementData");
+} // setAdvertisementData
+
+
+/**
+ * @brief Set the advertisement data that is to be published in a scan response.
+ * @param [in] advertisementData The data to be advertised.
+ * @details Calling this without also using setAdvertisementData will have no effect.\n
+ * When using custom scan response data you must also use custom advertisement data.
+ */
+void NimBLEAdvertising::setScanResponseData(NimBLEAdvertisementData& advertisementData) {
+ NIMBLE_LOGD(LOG_TAG, ">> setScanResponseData");
+ int rc = ble_gap_adv_rsp_set_data(
+ (uint8_t*)advertisementData.getPayload().data(),
+ advertisementData.getPayload().length());
+ if (rc != 0) {
+ NIMBLE_LOGE(LOG_TAG, "ble_gap_adv_rsp_set_data: %d %s",
+ rc, NimBLEUtils::returnCodeToString(rc));
+ }
+ m_customScanResponseData = true; // Set the flag that indicates we are using custom scan response data.
+ NIMBLE_LOGD(LOG_TAG, "<< setScanResponseData");
+} // setScanResponseData
+
+
+/**
+ * @brief Start advertising.
+ * @param [in] duration The duration, in seconds, to advertise, 0 == advertise forever.
+ * @param [in] advCompleteCB A pointer to a callback to be invoked when advertising ends.
+ * @return True if advertising started successfully.
+ */
+bool NimBLEAdvertising::start(uint32_t duration, void (*advCompleteCB)(NimBLEAdvertising *pAdv)) {
+ NIMBLE_LOGD(LOG_TAG, ">> Advertising start: customAdvData: %d, customScanResponseData: %d",
+ m_customAdvData, m_customScanResponseData);
+
+ // If Host is not synced we cannot start advertising.
+ if(!NimBLEDevice::m_synced) {
+ NIMBLE_LOGE(LOG_TAG, "Host reset, wait for sync.");
+ return false;
+ }
+
+#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
+ NimBLEServer* pServer = NimBLEDevice::getServer();
+ if(pServer != nullptr) {
+ if(!pServer->m_gattsStarted){
+ pServer->start();
+ } else if(pServer->getConnectedCount() >= NIMBLE_MAX_CONNECTIONS) {
+ NIMBLE_LOGE(LOG_TAG, "Max connections reached - not advertising");
+ return false;
+ }
+ }
+#endif
+
+ // If already advertising just return
+ if(ble_gap_adv_active()) {
+ NIMBLE_LOGW(LOG_TAG, "Advertising already active");
+ return false;
+ }
+
+ // Save the duration incase of host reset so we can restart with the same params
+ m_duration = duration;
+
+ if(duration == 0){
+ duration = BLE_HS_FOREVER;
+ }
+ else{
+ duration = duration*1000; // convert duration to milliseconds
+ }
+
+ m_advCompCB = advCompleteCB;
+
+ m_advParams.disc_mode = BLE_GAP_DISC_MODE_GEN;
+ m_advData.flags = (BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP);
+ if(m_advParams.conn_mode == BLE_GAP_CONN_MODE_NON) {
+ if(!m_scanResp) {
+ m_advParams.disc_mode = BLE_GAP_DISC_MODE_NON;
+ m_advData.flags = BLE_HS_ADV_F_BREDR_UNSUP;
+ }
+ }
+
+ int rc = 0;
+
+ 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 + BLE_HS_ADV_TX_PWR_LVL_LEN);
+
+ if(m_advData.slave_itvl_range != nullptr)
+ payloadLen += (2 + BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN);
+
+ for(auto &it : m_serviceUUIDs) {
+ if(it.getNative()->u.type == BLE_UUID_TYPE_16) {
+ int add = (m_advData.num_uuids16 > 0) ? 2 : 4;
+ if((payloadLen + add) > BLE_HS_ADV_MAX_SZ){
+ m_advData.uuids16_is_complete = 0;
+ continue;
+ }
+ payloadLen += add;
+
+ if(nullptr == (m_advData.uuids16 = (ble_uuid16_t*)realloc((void*)m_advData.uuids16,
+ (m_advData.num_uuids16 + 1) * sizeof(ble_uuid16_t))))
+ {
+ NIMBLE_LOGC(LOG_TAG, "Error, no mem");
+ abort();
+ }
+ memcpy((void*)&m_advData.uuids16[m_advData.num_uuids16],
+ &it.getNative()->u16, sizeof(ble_uuid16_t));
+ m_advData.uuids16_is_complete = 1;
+ m_advData.num_uuids16++;
+ }
+ if(it.getNative()->u.type == BLE_UUID_TYPE_32) {
+ int add = (m_advData.num_uuids32 > 0) ? 4 : 6;
+ if((payloadLen + add) > BLE_HS_ADV_MAX_SZ){
+ m_advData.uuids32_is_complete = 0;
+ continue;
+ }
+ payloadLen += add;
+
+ if(nullptr == (m_advData.uuids32 = (ble_uuid32_t*)realloc((void*)m_advData.uuids32,
+ (m_advData.num_uuids32 + 1) * sizeof(ble_uuid32_t))))
+ {
+ NIMBLE_LOGC(LOG_TAG, "Error, no mem");
+ abort();
+ }
+ memcpy((void*)&m_advData.uuids32[m_advData.num_uuids32],
+ &it.getNative()->u32, sizeof(ble_uuid32_t));
+ m_advData.uuids32_is_complete = 1;
+ m_advData.num_uuids32++;
+ }
+ if(it.getNative()->u.type == BLE_UUID_TYPE_128){
+ int add = (m_advData.num_uuids128 > 0) ? 16 : 18;
+ if((payloadLen + add) > BLE_HS_ADV_MAX_SZ){
+ m_advData.uuids128_is_complete = 0;
+ continue;
+ }
+ payloadLen += add;
+
+ if(nullptr == (m_advData.uuids128 = (ble_uuid128_t*)realloc((void*)m_advData.uuids128,
+ (m_advData.num_uuids128 + 1) * sizeof(ble_uuid128_t))))
+ {
+ NIMBLE_LOGC(LOG_TAG, "Error, no mem");
+ abort();
+ }
+ memcpy((void*)&m_advData.uuids128[m_advData.num_uuids128],
+ &it.getNative()->u128, sizeof(ble_uuid128_t));
+ m_advData.uuids128_is_complete = 1;
+ m_advData.num_uuids128++;
+ }
+ }
+
+ // 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 && !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) {
+ m_scanData.name_len = BLE_HS_ADV_MAX_SZ - 2;
+ m_scanData.name_is_complete = 0;
+ } else {
+ m_scanData.name_is_complete = 1;
+ }
+ m_advData.name = nullptr;
+ m_advData.name_len = 0;
+ m_advData.name_is_complete = 0;
+ } else {
+ if(m_advData.tx_pwr_lvl_is_present) {
+ m_advData.tx_pwr_lvl_is_present = 0;
+ payloadLen -= (2 + 1);
+ }
+ // if not using scan response just cut the name down
+ // leaving 2 bytes for the data specifier.
+ if(m_advData.name_len > (BLE_HS_ADV_MAX_SZ - payloadLen - 2)) {
+ m_advData.name_len = (BLE_HS_ADV_MAX_SZ - payloadLen - 2);
+ m_advData.name_is_complete = 0;
+ }
+ }
+ }
+
+ if(m_scanResp && !m_customScanResponseData) {
+ rc = ble_gap_adv_rsp_set_fields(&m_scanData);
+ switch(rc) {
+ case 0:
+ break;
+
+ case BLE_HS_EBUSY:
+ NIMBLE_LOGE(LOG_TAG, "Already advertising");
+ break;
+
+ case BLE_HS_EMSGSIZE:
+ NIMBLE_LOGE(LOG_TAG, "Scan data too long");
+ break;
+
+ default:
+ NIMBLE_LOGE(LOG_TAG, "Error setting scan response data; rc=%d, %s",
+ rc, NimBLEUtils::returnCodeToString(rc));
+ break;
+ }
+ }
+
+ if(rc == 0) {
+ rc = ble_gap_adv_set_fields(&m_advData);
+ switch(rc) {
+ case 0:
+ break;
+
+ case BLE_HS_EBUSY:
+ NIMBLE_LOGE(LOG_TAG, "Already advertising");
+ break;
+
+ case BLE_HS_EMSGSIZE:
+ NIMBLE_LOGE(LOG_TAG, "Advertisement data too long");
+ break;
+
+ default:
+ NIMBLE_LOGE(LOG_TAG, "Error setting advertisement data; rc=%d, %s",
+ rc, NimBLEUtils::returnCodeToString(rc));
+ break;
+ }
+ }
+
+ if(m_advData.num_uuids128 > 0) {
+ free((void*)m_advData.uuids128);
+ m_advData.uuids128 = nullptr;
+ m_advData.num_uuids128 = 0;
+ }
+
+ if(m_advData.num_uuids32 > 0) {
+ free((void*)m_advData.uuids32);
+ m_advData.uuids32 = nullptr;
+ m_advData.num_uuids32 = 0;
+ }
+
+ if(m_advData.num_uuids16 > 0) {
+ free((void*)m_advData.uuids16);
+ m_advData.uuids16 = nullptr;
+ m_advData.num_uuids16 = 0;
+ }
+
+ if(rc !=0) {
+ return false;
+ }
+
+ m_advDataSet = true;
+ }
+
+#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
+ rc = ble_gap_adv_start(NimBLEDevice::m_own_addr_type, NULL, duration,
+ &m_advParams,
+ (pServer != nullptr) ? NimBLEServer::handleGapEvent :
+ NimBLEAdvertising::handleGapEvent,
+ (pServer != nullptr) ? (void*)pServer : (void*)this);
+#else
+ rc = ble_gap_adv_start(NimBLEDevice::m_own_addr_type, NULL, duration,
+ &m_advParams, NimBLEAdvertising::handleGapEvent, this);
+#endif
+ switch(rc) {
+ case 0:
+ break;
+
+ case BLE_HS_EINVAL:
+ NIMBLE_LOGE(LOG_TAG, "Unable to advertise - Duration too long");
+ break;
+
+ case BLE_HS_EPREEMPTED:
+ NIMBLE_LOGE(LOG_TAG, "Unable to advertise - busy");
+ break;
+
+ case BLE_HS_ETIMEOUT_HCI:
+ case BLE_HS_EOS:
+ case BLE_HS_ECONTROLLER:
+ case BLE_HS_ENOTSYNCED:
+ NIMBLE_LOGE(LOG_TAG, "Unable to advertise - Host Reset");
+ break;
+
+ default:
+ NIMBLE_LOGE(LOG_TAG, "Error enabling advertising; rc=%d, %s",
+ rc, NimBLEUtils::returnCodeToString(rc));
+ break;
+ }
+
+ NIMBLE_LOGD(LOG_TAG, "<< Advertising start");
+ return (rc == 0);
+} // start
+
+
+/**
+ * @brief Stop advertising.
+ */
+void NimBLEAdvertising::stop() {
+ NIMBLE_LOGD(LOG_TAG, ">> stop");
+
+ int rc = ble_gap_adv_stop();
+ if (rc != 0 && rc != BLE_HS_EALREADY) {
+ NIMBLE_LOGE(LOG_TAG, "ble_gap_adv_stop rc=%d %s",
+ rc, NimBLEUtils::returnCodeToString(rc));
+ return;
+ }
+
+ NIMBLE_LOGD(LOG_TAG, "<< stop");
+} // stop
+
+
+/**
+ * @brief Handles the callback when advertising stops.
+ */
+void NimBLEAdvertising::advCompleteCB() {
+ if(m_advCompCB != nullptr) {
+ m_advCompCB(this);
+ }
+} // advCompleteCB
+
+
+/**
+ * @brief Check if currently advertising.
+ * @return true if advertising is active.
+ */
+bool NimBLEAdvertising::isAdvertising() {
+ return ble_gap_adv_active();
+} // isAdvertising
+
+
+/*
+ * Host reset seems to clear advertising data,
+ * we need clear the flag so it reloads it.
+ */
+void NimBLEAdvertising::onHostSync() {
+ NIMBLE_LOGD(LOG_TAG, "Host re-synced");
+
+ m_advDataSet = false;
+ // If we were advertising forever, restart it now
+ if(m_duration == 0) {
+ start(m_duration, m_advCompCB);
+ } else {
+ // Otherwise we should tell the app that advertising stopped.
+ advCompleteCB();
+ }
+} // onHostSync
+
+
+/**
+ * @brief Handler for gap events when not using peripheral role.
+ * @param [in] event the event data.
+ * @param [in] arg pointer to the advertising instance.
+ */
+/*STATIC*/
+int NimBLEAdvertising::handleGapEvent(struct ble_gap_event *event, void *arg) {
+ NimBLEAdvertising *pAdv = (NimBLEAdvertising*)arg;
+
+ if(event->type == BLE_GAP_EVENT_ADV_COMPLETE) {
+ switch(event->adv_complete.reason) {
+ // Don't call the callback if host reset, we want to
+ // preserve the active flag until re-sync to restart advertising.
+ case BLE_HS_ETIMEOUT_HCI:
+ case BLE_HS_EOS:
+ case BLE_HS_ECONTROLLER:
+ case BLE_HS_ENOTSYNCED:
+ NIMBLE_LOGC(LOG_TAG, "host reset, rc=%d", event->adv_complete.reason);
+ NimBLEDevice::onReset(event->adv_complete.reason);
+ return 0;
+ default:
+ break;
+ }
+ pAdv->advCompleteCB();
+ }
+ return 0;
+}
+
+
+/**
+ * @brief Add data to the payload to be advertised.
+ * @param [in] data The data to be added to the payload.
+ */
+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);
+} // addData
+
+
+/**
+ * @brief Add data to the payload to be advertised.
+ * @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) {
+ addData(std::string(data, length));
+} // addData
+
+
+/**
+ * @brief Set the appearance.
+ * @param [in] appearance The appearance code value.
+ *
+ * See also:
+ * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.gap.appearance.xml
+ */
+void NimBLEAdvertisementData::setAppearance(uint16_t appearance) {
+ char cdata[2];
+ cdata[0] = 3;
+ cdata[1] = BLE_HS_ADV_TYPE_APPEARANCE; // 0x19
+ addData(std::string(cdata, 2) + std::string((char*) &appearance, 2));
+} // setAppearance
+
+
+/**
+ * @brief Set the advertisement flags.
+ * @param [in] flag The flags to be set in the advertisement.
+ * * BLE_HS_ADV_F_DISC_LTD
+ * * BLE_HS_ADV_F_DISC_GEN
+ * * BLE_HS_ADV_F_BREDR_UNSUP - must always use with NimBLE
+ */
+void NimBLEAdvertisementData::setFlags(uint8_t flag) {
+ char cdata[3];
+ cdata[0] = 2;
+ cdata[1] = BLE_HS_ADV_TYPE_FLAGS; // 0x01
+ cdata[2] = flag | BLE_HS_ADV_F_BREDR_UNSUP;
+ addData(std::string(cdata, 3));
+} // setFlag
+
+
+/**
+ * @brief Set manufacturer specific data.
+ * @param [in] data The manufacturer data to advertise.
+ */
+void NimBLEAdvertisementData::setManufacturerData(const std::string &data) {
+ char cdata[2];
+ cdata[0] = data.length() + 1;
+ cdata[1] = BLE_HS_ADV_TYPE_MFG_DATA ; // 0xff
+ addData(std::string(cdata, 2) + data);
+} // 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) {
+ char cdata[2];
+ cdata[0] = name.length() + 1;
+ cdata[1] = BLE_HS_ADV_TYPE_COMP_NAME; // 0x09
+ addData(std::string(cdata, 2) + name);
+} // setName
+
+
+/**
+ * @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];
+ 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:
+ cdata[1] = complete ? BLE_HS_ADV_TYPE_COMP_UUIDS32 : BLE_HS_ADV_TYPE_INCOMP_UUIDS32;
+ break;
+ case 128:
+ cdata[1] = complete ? BLE_HS_ADV_TYPE_COMP_UUIDS128 : BLE_HS_ADV_TYPE_INCOMP_UUIDS128;
+ break;
+ default:
+ return;
+ }
+
+ 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
+
+
+/**
+ * @brief Set the service data (UUID + data)
+ * @param [in] uuid The UUID to set with the service data.
+ * @param [in] data The data to be associated with the service data advertised.
+ */
+void NimBLEAdvertisementData::setServiceData(const NimBLEUUID &uuid, const std::string &data) {
+ char cdata[2];
+ switch (uuid.bitSize()) {
+ case 16: {
+ // [Len] [0x16] [UUID16] data
+ cdata[0] = data.length() + 3;
+ cdata[1] = BLE_HS_ADV_TYPE_SVC_DATA_UUID16; // 0x16
+ addData(std::string(cdata, 2) + std::string((char*) &uuid.getNative()->u16.value, 2) + data);
+ break;
+ }
+
+ case 32: {
+ // [Len] [0x20] [UUID32] data
+ cdata[0] = data.length() + 5;
+ cdata[1] = BLE_HS_ADV_TYPE_SVC_DATA_UUID32; // 0x20
+ addData(std::string(cdata, 2) + std::string((char*) &uuid.getNative()->u32.value, 4) + data);
+ break;
+ }
+
+ case 128: {
+ // [Len] [0x21] [UUID128] data
+ cdata[0] = data.length() + 17;
+ cdata[1] = BLE_HS_ADV_TYPE_SVC_DATA_UUID128; // 0x21
+ addData(std::string(cdata, 2) + std::string((char*) &uuid.getNative()->u128.value, 16) + data);
+ break;
+ }
+
+ default:
+ return;
+ }
+} // setServiceData
+
+
+/**
+ * @brief Set the short name.
+ * @param [in] name The short name of the device.
+ */
+void NimBLEAdvertisementData::setShortName(const std::string &name) {
+ char cdata[2];
+ cdata[0] = name.length() + 1;
+ cdata[1] = BLE_HS_ADV_TYPE_INCOMP_NAME; // 0x08
+ addData(std::string(cdata, 2) + name);
+} // 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.
+ */
+std::string NimBLEAdvertisementData::getPayload() {
+ return m_payload;
+} // getPayload
+
+#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER */
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/NimBLEAdvertising.h b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEAdvertising.h
new file mode 100644
index 0000000..63a21d8
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEAdvertising.h
@@ -0,0 +1,138 @@
+/*
+ * NimBLEAdvertising.h
+ *
+ * Created: on March 3, 2020
+ * Author H2zero
+ *
+ * Originally:
+ *
+ * BLEAdvertising.h
+ *
+ * Created on: Jun 21, 2017
+ * Author: kolban
+ */
+
+#ifndef MAIN_BLEADVERTISING_H_
+#define MAIN_BLEADVERTISING_H_
+#include "nimconfig.h"
+#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
+
+#if defined(CONFIG_NIMBLE_CPP_IDF)
+#include "host/ble_gap.h"
+#else
+#include "nimble/nimble/host/include/host/ble_gap.h"
+#endif
+
+/**** FIX COMPILATION ****/
+#undef min
+#undef max
+/**************************/
+
+#include "NimBLEUUID.h"
+
+#include
+
+/* COMPATIBILITY - DO NOT USE */
+#define ESP_BLE_ADV_FLAG_LIMIT_DISC (0x01 << 0)
+#define ESP_BLE_ADV_FLAG_GEN_DISC (0x01 << 1)
+#define ESP_BLE_ADV_FLAG_BREDR_NOT_SPT (0x01 << 2)
+#define ESP_BLE_ADV_FLAG_DMT_CONTROLLER_SPT (0x01 << 3)
+#define ESP_BLE_ADV_FLAG_DMT_HOST_SPT (0x01 << 4)
+#define ESP_BLE_ADV_FLAG_NON_LIMIT_DISC (0x00 )
+ /* ************************* */
+
+
+/**
+ * @brief Advertisement data set by the programmer to be published by the %BLE server.
+ */
+class NimBLEAdvertisementData {
+ // Only a subset of the possible BLE architected advertisement fields are currently exposed. Others will
+ // be exposed on demand/request or as time permits.
+ //
+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
+
+
+/**
+ * @brief Perform and manage %BLE advertising.
+ *
+ * A %BLE server will want to perform advertising in order to make itself known to %BLE clients.
+ */
+class NimBLEAdvertising {
+public:
+ NimBLEAdvertising();
+ void addServiceUUID(const NimBLEUUID &serviceUUID);
+ void addServiceUUID(const char* serviceUUID);
+ void removeServiceUUID(const NimBLEUUID &serviceUUID);
+ 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);
+ void setAdvertisementData(NimBLEAdvertisementData& advertisementData);
+ void setScanFilter(bool scanRequestWhitelistOnly, bool connectWhitelistOnly);
+ void setScanResponseData(NimBLEAdvertisementData& advertisementData);
+ void setScanResponse(bool);
+ void setMinPreferred(uint16_t);
+ void setMaxPreferred(uint16_t);
+ void addTxPower();
+ void reset();
+ void advCompleteCB();
+ bool isAdvertising();
+
+private:
+ friend class NimBLEDevice;
+
+ void onHostSync();
+ static int handleGapEvent(struct ble_gap_event *event, void *arg);
+
+ ble_hs_adv_fields m_advData;
+ ble_hs_adv_fields m_scanData;
+ ble_gap_adv_params m_advParams;
+ std::vector m_serviceUUIDs;
+ bool m_customAdvData;
+ bool m_customScanResponseData;
+ bool m_scanResp;
+ bool m_advDataSet;
+ 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 /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER */
+#endif /* MAIN_BLEADVERTISING_H_ */
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/NimBLEBeacon.cpp b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEBeacon.cpp
new file mode 100644
index 0000000..996893a
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEBeacon.cpp
@@ -0,0 +1,157 @@
+/*
+ * NimBLEBeacon2.cpp
+ *
+ * Created: on March 15 2020
+ * Author H2zero
+ *
+ * Originally:
+ *
+ * BLEBeacon.cpp
+ *
+ * Created on: Jan 4, 2018
+ * Author: kolban
+ */
+#include "nimconfig.h"
+#if defined(CONFIG_BT_ENABLED)
+
+#include
+#include
+#include "NimBLEBeacon.h"
+#include "NimBLELog.h"
+
+#define ENDIAN_CHANGE_U16(x) ((((x)&0xFF00)>>8) + (((x)&0xFF)<<8))
+
+static const char* LOG_TAG = "NimBLEBeacon";
+
+
+/**
+ * @brief Construct a default beacon object.
+ */
+NimBLEBeacon::NimBLEBeacon() {
+ m_beaconData.manufacturerId = 0x4c00;
+ m_beaconData.subType = 0x02;
+ m_beaconData.subTypeLength = 0x15;
+ m_beaconData.major = 0;
+ m_beaconData.minor = 0;
+ m_beaconData.signalPower = 0;
+ memset(m_beaconData.proximityUUID, 0, sizeof(m_beaconData.proximityUUID));
+} // NimBLEBeacon
+
+
+/**
+ * @brief Retrieve the data that is being advertised.
+ * @return The advertised data.
+ */
+std::string NimBLEBeacon::getData() {
+ return std::string((char*) &m_beaconData, sizeof(m_beaconData));
+} // getData
+
+
+/**
+ * @brief Get the major value being advertised.
+ * @return The major value advertised.
+ */
+uint16_t NimBLEBeacon::getMajor() {
+ return m_beaconData.major;
+}
+
+
+/**
+ * @brief Get the manufacturer ID being advertised.
+ * @return The manufacturer ID value advertised.
+ */
+uint16_t NimBLEBeacon::getManufacturerId() {
+ return m_beaconData.manufacturerId;
+}
+
+
+/**
+ * @brief Get the minor value being advertised.
+ * @return minor value advertised.
+ */
+uint16_t NimBLEBeacon::getMinor() {
+ return m_beaconData.minor;
+}
+
+
+/**
+ * @brief Get the proximity UUID being advertised.
+ * @return The UUID advertised.
+ */
+NimBLEUUID NimBLEBeacon::getProximityUUID() {
+ return NimBLEUUID(m_beaconData.proximityUUID, 16, true);
+}
+
+
+/**
+ * @brief Get the signal power being advertised.
+ * @return signal power level advertised.
+ */
+int8_t NimBLEBeacon::getSignalPower() {
+ return m_beaconData.signalPower;
+}
+
+
+/**
+ * @brief Set the raw data for the beacon record.
+ * @param [in] data The raw beacon data.
+ */
+void NimBLEBeacon::setData(const std::string &data) {
+ if (data.length() != sizeof(m_beaconData)) {
+ NIMBLE_LOGE(LOG_TAG, "Unable to set the data ... length passed in was %d and expected %d",
+ data.length(), sizeof(m_beaconData));
+ return;
+ }
+ memcpy(&m_beaconData, data.data(), sizeof(m_beaconData));
+} // setData
+
+
+/**
+ * @brief Set the major value.
+ * @param [in] major The major value.
+ */
+void NimBLEBeacon::setMajor(uint16_t major) {
+ m_beaconData.major = ENDIAN_CHANGE_U16(major);
+} // setMajor
+
+
+/**
+ * @brief Set the manufacturer ID.
+ * @param [in] manufacturerId The manufacturer ID value.
+ */
+void NimBLEBeacon::setManufacturerId(uint16_t manufacturerId) {
+ m_beaconData.manufacturerId = ENDIAN_CHANGE_U16(manufacturerId);
+} // setManufacturerId
+
+
+/**
+ * @brief Set the minor value.
+ * @param [in] minor The minor value.
+ */
+void NimBLEBeacon::setMinor(uint16_t minor) {
+ m_beaconData.minor = ENDIAN_CHANGE_U16(minor);
+} // setMinior
+
+
+/**
+ * @brief Set the proximity UUID.
+ * @param [in] uuid The proximity UUID.
+ */
+void NimBLEBeacon::setProximityUUID(const NimBLEUUID &uuid) {
+ NimBLEUUID temp_uuid = uuid;
+ temp_uuid.to128();
+ std::reverse_copy(temp_uuid.getNative()->u128.value,
+ temp_uuid.getNative()->u128.value + 16,
+ m_beaconData.proximityUUID);
+} // setProximityUUID
+
+
+/**
+ * @brief Set the signal power.
+ * @param [in] signalPower The signal power value.
+ */
+void NimBLEBeacon::setSignalPower(int8_t signalPower) {
+ m_beaconData.signalPower = signalPower;
+} // setSignalPower
+
+#endif
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/NimBLEBeacon.h b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEBeacon.h
new file mode 100644
index 0000000..82ee61c
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEBeacon.h
@@ -0,0 +1,51 @@
+/*
+ * NimBLEBeacon2.h
+ *
+ * Created: on March 15 2020
+ * Author H2zero
+ *
+ * Originally:
+ *
+ * BLEBeacon2.h
+ *
+ * Created on: Jan 4, 2018
+ * Author: kolban
+ */
+
+#ifndef MAIN_NIMBLEBEACON_H_
+#define MAIN_NIMBLEBEACON_H_
+
+#include "NimBLEUUID.h"
+/**
+ * @brief Representation of a beacon.
+ * See:
+ * * https://en.wikipedia.org/wiki/IBeacon
+ */
+class NimBLEBeacon {
+private:
+ struct {
+ uint16_t manufacturerId;
+ uint8_t subType;
+ uint8_t subTypeLength;
+ uint8_t proximityUUID[16];
+ uint16_t major;
+ uint16_t minor;
+ int8_t signalPower;
+ } __attribute__((packed)) m_beaconData;
+public:
+ NimBLEBeacon();
+ std::string getData();
+ uint16_t getMajor();
+ uint16_t getMinor();
+ uint16_t getManufacturerId();
+ NimBLEUUID getProximityUUID();
+ int8_t getSignalPower();
+ void setData(const std::string &data);
+ void setMajor(uint16_t major);
+ void setMinor(uint16_t minor);
+ void setManufacturerId(uint16_t manufacturerId);
+ void setProximityUUID(const NimBLEUUID &uuid);
+ void setSignalPower(int8_t signalPower);
+}; // NimBLEBeacon
+
+#endif /* MAIN_NIMBLEBEACON_H_ */
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/NimBLECharacteristic.cpp b/src/components/esp-nimble-cpp-1.3.3/src/NimBLECharacteristic.cpp
new file mode 100644
index 0000000..cb447d6
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/NimBLECharacteristic.cpp
@@ -0,0 +1,649 @@
+/*
+ * NimBLECharacteristic.cpp
+ *
+ * Created: on March 3, 2020
+ * Author H2zero
+ *
+ * BLECharacteristic.cpp
+ *
+ * Created on: Jun 22, 2017
+ * Author: kolban
+ */
+
+#include "nimconfig.h"
+#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
+
+#include "NimBLECharacteristic.h"
+#include "NimBLE2904.h"
+#include "NimBLEDevice.h"
+#include "NimBLELog.h"
+
+#define NULL_HANDLE (0xffff)
+#define NIMBLE_SUB_NOTIFY 0x0001
+#define NIMBLE_SUB_INDICATE 0x0002
+
+static NimBLECharacteristicCallbacks defaultCallback;
+static const char* LOG_TAG = "NimBLECharacteristic";
+
+
+/**
+ * @brief Construct a characteristic
+ * @param [in] uuid - UUID (const char*) for the characteristic.
+ * @param [in] properties - Properties for the characteristic.
+ * @param [in] pService - pointer to the service instance this characteristic belongs to.
+ */
+NimBLECharacteristic::NimBLECharacteristic(const char* uuid, uint16_t properties, NimBLEService* pService)
+: NimBLECharacteristic(NimBLEUUID(uuid), properties, pService) {
+}
+
+/**
+ * @brief Construct a characteristic
+ * @param [in] uuid - UUID for the characteristic.
+ * @param [in] properties - Properties for the characteristic.
+ * @param [in] pService - pointer to the service instance this characteristic belongs to.
+ */
+NimBLECharacteristic::NimBLECharacteristic(const NimBLEUUID &uuid, uint16_t properties, NimBLEService* pService) {
+ m_uuid = uuid;
+ m_handle = NULL_HANDLE;
+ m_properties = properties;
+ m_pCallbacks = &defaultCallback;
+ m_pService = pService;
+ m_value = "";
+ m_timestamp = 0;
+ m_removed = 0;
+} // NimBLECharacteristic
+
+/**
+ * @brief Destructor.
+ */
+NimBLECharacteristic::~NimBLECharacteristic() {
+ for(auto &it : m_dscVec) {
+ delete it;
+ }
+} // ~NimBLECharacteristic
+
+
+/**
+ * @brief Create a new BLE Descriptor associated with this characteristic.
+ * @param [in] uuid - The UUID of the descriptor.
+ * @param [in] properties - The properties of the descriptor.
+ * @param [in] max_len - The max length in bytes of the descriptor value.
+ * @return The new BLE descriptor.
+ */
+NimBLEDescriptor* NimBLECharacteristic::createDescriptor(const char* uuid, uint32_t properties, uint16_t max_len) {
+ return createDescriptor(NimBLEUUID(uuid), properties, max_len);
+}
+
+
+/**
+ * @brief Create a new BLE Descriptor associated with this characteristic.
+ * @param [in] uuid - The UUID of the descriptor.
+ * @param [in] properties - The properties of the descriptor.
+ * @param [in] max_len - The max length in bytes of the descriptor value.
+ * @return The new BLE descriptor.
+ */
+NimBLEDescriptor* NimBLECharacteristic::createDescriptor(const NimBLEUUID &uuid, uint32_t properties, uint16_t max_len) {
+ NimBLEDescriptor* pDescriptor = nullptr;
+ if(uuid == NimBLEUUID(uint16_t(0x2902))) {
+ assert(0 && "0x2902 descriptors cannot be manually created");
+ } else if (uuid == NimBLEUUID(uint16_t(0x2904))) {
+ pDescriptor = new NimBLE2904(this);
+ } else {
+ pDescriptor = new NimBLEDescriptor(uuid, properties, max_len, this);
+ }
+
+ addDescriptor(pDescriptor);
+ return pDescriptor;
+} // createDescriptor
+
+
+/**
+ * @brief Add a descriptor to the characteristic.
+ * @param [in] pDescriptor A pointer to the descriptor to add.
+ */
+void NimBLECharacteristic::addDescriptor(NimBLEDescriptor *pDescriptor) {
+ bool foundRemoved = false;
+
+ if(pDescriptor->m_removed > 0) {
+ for(auto& it : m_dscVec) {
+ if(it == pDescriptor) {
+ foundRemoved = true;
+ pDescriptor->m_removed = 0;
+ }
+ }
+ }
+
+ if(!foundRemoved) {
+ m_dscVec.push_back(pDescriptor);
+ }
+
+ pDescriptor->setCharacteristic(this);
+ NimBLEDevice::getServer()->serviceChanged();
+}
+
+
+/**
+ * @brief Remove a descriptor from the characterisitc.
+ * @param[in] pDescriptor A pointer to the descriptor instance to remove from the characterisitc.
+ * @param[in] deleteDsc If true it will delete the descriptor instance and free it's resources.
+ */
+void NimBLECharacteristic::removeDescriptor(NimBLEDescriptor *pDescriptor, bool deleteDsc) {
+ // Check if the descriptor was already removed and if so, check if this
+ // is being called to delete the object and do so if requested.
+ // Otherwise, ignore the call and return.
+ if(pDescriptor->m_removed > 0) {
+ if(deleteDsc) {
+ for(auto it = m_dscVec.begin(); it != m_dscVec.end(); ++it) {
+ if ((*it) == pDescriptor) {
+ delete *it;
+ m_dscVec.erase(it);
+ break;
+ }
+ }
+ }
+
+ return;
+ }
+
+ pDescriptor->m_removed = deleteDsc ? NIMBLE_ATT_REMOVE_DELETE : NIMBLE_ATT_REMOVE_HIDE;
+ NimBLEDevice::getServer()->serviceChanged();
+} // removeDescriptor
+
+
+/**
+ * @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));
+} // getDescriptorByUUID
+
+
+/**
+ * @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) {
+ if (it->getUUID() == uuid) {
+ return it;
+ }
+ }
+ 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.
+ * @return The handle of the characteristic.
+ */
+uint16_t NimBLECharacteristic::getHandle() {
+ return m_handle;
+} // getHandle
+
+
+/**
+ * @brief Get the properties of the characteristic.
+ * @return The properties of the characteristic.
+ */
+uint16_t NimBLECharacteristic::getProperties() {
+ return m_properties;
+} // getProperties
+
+
+/**
+ * @brief Get the service associated with this characteristic.
+ */
+NimBLEService* NimBLECharacteristic::getService() {
+ return m_pService;
+} // getService
+
+
+void NimBLECharacteristic::setService(NimBLEService *pService) {
+ m_pService = pService;
+}
+
+
+/**
+ * @brief Get the UUID of the characteristic.
+ * @return The UUID of the characteristic.
+ */
+NimBLEUUID NimBLECharacteristic::getUUID() {
+ return m_uuid;
+} // getUUID
+
+
+/**
+ * @brief Retrieve the current value of the characteristic.
+ * @return A std::string containing the current characteristic value.
+ */
+std::string NimBLECharacteristic::getValue(time_t *timestamp) {
+ ble_npl_hw_enter_critical();
+ std::string retVal = m_value;
+ if(timestamp != nullptr) {
+ *timestamp = m_timestamp;
+ }
+ ble_npl_hw_exit_critical(0);
+
+ return retVal;
+} // getValue
+
+
+/**
+ * @brief Retrieve the the current data length of the characteristic.
+ * @return The length of the current characteristic data.
+ */
+size_t NimBLECharacteristic::getDataLength() {
+ ble_npl_hw_enter_critical();
+ size_t len = m_value.length();
+ ble_npl_hw_exit_critical(0);
+ return len;
+}
+
+
+/**
+ * @brief STATIC callback to handle events from the NimBLE stack.
+ */
+int NimBLECharacteristic::handleGapEvent(uint16_t conn_handle, uint16_t attr_handle,
+ struct ble_gatt_access_ctxt *ctxt,
+ void *arg)
+{
+ const ble_uuid_t *uuid;
+ int rc;
+ struct ble_gap_conn_desc desc;
+ NimBLECharacteristic* pCharacteristic = (NimBLECharacteristic*)arg;
+
+ NIMBLE_LOGD(LOG_TAG, "Characteristic %s %s event", pCharacteristic->getUUID().toString().c_str(),
+ ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR ? "Read" : "Write");
+
+ uuid = ctxt->chr->uuid;
+ if(ble_uuid_cmp(uuid, &pCharacteristic->getUUID().getNative()->u) == 0){
+ switch(ctxt->op) {
+ case BLE_GATT_ACCESS_OP_READ_CHR: {
+ // If the packet header is only 8 bytes this is a follow up of a long read
+ // so we don't want to call the onRead() callback again.
+ if(ctxt->om->om_pkthdr_len > 8) {
+ rc = ble_gap_conn_find(conn_handle, &desc);
+ assert(rc == 0);
+ pCharacteristic->m_pCallbacks->onRead(pCharacteristic);
+ pCharacteristic->m_pCallbacks->onRead(pCharacteristic, &desc);
+ }
+
+ ble_npl_hw_enter_critical();
+ rc = os_mbuf_append(ctxt->om, (uint8_t*)pCharacteristic->m_value.data(),
+ pCharacteristic->m_value.length());
+ ble_npl_hw_exit_critical(0);
+ return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
+ }
+
+ case BLE_GATT_ACCESS_OP_WRITE_CHR: {
+ if (ctxt->om->om_len > BLE_ATT_ATTR_MAX_LEN) {
+ return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
+ }
+
+ uint8_t buf[BLE_ATT_ATTR_MAX_LEN];
+ size_t len = ctxt->om->om_len;
+ memcpy(buf, ctxt->om->om_data,len);
+
+ os_mbuf *next;
+ next = SLIST_NEXT(ctxt->om, om_next);
+ while(next != NULL){
+ if((len + next->om_len) > BLE_ATT_ATTR_MAX_LEN) {
+ return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
+ }
+ memcpy(&buf[len], next->om_data, next->om_len);
+ len += next->om_len;
+ next = SLIST_NEXT(next, om_next);
+ }
+ rc = ble_gap_conn_find(conn_handle, &desc);
+ assert(rc == 0);
+ pCharacteristic->setValue(buf, len);
+ pCharacteristic->m_pCallbacks->onWrite(pCharacteristic);
+ pCharacteristic->m_pCallbacks->onWrite(pCharacteristic, &desc);
+ return 0;
+ }
+ default:
+ break;
+ }
+ }
+
+ return BLE_ATT_ERR_UNLIKELY;
+}
+
+
+/**
+ * @brief Get the number of clients subscribed to the characteristic.
+ * @returns Number of clients subscribed to notifications / indications.
+ */
+size_t NimBLECharacteristic::getSubscribedCount() {
+ return m_subscribedVec.size();
+}
+
+
+/**
+ * @brief Set the subscribe status for this characteristic.\n
+ * This will maintain a vector of subscribed clients and their indicate/notify status.
+ */
+void NimBLECharacteristic::setSubscribe(struct ble_gap_event *event) {
+ ble_gap_conn_desc desc;
+ if(ble_gap_conn_find(event->subscribe.conn_handle, &desc) != 0) {
+ return;
+ }
+
+ uint16_t subVal = 0;
+ if(event->subscribe.cur_notify > 0 && (m_properties & NIMBLE_PROPERTY::NOTIFY)) {
+ subVal |= NIMBLE_SUB_NOTIFY;
+ }
+ if(event->subscribe.cur_indicate && (m_properties & NIMBLE_PROPERTY::INDICATE)) {
+ subVal |= NIMBLE_SUB_INDICATE;
+ }
+
+ NIMBLE_LOGI(LOG_TAG, "New subscribe value for conn: %d val: %d",
+ event->subscribe.conn_handle, subVal);
+
+ if(!event->subscribe.cur_indicate && event->subscribe.prev_indicate) {
+ NimBLEDevice::getServer()->clearIndicateWait(event->subscribe.conn_handle);
+ }
+
+
+ auto it = m_subscribedVec.begin();
+ for(;it != m_subscribedVec.end(); ++it) {
+ if((*it).first == event->subscribe.conn_handle) {
+ break;
+ }
+ }
+
+ if(subVal > 0) {
+ if(it == m_subscribedVec.end()) {
+ m_subscribedVec.push_back({event->subscribe.conn_handle, subVal});
+ } else {
+ (*it).second = subVal;
+ }
+ } else if(it != m_subscribedVec.end()) {
+ m_subscribedVec.erase(it);
+ }
+
+ m_pCallbacks->onSubscribe(this, &desc, subVal);
+}
+
+
+/**
+ * @brief Send an indication.\n
+ * An indication is a transmission of up to the first 20 bytes of the characteristic value.\n
+ * An indication will block waiting for a positive confirmation from the client.
+ */
+void NimBLECharacteristic::indicate() {
+ NIMBLE_LOGD(LOG_TAG, ">> indicate: length: %d", getDataLength());
+ notify(false);
+ NIMBLE_LOGD(LOG_TAG, "<< indicate");
+} // indicate
+
+
+/**
+ * @brief Send a notification.\n
+ * A notification is a transmission of up to the first 20 bytes of the characteristic value.\n
+ * A notification will not block; it is a fire and forget.
+ * @param[in] is_notification if true sends a notification, false sends an indication.
+ */
+void NimBLECharacteristic::notify(bool is_notification) {
+ notify(getValue(), is_notification);
+}
+
+/**
+ * @brief Send a notification.\n
+ * A notification is a transmission of up to the first 20 bytes of the characteristic value.\n
+ * A notification will not block; it is a fire and forget.
+ * @param[in] value An optional value to send as the notification, else the current characteristic value is used.
+ * @param[in] is_notification if true sends a notification, false sends an indication.
+ */
+void NimBLECharacteristic::notify(std::string value, bool is_notification) {
+ size_t length = value.length();
+ NIMBLE_LOGD(LOG_TAG, ">> notify: length: %d", length);
+
+ if(!(m_properties & NIMBLE_PROPERTY::NOTIFY) &&
+ !(m_properties & NIMBLE_PROPERTY::INDICATE))
+ {
+ NIMBLE_LOGE(LOG_TAG,
+ "<< notify-Error; Notify/indicate not enabled for characterisitc: %s",
+ std::string(getUUID()).c_str());
+ }
+
+ if (m_subscribedVec.size() == 0) {
+ NIMBLE_LOGD(LOG_TAG, "<< notify: No clients subscribed.");
+ return;
+ }
+
+ m_pCallbacks->onNotify(this);
+
+ bool reqSec = (m_properties & BLE_GATT_CHR_F_READ_AUTHEN) ||
+ (m_properties & BLE_GATT_CHR_F_READ_AUTHOR) ||
+ (m_properties & BLE_GATT_CHR_F_READ_ENC);
+ int rc = 0;
+
+ for (auto &it : m_subscribedVec) {
+ uint16_t _mtu = getService()->getServer()->getPeerMTU(it.first) - 3;
+
+ // check if connected and subscribed
+ if(_mtu == 0 || it.second == 0) {
+ continue;
+ }
+
+ // check if security requirements are satisfied
+ if(reqSec) {
+ struct ble_gap_conn_desc desc;
+ rc = ble_gap_conn_find(it.first, &desc);
+ if(rc != 0 || !desc.sec_state.encrypted) {
+ continue;
+ }
+ }
+
+ if (length > _mtu) {
+ NIMBLE_LOGW(LOG_TAG, "- Truncating to %d bytes (maximum notify size)", _mtu);
+ }
+
+ if(is_notification && (!(it.second & NIMBLE_SUB_NOTIFY))) {
+ NIMBLE_LOGW(LOG_TAG,
+ "Sending notification to client subscribed to indications, sending indication instead");
+ is_notification = false;
+ }
+
+ if(!is_notification && (!(it.second & NIMBLE_SUB_INDICATE))) {
+ NIMBLE_LOGW(LOG_TAG,
+ "Sending indication to client subscribed to notification, sending notification instead");
+ is_notification = true;
+ }
+
+ // don't create the m_buf until we are sure to send the data or else
+ // we could be allocating a buffer that doesn't get released.
+ // We also must create it in each loop iteration because it is consumed with each host call.
+ os_mbuf *om = ble_hs_mbuf_from_flat((uint8_t*)value.data(), length);
+
+ if(!is_notification && (m_properties & NIMBLE_PROPERTY::INDICATE)) {
+ if(!NimBLEDevice::getServer()->setIndicateWait(it.first)) {
+ NIMBLE_LOGE(LOG_TAG, "prior Indication in progress");
+ os_mbuf_free_chain(om);
+ return;
+ }
+
+ rc = ble_gattc_indicate_custom(it.first, m_handle, om);
+ if(rc != 0){
+ NimBLEDevice::getServer()->clearIndicateWait(it.first);
+ }
+ } else {
+ ble_gattc_notify_custom(it.first, m_handle, om);
+ }
+ }
+
+ NIMBLE_LOGD(LOG_TAG, "<< notify");
+} // Notify
+
+
+/**
+ * @brief Set the callback handlers for this characteristic.
+ * @param [in] pCallbacks An instance of a NimBLECharacteristicCallbacks class\n
+ * used to define any callbacks for the characteristic.
+ */
+void NimBLECharacteristic::setCallbacks(NimBLECharacteristicCallbacks* pCallbacks) {
+ if (pCallbacks != nullptr){
+ m_pCallbacks = pCallbacks;
+ } else {
+ m_pCallbacks = &defaultCallback;
+ }
+} // setCallbacks
+
+/**
+ * @brief Get the callback handlers for this characteristic.
+ */
+NimBLECharacteristicCallbacks* NimBLECharacteristic::getCallbacks() {
+ return m_pCallbacks;
+} //getCallbacks
+
+
+/**
+ * @brief Set the value of the characteristic.
+ * @param [in] data The data to set for the characteristic.
+ * @param [in] length The length of the data in bytes.
+ */
+void NimBLECharacteristic::setValue(const uint8_t* data, size_t length) {
+#if CONFIG_NIMBLE_CPP_LOG_LEVEL >= 4
+ char* pHex = NimBLEUtils::buildHexData(nullptr, data, length);
+ NIMBLE_LOGD(LOG_TAG, ">> setValue: length=%d, data=%s, characteristic UUID=%s", length, pHex, getUUID().toString().c_str());
+ free(pHex);
+#endif
+
+ if (length > BLE_ATT_ATTR_MAX_LEN) {
+ NIMBLE_LOGE(LOG_TAG, "Size %d too large, must be no bigger than %d", length, BLE_ATT_ATTR_MAX_LEN);
+ return;
+ }
+
+ time_t t = time(nullptr);
+ ble_npl_hw_enter_critical();
+ m_value = std::string((char*)data, length);
+ m_timestamp = t;
+ ble_npl_hw_exit_critical(0);
+
+ NIMBLE_LOGD(LOG_TAG, "<< setValue");
+} // setValue
+
+
+/**
+ * @brief Set the value of the characteristic from string data.\n
+ * We set the value of the characteristic from the bytes contained in the string.
+ * @param [in] value the std::string value of the characteristic.
+ */
+void NimBLECharacteristic::setValue(const std::string &value) {
+ setValue((uint8_t*)(value.data()), value.length());
+} // setValue
+
+
+/**
+ * @brief Return a string representation of the characteristic.
+ * @return A string representation of the characteristic.
+ */
+std::string NimBLECharacteristic::toString() {
+ std::string res = "UUID: " + m_uuid.toString() + ", handle : 0x";
+ char hex[5];
+ snprintf(hex, sizeof(hex), "%04x", m_handle);
+ res += hex;
+ res += " ";
+ if (m_properties & BLE_GATT_CHR_PROP_READ ) res += "Read ";
+ if (m_properties & BLE_GATT_CHR_PROP_WRITE) res += "Write ";
+ if (m_properties & BLE_GATT_CHR_PROP_WRITE_NO_RSP) res += "WriteNoResponse ";
+ if (m_properties & BLE_GATT_CHR_PROP_BROADCAST) res += "Broadcast ";
+ if (m_properties & BLE_GATT_CHR_PROP_NOTIFY) res += "Notify ";
+ if (m_properties & BLE_GATT_CHR_PROP_INDICATE) res += "Indicate ";
+ return res;
+} // toString
+
+
+NimBLECharacteristicCallbacks::~NimBLECharacteristicCallbacks() {}
+
+
+/**
+ * @brief Callback function to support a read request.
+ * @param [in] pCharacteristic The characteristic that is the source of the event.
+ */
+void NimBLECharacteristicCallbacks::onRead(NimBLECharacteristic* pCharacteristic) {
+ NIMBLE_LOGD("NimBLECharacteristicCallbacks", "onRead: default");
+} // onRead
+
+/**
+ * @brief Callback function to support a read request.
+ * @param [in] pCharacteristic The characteristic that is the source of the event.
+ * @param [in] desc The connection description struct that is associated with the peer that performed the read.
+ */
+void NimBLECharacteristicCallbacks::onRead(NimBLECharacteristic* pCharacteristic, ble_gap_conn_desc* desc) {
+ NIMBLE_LOGD("NimBLECharacteristicCallbacks", "onRead: default");
+} // onRead
+
+/**
+ * @brief Callback function to support a write request.
+ * @param [in] pCharacteristic The characteristic that is the source of the event.
+ */
+void NimBLECharacteristicCallbacks::onWrite(NimBLECharacteristic* pCharacteristic) {
+ NIMBLE_LOGD("NimBLECharacteristicCallbacks", "onWrite: default");
+} // onWrite
+
+/**
+ * @brief Callback function to support a write request.
+ * @param [in] pCharacteristic The characteristic that is the source of the event.
+ * @param [in] desc The connection description struct that is associated with the peer that performed the write.
+ */
+void NimBLECharacteristicCallbacks::onWrite(NimBLECharacteristic* pCharacteristic, ble_gap_conn_desc* desc) {
+ NIMBLE_LOGD("NimBLECharacteristicCallbacks", "onWrite: default");
+} // onWrite
+
+/**
+ * @brief Callback function to support a Notify request.
+ * @param [in] pCharacteristic The characteristic that is the source of the event.
+ */
+void NimBLECharacteristicCallbacks::onNotify(NimBLECharacteristic* pCharacteristic) {
+ NIMBLE_LOGD("NimBLECharacteristicCallbacks", "onNotify: default");
+} // onNotify
+
+
+/**
+ * @brief Callback function to support a Notify/Indicate Status report.
+ * @param [in] pCharacteristic The characteristic that is the source of the event.
+ * @param [in] s Status of the notification/indication.
+ * @param [in] code Additional return code from the NimBLE stack.
+ */
+void NimBLECharacteristicCallbacks::onStatus(NimBLECharacteristic* pCharacteristic, Status s, int code) {
+ NIMBLE_LOGD("NimBLECharacteristicCallbacks", "onStatus: default");
+} // onStatus
+
+
+/**
+ * @brief Callback function called when a client changes subscription status.
+ * @param [in] pCharacteristic The characteristic that is the source of the event.
+ * @param [in] desc The connection description struct that is associated with the client.
+ * @param [in] subValue The subscription status:
+ * * 0 = Un-Subscribed
+ * * 1 = Notifications
+ * * 2 = Indications
+ * * 3 = Notifications and Indications
+ */
+void NimBLECharacteristicCallbacks::onSubscribe(NimBLECharacteristic* pCharacteristic,
+ ble_gap_conn_desc* desc,
+ uint16_t subValue)
+{
+ NIMBLE_LOGD("NimBLECharacteristicCallbacks", "onSubscribe: default");
+}
+
+#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/NimBLECharacteristic.h b/src/components/esp-nimble-cpp-1.3.3/src/NimBLECharacteristic.h
new file mode 100644
index 0000000..9af1120
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/NimBLECharacteristic.h
@@ -0,0 +1,202 @@
+/*
+ * NimBLECharacteristic.h
+ *
+ * Created: on March 3, 2020
+ * Author H2zero
+ *
+ * Originally:
+ * BLECharacteristic.h
+ *
+ * Created on: Jun 22, 2017
+ * Author: kolban
+ */
+
+#ifndef MAIN_NIMBLECHARACTERISTIC_H_
+#define MAIN_NIMBLECHARACTERISTIC_H_
+#include "nimconfig.h"
+#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
+
+#if defined(CONFIG_NIMBLE_CPP_IDF)
+#include "host/ble_hs.h"
+#else
+#include "nimble/nimble/host/include/host/ble_hs.h"
+#endif
+
+/**** FIX COMPILATION ****/
+#undef min
+#undef max
+/**************************/
+
+typedef enum {
+ READ = BLE_GATT_CHR_F_READ,
+ READ_ENC = BLE_GATT_CHR_F_READ_ENC,
+ READ_AUTHEN = BLE_GATT_CHR_F_READ_AUTHEN,
+ READ_AUTHOR = BLE_GATT_CHR_F_READ_AUTHOR,
+ WRITE = BLE_GATT_CHR_F_WRITE,
+ WRITE_NR = BLE_GATT_CHR_F_WRITE_NO_RSP,
+ WRITE_ENC = BLE_GATT_CHR_F_WRITE_ENC,
+ WRITE_AUTHEN = BLE_GATT_CHR_F_WRITE_AUTHEN,
+ WRITE_AUTHOR = BLE_GATT_CHR_F_WRITE_AUTHOR,
+ BROADCAST = BLE_GATT_CHR_F_BROADCAST,
+ NOTIFY = BLE_GATT_CHR_F_NOTIFY,
+ INDICATE = BLE_GATT_CHR_F_INDICATE
+} NIMBLE_PROPERTY;
+
+#include "NimBLEService.h"
+#include "NimBLEDescriptor.h"
+
+#include
+#include
+
+class NimBLEService;
+class NimBLEDescriptor;
+class NimBLECharacteristicCallbacks;
+
+
+/**
+ * @brief The model of a %BLE Characteristic.
+ *
+ * A BLE Characteristic is an identified value container that manages a value. It is exposed by a BLE server and
+ * can be read and written to by a %BLE client.
+ */
+class NimBLECharacteristic {
+public:
+ NimBLECharacteristic(const char* uuid,
+ uint16_t properties =
+ NIMBLE_PROPERTY::READ |
+ NIMBLE_PROPERTY::WRITE,
+ NimBLEService* pService = nullptr);
+ NimBLECharacteristic(const NimBLEUUID &uuid,
+ uint16_t properties =
+ NIMBLE_PROPERTY::READ |
+ NIMBLE_PROPERTY::WRITE,
+ NimBLEService* pService = nullptr);
+
+ ~NimBLECharacteristic();
+
+ uint16_t getHandle();
+ NimBLEUUID getUUID();
+ std::string toString();
+
+ void setCallbacks(NimBLECharacteristicCallbacks* pCallbacks);
+ NimBLECharacteristicCallbacks*
+ getCallbacks();
+
+ void indicate();
+ void notify(bool is_notification = true);
+ void notify(std::string value, bool is_notification = true);
+
+ size_t getSubscribedCount();
+
+ NimBLEDescriptor* createDescriptor(const char* uuid,
+ uint32_t properties =
+ NIMBLE_PROPERTY::READ |
+ NIMBLE_PROPERTY::WRITE,
+ uint16_t max_len = 100);
+ NimBLEDescriptor* createDescriptor(const NimBLEUUID &uuid,
+ uint32_t properties =
+ NIMBLE_PROPERTY::READ |
+ NIMBLE_PROPERTY::WRITE,
+ uint16_t max_len = 100);
+
+ void addDescriptor(NimBLEDescriptor *pDescriptor);
+ NimBLEDescriptor* getDescriptorByUUID(const char* uuid);
+ NimBLEDescriptor* getDescriptorByUUID(const NimBLEUUID &uuid);
+ NimBLEDescriptor* getDescriptorByHandle(uint16_t handle);
+ void removeDescriptor(NimBLEDescriptor *pDescriptor, bool deleteDsc = false);
+
+ 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.
+ * @param [in] timestamp A pointer to a time_t struct to store the time the value was read.
+ * @param [in] skipSizeCheck If true it will skip checking if the data size is less than sizeof() .
+ * @return The data converted to or NULL if skipSizeCheck is false and the data is
+ * less than sizeof() .
+ * @details Use: getValue(×tamp, skipSizeCheck);
+ */
+ template
+ T getValue(time_t *timestamp = nullptr, bool skipSizeCheck = false) {
+ std::string value = getValue();
+ if(!skipSizeCheck && value.size() < sizeof(T)) return T();
+ const char *pData = value.data();
+ return *((T *)pData);
+ }
+
+ 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) {
+ setValue((uint8_t*)&s, sizeof(T));
+ }
+
+ NimBLEService* getService();
+ uint16_t getProperties();
+
+private:
+
+ friend class NimBLEServer;
+ friend class NimBLEService;
+
+ void setService(NimBLEService *pService);
+ void setSubscribe(struct ble_gap_event *event);
+ static int handleGapEvent(uint16_t conn_handle, uint16_t attr_handle,
+ struct ble_gatt_access_ctxt *ctxt, void *arg);
+
+ NimBLEUUID m_uuid;
+ uint16_t m_handle;
+ uint16_t m_properties;
+ NimBLECharacteristicCallbacks* m_pCallbacks;
+ NimBLEService* m_pService;
+ std::string m_value;
+ std::vector m_dscVec;
+ time_t m_timestamp;
+ uint8_t m_removed;
+
+ std::vector> m_subscribedVec;
+}; // NimBLECharacteristic
+
+
+/**
+ * @brief Callbacks that can be associated with a %BLE characteristic to inform of events.
+ *
+ * When a server application creates a %BLE characteristic, we may wish to be informed when there is either
+ * a read or write request to the characteristic's value. An application can register a
+ * sub-classed instance of this class and will be notified when such an event happens.
+ */
+class NimBLECharacteristicCallbacks {
+public:
+
+/**
+ * @brief An enum to provide the callback the status of the
+ * notification/indication, implemented for backward compatibility.
+ * @deprecated To be removed in the future as the NimBLE stack return code is also provided.
+ */
+ typedef enum {
+ SUCCESS_INDICATE,
+ SUCCESS_NOTIFY,
+ ERROR_INDICATE_DISABLED,
+ ERROR_NOTIFY_DISABLED,
+ ERROR_GATT,
+ ERROR_NO_CLIENT,
+ ERROR_INDICATE_TIMEOUT,
+ ERROR_INDICATE_FAILURE
+ }Status;
+
+ virtual ~NimBLECharacteristicCallbacks();
+ virtual void onRead(NimBLECharacteristic* pCharacteristic);
+ virtual void onRead(NimBLECharacteristic* pCharacteristic, ble_gap_conn_desc* desc);
+ virtual void onWrite(NimBLECharacteristic* pCharacteristic);
+ virtual void onWrite(NimBLECharacteristic* pCharacteristic, ble_gap_conn_desc* desc);
+ virtual void onNotify(NimBLECharacteristic* pCharacteristic);
+ virtual void onStatus(NimBLECharacteristic* pCharacteristic, Status s, int code);
+ virtual void onSubscribe(NimBLECharacteristic* pCharacteristic, ble_gap_conn_desc* desc, uint16_t subValue);
+};
+
+#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
+#endif /*MAIN_NIMBLECHARACTERISTIC_H_*/
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/NimBLEClient.cpp b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEClient.cpp
new file mode 100644
index 0000000..16dfe0d
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEClient.cpp
@@ -0,0 +1,1251 @@
+/*
+ * NimBLEClient.cpp
+ *
+ * Created: on Jan 26 2020
+ * Author H2zero
+ *
+ * Originally:
+ * BLEClient.cpp
+ *
+ * Created on: Mar 22, 2017
+ * Author: kolban
+ */
+
+#include "nimconfig.h"
+#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
+
+#include "NimBLEClient.h"
+#include "NimBLEDevice.h"
+#include "NimBLELog.h"
+
+#include
+#include
+#include
+
+#if defined(CONFIG_NIMBLE_CPP_IDF)
+#include "nimble/nimble_port.h"
+#else
+#include "nimble/porting/nimble/include/nimble/nimble_port.h"
+#endif
+
+static const char* LOG_TAG = "NimBLEClient";
+static NimBLEClientCallbacks defaultCallbacks;
+
+/*
+ * Design
+ * ------
+ * When we perform a getService() request, we are asking the BLE server to return each of the services
+ * that it exposes. For each service, we receive a callback which contains details
+ * of the exposed service including its UUID.
+ *
+ * The objects we will invent for a NimBLEClient will be as follows:
+ * * NimBLERemoteService - A model of a remote service.
+ * * NimBLERemoteCharacteristic - A model of a remote characteristic
+ * * NimBLERemoteDescriptor - A model of a remote descriptor.
+ *
+ * Since there is a hierarchical relationship here, we will have the idea that from a NimBLERemoteService will own
+ * zero or more remote characteristics and a NimBLERemoteCharacteristic will own zero or more remote NimBLEDescriptors.
+ *
+ * We will assume that a NimBLERemoteService contains a vector of owned characteristics
+ * and that a NimBLECharacteristic contains a vector of owned descriptors.
+ *
+ *
+ */
+
+
+/**
+ * @brief Constructor, private - only callable by NimBLEDevice::createClient
+ * to ensure proper handling of the list of client objects.
+ */
+NimBLEClient::NimBLEClient(const NimBLEAddress &peerAddress) : m_peerAddress(peerAddress) {
+ m_pClientCallbacks = &defaultCallbacks;
+ m_conn_id = BLE_HS_CONN_HANDLE_NONE;
+ m_connectTimeout = 30000;
+ m_deleteCallbacks = false;
+ m_pTaskData = nullptr;
+ m_connEstablished = false;
+ m_lastErr = 0;
+
+ m_pConnParams.scan_itvl = 16; // Scan interval in 0.625ms units (NimBLE Default)
+ m_pConnParams.scan_window = 16; // Scan window in 0.625ms units (NimBLE Default)
+ m_pConnParams.itvl_min = BLE_GAP_INITIAL_CONN_ITVL_MIN; // min_int = 0x10*1.25ms = 20ms
+ m_pConnParams.itvl_max = BLE_GAP_INITIAL_CONN_ITVL_MAX; // max_int = 0x20*1.25ms = 40ms
+ m_pConnParams.latency = BLE_GAP_INITIAL_CONN_LATENCY; // number of packets allowed to skip (extends max interval)
+ m_pConnParams.supervision_timeout = BLE_GAP_INITIAL_SUPERVISION_TIMEOUT; // timeout = 400*10ms = 4000ms
+ m_pConnParams.min_ce_len = BLE_GAP_INITIAL_CONN_MIN_CE_LEN; // Minimum length of connection event in 0.625ms units
+ m_pConnParams.max_ce_len = BLE_GAP_INITIAL_CONN_MAX_CE_LEN; // Maximum length of connection event in 0.625ms units
+
+ memset(&m_dcTimer, 0, sizeof(m_dcTimer));
+ ble_npl_callout_init(&m_dcTimer, nimble_port_get_dflt_eventq(),
+ NimBLEClient::dcTimerCb, this);
+} // NimBLEClient
+
+
+/**
+ * @brief Destructor, private - only callable by NimBLEDevice::deleteClient
+ * to ensure proper disconnect and removal from device list.
+ */
+NimBLEClient::~NimBLEClient() {
+ // We may have allocated service references associated with this client.
+ // Before we are finished with the client, we must release resources.
+ deleteServices();
+
+ if(m_deleteCallbacks && m_pClientCallbacks != &defaultCallbacks) {
+ delete m_pClientCallbacks;
+ }
+
+ ble_npl_callout_deinit(&m_dcTimer);
+
+} // ~NimBLEClient
+
+
+/**
+ * @brief If we have asked to disconnect and the event does not
+ * occur within the supervision timeout + added delay, this will
+ * be called to reset the host in the case of a stalled controller.
+ */
+void NimBLEClient::dcTimerCb(ble_npl_event *event) {
+ /* NimBLEClient *pClient = (NimBLEClient*)event->arg;
+ NIMBLE_LOGC(LOG_TAG, "Timed out disconnecting from %s - resetting host",
+ std::string(pClient->getPeerAddress()).c_str());
+ */
+ ble_hs_sched_reset(BLE_HS_ECONTROLLER);
+}
+
+
+/**
+ * @brief Delete all service objects created by this client and clear the vector.
+ */
+void NimBLEClient::deleteServices() {
+ NIMBLE_LOGD(LOG_TAG, ">> deleteServices");
+ // Delete all the services.
+ for(auto &it: m_servicesVector) {
+ delete it;
+ }
+ m_servicesVector.clear();
+
+ NIMBLE_LOGD(LOG_TAG, "<< deleteServices");
+} // deleteServices
+
+
+/**
+ * @brief Delete service by UUID
+ * @param [in] uuid The UUID of the service to be deleted from the local database.
+ * @return Number of services left.
+ */
+size_t NimBLEClient::deleteService(const NimBLEUUID &uuid) {
+ NIMBLE_LOGD(LOG_TAG, ">> deleteService");
+ // Delete the requested service.
+ for(auto it = m_servicesVector.begin(); it != m_servicesVector.end(); ++it) {
+ if((*it)->getUUID() == uuid) {
+ delete *it;
+ m_servicesVector.erase(it);
+ break;
+ }
+ }
+
+ NIMBLE_LOGD(LOG_TAG, "<< deleteService");
+
+ return m_servicesVector.size();
+} // deleteServices
+
+
+/**
+ * @brief Connect to the BLE Server.
+ * @param [in] deleteAttibutes If true this will delete any attribute objects this client may already\n
+ * have created and clears the vectors after successful connection.
+ * @return True on success.
+ */
+bool NimBLEClient::connect(bool deleteAttibutes) {
+ return connect(m_peerAddress, deleteAttibutes);
+}
+
+/**
+ * @brief Connect to an advertising device.
+ * @param [in] device The device to connect to.
+ * @param [in] deleteAttibutes If true this will delete any attribute objects this client may already\n
+ * have created and clears the vectors after successful connection.
+ * @return True on success.
+ */
+bool NimBLEClient::connect(NimBLEAdvertisedDevice* device, bool deleteAttibutes) {
+ NimBLEAddress address(device->getAddress());
+ return connect(address, deleteAttibutes);
+}
+
+
+/**
+ * @brief Connect to the BLE Server.
+ * @param [in] address The address of the server.
+ * @param [in] deleteAttibutes If true this will delete any attribute objects this client may already\n
+ * have created and clears the vectors after successful connection.
+ * @return True on success.
+ */
+bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttibutes) {
+ NIMBLE_LOGD(LOG_TAG, ">> connect(%s)", address.toString().c_str());
+
+ if(!NimBLEDevice::m_synced) {
+ NIMBLE_LOGC(LOG_TAG, "Host reset, wait for sync.");
+ return false;
+ }
+
+ if(isConnected() || m_connEstablished || m_pTaskData != nullptr) {
+ NIMBLE_LOGE(LOG_TAG, "Client busy, connected to %s, id=%d",
+ std::string(m_peerAddress).c_str(), getConnId());
+ return false;
+ }
+
+ ble_addr_t peerAddr_t;
+ memcpy(&peerAddr_t.val, address.getNative(),6);
+ peerAddr_t.type = address.getType();
+ if(ble_gap_conn_find_by_addr(&peerAddr_t, NULL) == 0) {
+ NIMBLE_LOGE(LOG_TAG, "A connection to %s already exists",
+ address.toString().c_str());
+ return false;
+ }
+
+ if(address == NimBLEAddress("")) {
+ NIMBLE_LOGE(LOG_TAG, "Invalid peer address;(NULL)");
+ return false;
+ } else {
+ m_peerAddress = address;
+ }
+
+ TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
+ ble_task_data_t taskData = {this, cur_task, 0, nullptr};
+ m_pTaskData = &taskData;
+ int rc = 0;
+
+ /* Try to connect the the advertiser. Allow 30 seconds (30000 ms) for
+ * timeout (default value of m_connectTimeout).
+ * Loop on BLE_HS_EBUSY if the scan hasn't stopped yet.
+ */
+ do {
+ rc = ble_gap_connect(NimBLEDevice::m_own_addr_type, &peerAddr_t,
+ m_connectTimeout, &m_pConnParams,
+ NimBLEClient::handleGapEvent, this);
+ switch (rc) {
+ case 0:
+ break;
+
+ case BLE_HS_EBUSY:
+ // Scan was still running, stop it and try again
+ if (!NimBLEDevice::getScan()->stop()) {
+ rc = BLE_HS_EUNKNOWN;
+ }
+ break;
+
+ case BLE_HS_EDONE:
+ // A connection to this device already exists, do not connect twice.
+ NIMBLE_LOGE(LOG_TAG, "Already connected to device; addr=%s",
+ std::string(m_peerAddress).c_str());
+ break;
+
+ case BLE_HS_EALREADY:
+ // Already attemting to connect to this device, cancel the previous
+ // attempt and report failure here so we don't get 2 connections.
+ NIMBLE_LOGE(LOG_TAG, "Already attempting to connect to %s - cancelling",
+ std::string(m_peerAddress).c_str());
+ ble_gap_conn_cancel();
+ break;
+
+ default:
+ NIMBLE_LOGE(LOG_TAG, "Failed to connect to %s, rc=%d; %s",
+ std::string(m_peerAddress).c_str(),
+ rc, NimBLEUtils::returnCodeToString(rc));
+ break;
+ }
+
+ } while (rc == BLE_HS_EBUSY);
+
+ m_lastErr = rc;
+
+ if(rc != 0) {
+ m_pTaskData = nullptr;
+ return false;
+ }
+
+#ifdef ulTaskNotifyValueClear
+ // Clear the task notification value to ensure we block
+ ulTaskNotifyValueClear(cur_task, ULONG_MAX);
+#endif
+ // Wait for the connect timeout time +1 second for the connection to complete
+ if(ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(m_connectTimeout + 1000)) == pdFALSE) {
+ m_pTaskData = nullptr;
+ // If a connection was made but no response from MTU exchange; disconnect
+ if(isConnected()) {
+ NIMBLE_LOGE(LOG_TAG, "Connect timeout - no response");
+ disconnect();
+ } else {
+ // workaround; if the controller doesn't cancel the connection
+ // at the timeout, cancel it here.
+ NIMBLE_LOGE(LOG_TAG, "Connect timeout - cancelling");
+ ble_gap_conn_cancel();
+ }
+
+ return false;
+
+ } else if(taskData.rc != 0){
+ m_lastErr = taskData.rc;
+ NIMBLE_LOGE(LOG_TAG, "Connection failed; status=%d %s",
+ taskData.rc,
+ NimBLEUtils::returnCodeToString(taskData.rc));
+ // If the failure was not a result of a disconnection
+ // make sure we disconnect now to avoid dangling connections
+ if(isConnected()) {
+ disconnect();
+ }
+ return false;
+ } else {
+ NIMBLE_LOGI(LOG_TAG, "Connection established");
+ }
+
+ if(deleteAttibutes) {
+ deleteServices();
+ }
+
+ m_connEstablished = true;
+ m_pClientCallbacks->onConnect(this);
+
+ NIMBLE_LOGD(LOG_TAG, "<< connect()");
+ // Check if still connected before returning
+ return isConnected();
+} // connect
+
+
+/**
+ * @brief Initiate a secure connection (pair/bond) with the server.\n
+ * Called automatically when a characteristic or descriptor requires encryption or authentication to access it.
+ * @return True on success.
+ */
+bool NimBLEClient::secureConnection() {
+ TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
+ ble_task_data_t taskData = {this, cur_task, 0, nullptr};
+
+ int retryCount = 1;
+
+ do {
+ m_pTaskData = &taskData;
+
+ int rc = NimBLEDevice::startSecurity(m_conn_id);
+ if(rc != 0){
+ m_lastErr = rc;
+ m_pTaskData = nullptr;
+ return false;
+ }
+
+#ifdef ulTaskNotifyValueClear
+ // Clear the task notification value to ensure we block
+ ulTaskNotifyValueClear(cur_task, ULONG_MAX);
+#endif
+ ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
+ } while (taskData.rc == (BLE_HS_ERR_HCI_BASE + BLE_ERR_PINKEY_MISSING) && retryCount--);
+
+ if(taskData.rc != 0){
+ m_lastErr = taskData.rc;
+ return false;
+ }
+
+ return true;
+} // secureConnection
+
+
+/**
+ * @brief Disconnect from the peer.
+ * @return Error code from NimBLE stack, 0 = success.
+ */
+int NimBLEClient::disconnect(uint8_t reason) {
+ NIMBLE_LOGD(LOG_TAG, ">> disconnect()");
+ int rc = 0;
+ if(isConnected()) {
+ // If the timer was already started, ignore this call.
+ if(ble_npl_callout_is_active(&m_dcTimer)) {
+ NIMBLE_LOGI(LOG_TAG, "Already disconnecting, timer started");
+ return BLE_HS_EALREADY;
+ }
+
+ ble_gap_conn_desc desc;
+ if(ble_gap_conn_find(m_conn_id, &desc) != 0){
+ NIMBLE_LOGI(LOG_TAG, "Connection ID not found");
+ return BLE_HS_EALREADY;
+ }
+
+ // We use a timer to detect a controller error in the event that it does
+ // not inform the stack when disconnection is complete.
+ // This is a common error in certain esp-idf versions.
+ // The disconnect timeout time is the supervison timeout time + 1 second.
+ // In the case that the event happenss shortly after the supervision timeout
+ // we don't want to prematurely reset the host.
+ ble_npl_time_t ticks;
+ ble_npl_time_ms_to_ticks((desc.supervision_timeout + 100) * 10, &ticks);
+ ble_npl_callout_reset(&m_dcTimer, ticks);
+
+ rc = ble_gap_terminate(m_conn_id, reason);
+ if (rc != 0) {
+ if(rc != BLE_HS_EALREADY) {
+ ble_npl_callout_stop(&m_dcTimer);
+ }
+ NIMBLE_LOGE(LOG_TAG, "ble_gap_terminate failed: rc=%d %s",
+ rc, NimBLEUtils::returnCodeToString(rc));
+ }
+ } else {
+ NIMBLE_LOGD(LOG_TAG, "Not connected to any peers");
+ }
+
+ NIMBLE_LOGD(LOG_TAG, "<< disconnect()");
+ m_lastErr = rc;
+ return rc;
+} // disconnect
+
+
+/**
+ * @brief Set the connection paramaters to use when connecting to a server.
+ * @param [in] minInterval The minimum connection interval in 1.25ms units.
+ * @param [in] maxInterval The maximum connection interval in 1.25ms units.
+ * @param [in] latency The number of packets allowed to skip (extends max interval).
+ * @param [in] timeout The timeout time in 10ms units before disconnecting.
+ * @param [in] scanInterval The scan interval to use when attempting to connect in 0.625ms units.
+ * @param [in] scanWindow The scan window to use when attempting to connect in 0.625ms units.
+ */
+void NimBLEClient::setConnectionParams(uint16_t minInterval, uint16_t maxInterval,
+ uint16_t latency, uint16_t timeout,
+ uint16_t scanInterval, uint16_t scanWindow)/*,
+ uint16_t minConnTime, uint16_t maxConnTime)*/
+{
+
+ m_pConnParams.scan_itvl = scanInterval;
+ m_pConnParams.scan_window = scanWindow;
+ m_pConnParams.itvl_min = minInterval;
+ m_pConnParams.itvl_max = maxInterval;
+ m_pConnParams.latency = latency;
+ m_pConnParams.supervision_timeout = timeout;
+
+ // These are not used by NimBLE at this time - Must leave at defaults
+ //m_pConnParams->min_ce_len = minConnTime; // Minimum length of connection event in 0.625ms units
+ //m_pConnParams->max_ce_len = maxConnTime; // Maximum length of connection event in 0.625ms units
+
+ int rc = NimBLEUtils::checkConnParams(&m_pConnParams);
+ assert(rc == 0 && "Invalid Connection parameters");
+} // setConnectionParams
+
+
+/**
+ * @brief Update the connection parameters:
+ * * Can only be used after a connection has been established.
+ * @param [in] minInterval The minimum connection interval in 1.25ms units.
+ * @param [in] maxInterval The maximum connection interval in 1.25ms units.
+ * @param [in] latency The number of packets allowed to skip (extends max interval).
+ * @param [in] timeout The timeout time in 10ms units before disconnecting.
+ */
+void NimBLEClient::updateConnParams(uint16_t minInterval, uint16_t maxInterval,
+ uint16_t latency, uint16_t timeout)
+{
+ ble_gap_upd_params params;
+
+ params.latency = latency;
+ params.itvl_max = maxInterval;
+ params.itvl_min = minInterval;
+ params.supervision_timeout = timeout;
+ // These are not used by NimBLE at this time - Must leave at defaults
+ params.min_ce_len = BLE_GAP_INITIAL_CONN_MIN_CE_LEN;
+ params.max_ce_len = BLE_GAP_INITIAL_CONN_MAX_CE_LEN;
+
+ int rc = ble_gap_update_params(m_conn_id, ¶ms);
+ if(rc != 0) {
+ NIMBLE_LOGE(LOG_TAG, "Update params error: %d, %s",
+ rc, NimBLEUtils::returnCodeToString(rc));
+ }
+} // updateConnParams
+
+
+/**
+ * @brief Request an update of the data packet length.
+ * * Can only be used after a connection has been established.
+ * @details Sends a data length update request to the server the client is connected to.
+ * The Data Length Extension (DLE) allows to increase the Data Channel Payload from 27 bytes to up to 251 bytes.
+ * The server needs to support the Bluetooth 4.2 specifications, to be capable of DLE.
+ * @param [in] tx_octets The preferred number of payload octets to use (Range 0x001B-0x00FB).
+ */
+void NimBLEClient::setDataLen(uint16_t tx_octets) {
+#if defined(CONFIG_NIMBLE_CPP_IDF) && !defined(ESP_IDF_VERSION) || \
+ (ESP_IDF_VERSION_MAJOR * 100 + ESP_IDF_VERSION_MINOR * 10 + ESP_IDF_VERSION_PATCH) < 432
+ return;
+#else
+ uint16_t tx_time = (tx_octets + 14) * 8;
+
+ int rc = ble_gap_set_data_len(m_conn_id, tx_octets, tx_time);
+ if(rc != 0) {
+ NIMBLE_LOGE(LOG_TAG, "Set data length error: %d, %s", rc, NimBLEUtils::returnCodeToString(rc));
+ }
+#endif
+} // setDataLen
+
+
+/**
+ * @brief Get detailed information about the current peer connection.
+ */
+NimBLEConnInfo NimBLEClient::getConnInfo() {
+ NimBLEConnInfo connInfo;
+ if (!isConnected()) {
+ NIMBLE_LOGE(LOG_TAG, "Not connected");
+ } else {
+ int rc = ble_gap_conn_find(m_conn_id, &connInfo.m_desc);
+ if (rc != 0) {
+ NIMBLE_LOGE(LOG_TAG, "Connection info not found");
+ }
+ }
+
+ return connInfo;
+} // getConnInfo
+
+
+/**
+ * @brief Set the timeout to wait for connection attempt to complete.
+ * @param [in] time The number of seconds before timeout.
+ */
+void NimBLEClient::setConnectTimeout(uint8_t time) {
+ m_connectTimeout = (uint32_t)(time * 1000);
+} // setConnectTimeout
+
+
+/**
+ * @brief Get the connection id for this client.
+ * @return The connection id.
+ */
+uint16_t NimBLEClient::getConnId() {
+ return m_conn_id;
+} // getConnId
+
+
+/**
+ * @brief Retrieve the address of the peer.
+ */
+NimBLEAddress NimBLEClient::getPeerAddress() {
+ return m_peerAddress;
+} // getPeerAddress
+
+
+/**
+ * @brief Set the peer address.
+ * @param [in] address The address of the peer that this client is
+ * connected or should connect to.
+ */
+void NimBLEClient::setPeerAddress(const NimBLEAddress &address) {
+ if(isConnected()) {
+ NIMBLE_LOGE(LOG_TAG, "Cannot set peer address while connected");
+ return;
+ }
+
+ m_peerAddress = address;
+ NIMBLE_LOGD(LOG_TAG, "Peer address set: %s", std::string(m_peerAddress).c_str());
+} // setPeerAddress
+
+
+/**
+ * @brief Ask the BLE server for the RSSI value.
+ * @return The RSSI value.
+ */
+int NimBLEClient::getRssi() {
+ NIMBLE_LOGD(LOG_TAG, ">> getRssi()");
+ if (!isConnected()) {
+ NIMBLE_LOGE(LOG_TAG, "<< getRssi(): Not connected");
+ return 0;
+ }
+
+ int8_t rssiValue = 0;
+ int rc = ble_gap_conn_rssi(m_conn_id, &rssiValue);
+ if(rc != 0) {
+ NIMBLE_LOGE(LOG_TAG, "Failed to read RSSI error code: %d, %s",
+ rc, NimBLEUtils::returnCodeToString(rc));
+ m_lastErr = rc;
+ return 0;
+ }
+
+ return rssiValue;
+} // getRssi
+
+
+/**
+ * @brief Get iterator to the beginning of the vector of remote service pointers.
+ * @return An iterator to the beginning of the vector of remote service pointers.
+ */
+std::vector::iterator NimBLEClient::begin() {
+ return m_servicesVector.begin();
+}
+
+
+/**
+ * @brief Get iterator to the end of the vector of remote service pointers.
+ * @return An iterator to the end of the vector of remote service pointers.
+ */
+std::vector::iterator NimBLEClient::end() {
+ return m_servicesVector.end();
+}
+
+
+/**
+ * @brief Get the service BLE Remote Service instance corresponding to the uuid.
+ * @param [in] uuid The UUID of the service being sought.
+ * @return A pointer to the service or nullptr if not found.
+ */
+NimBLERemoteService* NimBLEClient::getService(const char* uuid) {
+ return getService(NimBLEUUID(uuid));
+} // getService
+
+
+/**
+ * @brief Get the service object corresponding to the uuid.
+ * @param [in] uuid The UUID of the service being sought.
+ * @return A pointer to the service or nullptr if not found.
+ */
+NimBLERemoteService* NimBLEClient::getService(const NimBLEUUID &uuid) {
+ NIMBLE_LOGD(LOG_TAG, ">> getService: uuid: %s", uuid.toString().c_str());
+
+ for(auto &it: m_servicesVector) {
+ if(it->getUUID() == uuid) {
+ NIMBLE_LOGD(LOG_TAG, "<< getService: found the service with uuid: %s", uuid.toString().c_str());
+ return it;
+ }
+ }
+
+ size_t prev_size = m_servicesVector.size();
+ if(retrieveServices(&uuid)) {
+ if(m_servicesVector.size() > prev_size) {
+ return m_servicesVector.back();
+ }
+
+ // If the request was successful but 16/32 bit uuid not found
+ // try again with the 128 bit uuid.
+ if(uuid.bitSize() == BLE_UUID_TYPE_16 ||
+ uuid.bitSize() == BLE_UUID_TYPE_32)
+ {
+ NimBLEUUID uuid128(uuid);
+ uuid128.to128();
+ if(retrieveServices(&uuid128)) {
+ if(m_servicesVector.size() > prev_size) {
+ return m_servicesVector.back();
+ }
+ }
+ } else {
+ // If the request was successful but the 128 bit uuid not found
+ // try again with the 16 bit uuid.
+ NimBLEUUID uuid16(uuid);
+ uuid16.to16();
+ // if the uuid was 128 bit but not of the BLE base type this check will fail
+ if (uuid16.bitSize() == BLE_UUID_TYPE_16) {
+ if(retrieveServices(&uuid16)) {
+ if(m_servicesVector.size() > prev_size) {
+ return m_servicesVector.back();
+ }
+ }
+ }
+ }
+ }
+
+ NIMBLE_LOGD(LOG_TAG, "<< getService: not found");
+ return nullptr;
+} // getService
+
+
+/**
+ * @brief Get a pointer to the vector of found services.
+ * @param [in] refresh If true the current services vector will be cleared and\n
+ * all services will be retrieved from the peripheral.\n
+ * If false the vector will be returned with the currently stored services.
+ * @return A pointer to the vector of available services.
+ */
+std::vector* NimBLEClient::getServices(bool refresh) {
+ if(refresh) {
+ deleteServices();
+
+ if (!retrieveServices()) {
+ NIMBLE_LOGE(LOG_TAG, "Error: Failed to get services");
+ }
+ else{
+ NIMBLE_LOGI(LOG_TAG, "Found %d services", m_servicesVector.size());
+ }
+ }
+ return &m_servicesVector;
+} // getServices
+
+
+/**
+ * @brief Retrieves the full database of attributes that the peripheral has available.
+ */
+void NimBLEClient::discoverAttributes() {
+ for(auto svc: *getServices(true)) {
+ for(auto chr: *svc->getCharacteristics(true)) {
+ chr->getDescriptors(true);
+ }
+ }
+} // discoverAttributes
+
+
+/**
+ * @brief Ask the remote %BLE server for its services.\n
+ * Here we ask the server for its set of services and wait until we have received them all.
+ * @return true on success otherwise false if an error occurred
+ */
+bool NimBLEClient::retrieveServices(const NimBLEUUID *uuid_filter) {
+/**
+ * Design
+ * ------
+ * We invoke ble_gattc_disc_all_svcs. This will request a list of the services exposed by the
+ * peer BLE partner to be returned in the callback function provided.
+ */
+
+ NIMBLE_LOGD(LOG_TAG, ">> retrieveServices");
+
+ if(!isConnected()){
+ NIMBLE_LOGE(LOG_TAG, "Disconnected, could not retrieve services -aborting");
+ return false;
+ }
+
+ int rc = 0;
+ TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
+ ble_task_data_t taskData = {this, cur_task, 0, nullptr};
+
+ if(uuid_filter == nullptr) {
+ rc = ble_gattc_disc_all_svcs(m_conn_id, NimBLEClient::serviceDiscoveredCB, &taskData);
+ } else {
+ rc = ble_gattc_disc_svc_by_uuid(m_conn_id, &uuid_filter->getNative()->u,
+ NimBLEClient::serviceDiscoveredCB, &taskData);
+ }
+
+ if (rc != 0) {
+ NIMBLE_LOGE(LOG_TAG, "ble_gattc_disc_all_svcs: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
+ m_lastErr = rc;
+ return false;
+ }
+
+#ifdef ulTaskNotifyValueClear
+ // Clear the task notification value to ensure we block
+ ulTaskNotifyValueClear(cur_task, ULONG_MAX);
+#endif
+
+ // wait until we have all the services
+ ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
+ m_lastErr = taskData.rc;
+
+ if(taskData.rc == 0){
+ NIMBLE_LOGD(LOG_TAG, "<< retrieveServices");
+ return true;
+ }
+ else {
+ NIMBLE_LOGE(LOG_TAG, "Could not retrieve services");
+ return false;
+ }
+} // getServices
+
+
+/**
+ * @brief STATIC Callback for the service discovery API function.\n
+ * When a service is found or there is none left or there was an error
+ * the API will call this and report findings.
+ */
+int NimBLEClient::serviceDiscoveredCB(
+ uint16_t conn_handle,
+ const struct ble_gatt_error *error,
+ const struct ble_gatt_svc *service, void *arg)
+{
+ NIMBLE_LOGD(LOG_TAG,"Service Discovered >> status: %d handle: %d",
+ error->status, (error->status == 0) ? service->start_handle : -1);
+
+ ble_task_data_t *pTaskData = (ble_task_data_t*)arg;
+ NimBLEClient *client = (NimBLEClient*)pTaskData->pATT;
+
+ // Make sure the service discovery is for this device
+ if(client->getConnId() != conn_handle){
+ return 0;
+ }
+
+ if(error->status == 0) {
+ // Found a service - add it to the vector
+ NimBLERemoteService* pRemoteService = new NimBLERemoteService(client, service);
+ client->m_servicesVector.push_back(pRemoteService);
+ return 0;
+ }
+
+ if(error->status == BLE_HS_EDONE) {
+ pTaskData->rc = 0;
+ } else {
+ NIMBLE_LOGE(LOG_TAG, "characteristicDiscCB() rc=%d %s",
+ error->status,
+ NimBLEUtils::returnCodeToString(error->status));
+ pTaskData->rc = error->status;
+ }
+
+ xTaskNotifyGive(pTaskData->task);
+
+ NIMBLE_LOGD(LOG_TAG,"<< << Service Discovered");
+ return error->status;
+}
+
+
+/**
+ * @brief Get the value of a specific characteristic associated with a specific service.
+ * @param [in] serviceUUID The service that owns the characteristic.
+ * @param [in] characteristicUUID The characteristic whose value we wish to read.
+ * @returns characteristic value or an empty string if not found
+ */
+std::string NimBLEClient::getValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID) {
+ NIMBLE_LOGD(LOG_TAG, ">> getValue: serviceUUID: %s, characteristicUUID: %s",
+ serviceUUID.toString().c_str(), characteristicUUID.toString().c_str());
+
+ std::string ret = "";
+ NimBLERemoteService* pService = getService(serviceUUID);
+
+ if(pService != nullptr) {
+ NimBLERemoteCharacteristic* pChar = pService->getCharacteristic(characteristicUUID);
+ if(pChar != nullptr) {
+ ret = pChar->readValue();
+ }
+ }
+
+ NIMBLE_LOGD(LOG_TAG, "<> setValue: serviceUUID: %s, characteristicUUID: %s",
+ serviceUUID.toString().c_str(), characteristicUUID.toString().c_str());
+
+ bool ret = false;
+ NimBLERemoteService* pService = getService(serviceUUID);
+
+ if(pService != nullptr) {
+ NimBLERemoteCharacteristic* pChar = pService->getCharacteristic(characteristicUUID);
+ if(pChar != nullptr) {
+ ret = pChar->writeValue(value, response);
+ }
+ }
+
+ NIMBLE_LOGD(LOG_TAG, "<< setValue");
+ return ret;
+} // setValue
+
+
+/**
+ * @brief Get the remote characteristic with the specified handle.
+ * @param [in] handle The handle of the desired characteristic.
+ * @returns The matching remote characteristic, nullptr otherwise.
+ */
+NimBLERemoteCharacteristic* NimBLEClient::getCharacteristic(const uint16_t handle)
+{
+ NimBLERemoteService *pService = nullptr;
+ for(auto it = m_servicesVector.begin(); it != m_servicesVector.end(); ++it) {
+ if ((*it)->getStartHandle() <= handle && handle <= (*it)->getEndHandle()) {
+ pService = *it;
+ break;
+ }
+ }
+
+ if (pService != nullptr) {
+ for (auto it = pService->begin(); it != pService->end(); ++it) {
+ if ((*it)->getHandle() == handle) {
+ return *it;
+ }
+ }
+ }
+
+ return nullptr;
+}
+
+/**
+ * @brief Get the current mtu of this connection.
+ * @returns The MTU value.
+ */
+uint16_t NimBLEClient::getMTU() {
+ return ble_att_mtu(m_conn_id);
+} // getMTU
+
+
+/**
+ * @brief Handle a received GAP event.
+ * @param [in] event The event structure sent by the NimBLE stack.
+ * @param [in] arg A pointer to the client instance that registered for this callback.
+ */
+ /*STATIC*/
+ int NimBLEClient::handleGapEvent(struct ble_gap_event *event, void *arg) {
+ NimBLEClient* client = (NimBLEClient*)arg;
+ int rc;
+
+ NIMBLE_LOGD(LOG_TAG, "Got Client event %s", NimBLEUtils::gapEventToString(event->type));
+
+ switch(event->type) {
+
+ case BLE_GAP_EVENT_DISCONNECT: {
+ rc = event->disconnect.reason;
+ // If Host reset tell the device now before returning to prevent
+ // any errors caused by calling host functions before resyncing.
+ switch(rc) {
+ case BLE_HS_ECONTROLLER:
+ case BLE_HS_ETIMEOUT_HCI:
+ case BLE_HS_ENOTSYNCED:
+ case BLE_HS_EOS:
+ NIMBLE_LOGC(LOG_TAG, "Disconnect - host reset, rc=%d", rc);
+ NimBLEDevice::onReset(rc);
+ break;
+ default:
+ // Check that the event is for this client.
+ if(client->m_conn_id != event->disconnect.conn.conn_handle) {
+ return 0;
+ }
+ break;
+ }
+
+ // Stop the disconnect timer since we are now disconnected.
+ ble_npl_callout_stop(&client->m_dcTimer);
+
+ // Remove the device from ignore list so we will scan it again
+ NimBLEDevice::removeIgnored(client->m_peerAddress);
+
+ // No longer connected, clear the connection ID.
+ client->m_conn_id = BLE_HS_CONN_HANDLE_NONE;
+
+ // If we received a connected event but did not get established (no PDU)
+ // then a disconnect event will be sent but we should not send it to the
+ // app for processing. Instead we will ensure the task is released
+ // and report the error.
+ if(!client->m_connEstablished)
+ break;
+
+ NIMBLE_LOGI(LOG_TAG, "disconnect; reason=%d, %s",
+ rc, NimBLEUtils::returnCodeToString(rc));
+
+ client->m_connEstablished = false;
+ client->m_pClientCallbacks->onDisconnect(client);
+ break;
+ } // BLE_GAP_EVENT_DISCONNECT
+
+ case BLE_GAP_EVENT_CONNECT: {
+ // If we aren't waiting for this connection response
+ // we should drop the connection immediately.
+ if(client->isConnected() || client->m_pTaskData == nullptr) {
+ ble_gap_terminate(event->connect.conn_handle, BLE_ERR_REM_USER_CONN_TERM);
+ return 0;
+ }
+
+ rc = event->connect.status;
+ if (rc == 0) {
+ NIMBLE_LOGI(LOG_TAG, "Connected event");
+
+ client->m_conn_id = event->connect.conn_handle;
+
+ rc = ble_gattc_exchange_mtu(client->m_conn_id, NULL,NULL);
+ if(rc != 0) {
+ NIMBLE_LOGE(LOG_TAG, "MTU exchange error; rc=%d %s",
+ rc, NimBLEUtils::returnCodeToString(rc));
+ break;
+ }
+
+ // In the case of a multiconnecting device we ignore this device when
+ // scanning since we are already connected to it
+ NimBLEDevice::addIgnored(client->m_peerAddress);
+ } else {
+ client->m_conn_id = BLE_HS_CONN_HANDLE_NONE;
+ break;
+ }
+
+ return 0;
+ } // BLE_GAP_EVENT_CONNECT
+
+ case BLE_GAP_EVENT_NOTIFY_RX: {
+ if(client->m_conn_id != event->notify_rx.conn_handle)
+ return 0;
+
+ // If a notification comes before this flag is set we might
+ // access a vector while it is being cleared in connect()
+ if(!client->m_connEstablished) {
+ return 0;
+ }
+
+ NIMBLE_LOGD(LOG_TAG, "Notify Recieved for handle: %d",
+ event->notify_rx.attr_handle);
+
+ for(auto &it: client->m_servicesVector) {
+ // Dont waste cycles searching services without this handle in its range
+ if(it->getEndHandle() < event->notify_rx.attr_handle) {
+ continue;
+ }
+
+ auto cVector = &it->m_characteristicVector;
+ NIMBLE_LOGD(LOG_TAG, "checking service %s for handle: %d",
+ it->getUUID().toString().c_str(),
+ event->notify_rx.attr_handle);
+
+ auto characteristic = cVector->cbegin();
+ for(; characteristic != cVector->cend(); ++characteristic) {
+ if((*characteristic)->m_handle == event->notify_rx.attr_handle)
+ break;
+ }
+
+ if(characteristic != cVector->cend()) {
+ NIMBLE_LOGD(LOG_TAG, "Got Notification for characteristic %s",
+ (*characteristic)->toString().c_str());
+
+ uint32_t data_len = OS_MBUF_PKTLEN(event->notify_rx.om);
+ time_t t = time(nullptr);
+ ble_npl_hw_enter_critical();
+ (*characteristic)->m_value = std::string((char *)event->notify_rx.om->om_data, data_len);
+ (*characteristic)->m_timestamp = t;
+ ble_npl_hw_exit_critical(0);
+
+ if ((*characteristic)->m_notifyCallback != nullptr) {
+ NIMBLE_LOGD(LOG_TAG, "Invoking callback for notification on characteristic %s",
+ (*characteristic)->toString().c_str());
+ (*characteristic)->m_notifyCallback(*characteristic, event->notify_rx.om->om_data,
+ data_len, !event->notify_rx.indication);
+ }
+ break;
+ }
+ }
+
+ return 0;
+ } // BLE_GAP_EVENT_NOTIFY_RX
+
+ case BLE_GAP_EVENT_CONN_UPDATE_REQ:
+ case BLE_GAP_EVENT_L2CAP_UPDATE_REQ: {
+ if(client->m_conn_id != event->conn_update_req.conn_handle){
+ return 0;
+ }
+ NIMBLE_LOGD(LOG_TAG, "Peer requesting to update connection parameters");
+ NIMBLE_LOGD(LOG_TAG, "MinInterval: %d, MaxInterval: %d, Latency: %d, Timeout: %d",
+ event->conn_update_req.peer_params->itvl_min,
+ event->conn_update_req.peer_params->itvl_max,
+ event->conn_update_req.peer_params->latency,
+ event->conn_update_req.peer_params->supervision_timeout);
+
+ rc = client->m_pClientCallbacks->onConnParamsUpdateRequest(client,
+ event->conn_update_req.peer_params) ? 0 : BLE_ERR_CONN_PARMS;
+
+
+ if(!rc && event->type == BLE_GAP_EVENT_CONN_UPDATE_REQ ) {
+ event->conn_update_req.self_params->itvl_min = client->m_pConnParams.itvl_min;
+ event->conn_update_req.self_params->itvl_max = client->m_pConnParams.itvl_max;
+ event->conn_update_req.self_params->latency = client->m_pConnParams.latency;
+ event->conn_update_req.self_params->supervision_timeout = client->m_pConnParams.supervision_timeout;
+ }
+
+ NIMBLE_LOGD(LOG_TAG, "%s peer params", (rc == 0) ? "Accepted" : "Rejected");
+ return rc;
+ } // BLE_GAP_EVENT_CONN_UPDATE_REQ, BLE_GAP_EVENT_L2CAP_UPDATE_REQ
+
+ case BLE_GAP_EVENT_CONN_UPDATE: {
+ if(client->m_conn_id != event->conn_update.conn_handle){
+ return 0;
+ }
+ if(event->conn_update.status == 0) {
+ NIMBLE_LOGI(LOG_TAG, "Connection parameters updated.");
+ } else {
+ NIMBLE_LOGE(LOG_TAG, "Update connection parameters failed.");
+ }
+ return 0;
+ } // BLE_GAP_EVENT_CONN_UPDATE
+
+ case BLE_GAP_EVENT_ENC_CHANGE: {
+ if(client->m_conn_id != event->enc_change.conn_handle){
+ return 0;
+ }
+
+ if(event->enc_change.status == 0 ||
+ event->enc_change.status == (BLE_HS_ERR_HCI_BASE + BLE_ERR_PINKEY_MISSING))
+ {
+ struct ble_gap_conn_desc desc;
+ rc = ble_gap_conn_find(event->enc_change.conn_handle, &desc);
+ assert(rc == 0);
+
+ if (event->enc_change.status == (BLE_HS_ERR_HCI_BASE + BLE_ERR_PINKEY_MISSING)) {
+ // Key is missing, try deleting.
+ ble_store_util_delete_peer(&desc.peer_id_addr);
+ } else if(NimBLEDevice::m_securityCallbacks != nullptr) {
+ NimBLEDevice::m_securityCallbacks->onAuthenticationComplete(&desc);
+ } else {
+ client->m_pClientCallbacks->onAuthenticationComplete(&desc);
+ }
+ }
+
+ rc = event->enc_change.status;
+ break;
+ } //BLE_GAP_EVENT_ENC_CHANGE
+
+ case BLE_GAP_EVENT_MTU: {
+ if(client->m_conn_id != event->mtu.conn_handle){
+ return 0;
+ }
+ NIMBLE_LOGI(LOG_TAG, "mtu update event; conn_handle=%d mtu=%d",
+ event->mtu.conn_handle,
+ event->mtu.value);
+ rc = 0;
+ break;
+ } // BLE_GAP_EVENT_MTU
+
+ case BLE_GAP_EVENT_PASSKEY_ACTION: {
+ struct ble_sm_io pkey = {0,0};
+
+ if(client->m_conn_id != event->passkey.conn_handle)
+ return 0;
+
+ if (event->passkey.params.action == BLE_SM_IOACT_DISP) {
+ pkey.action = event->passkey.params.action;
+ pkey.passkey = NimBLEDevice::m_passkey; // This is the passkey to be entered on peer
+ rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
+ NIMBLE_LOGD(LOG_TAG, "ble_sm_inject_io result: %d", rc);
+
+ } else if (event->passkey.params.action == BLE_SM_IOACT_NUMCMP) {
+ NIMBLE_LOGD(LOG_TAG, "Passkey on device's display: %" PRIu32, event->passkey.params.numcmp);
+ pkey.action = event->passkey.params.action;
+ // Compatibility only - Do not use, should be removed the in future
+ if(NimBLEDevice::m_securityCallbacks != nullptr) {
+ pkey.numcmp_accept = NimBLEDevice::m_securityCallbacks->onConfirmPIN(event->passkey.params.numcmp);
+ ////////////////////////////////////////////////////
+ } else {
+ pkey.numcmp_accept = client->m_pClientCallbacks->onConfirmPIN(event->passkey.params.numcmp);
+ }
+
+ rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
+ NIMBLE_LOGD(LOG_TAG, "ble_sm_inject_io result: %d", rc);
+
+ //TODO: Handle out of band pairing
+ } else if (event->passkey.params.action == BLE_SM_IOACT_OOB) {
+ static uint8_t tem_oob[16] = {0};
+ pkey.action = event->passkey.params.action;
+ for (int i = 0; i < 16; i++) {
+ pkey.oob[i] = tem_oob[i];
+ }
+ rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
+ NIMBLE_LOGD(LOG_TAG, "ble_sm_inject_io result: %d", rc);
+ ////////
+ } else if (event->passkey.params.action == BLE_SM_IOACT_INPUT) {
+ NIMBLE_LOGD(LOG_TAG, "Enter the passkey");
+ pkey.action = event->passkey.params.action;
+
+ // Compatibility only - Do not use, should be removed the in future
+ if(NimBLEDevice::m_securityCallbacks != nullptr) {
+ pkey.passkey = NimBLEDevice::m_securityCallbacks->onPassKeyRequest();
+ /////////////////////////////////////////////
+ } else {
+ pkey.passkey = client->m_pClientCallbacks->onPassKeyRequest();
+ }
+
+ rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
+ NIMBLE_LOGD(LOG_TAG, "ble_sm_inject_io result: %d", rc);
+
+ } else if (event->passkey.params.action == BLE_SM_IOACT_NONE) {
+ NIMBLE_LOGD(LOG_TAG, "No passkey action required");
+ }
+
+ return 0;
+ } // BLE_GAP_EVENT_PASSKEY_ACTION
+
+ default: {
+ return 0;
+ }
+ } // Switch
+
+ if(client->m_pTaskData != nullptr) {
+ client->m_pTaskData->rc = rc;
+ if(client->m_pTaskData->task) {
+ xTaskNotifyGive(client->m_pTaskData->task);
+ }
+ client->m_pTaskData = nullptr;
+ }
+
+ return 0;
+} // handleGapEvent
+
+
+/**
+ * @brief Are we connected to a server?
+ * @return True if we are connected and false if we are not connected.
+ */
+bool NimBLEClient::isConnected() {
+ return m_conn_id != BLE_HS_CONN_HANDLE_NONE;
+} // isConnected
+
+
+/**
+ * @brief Set the callbacks that will be invoked when events are received.
+ * @param [in] pClientCallbacks A pointer to a class to receive the event callbacks.
+ * @param [in] deleteCallbacks If true this will delete the callback class sent when the client is destructed.
+ */
+void NimBLEClient::setClientCallbacks(NimBLEClientCallbacks* pClientCallbacks, bool deleteCallbacks) {
+ if (pClientCallbacks != nullptr){
+ m_pClientCallbacks = pClientCallbacks;
+ } else {
+ m_pClientCallbacks = &defaultCallbacks;
+ }
+ m_deleteCallbacks = deleteCallbacks;
+} // setClientCallbacks
+
+
+/**
+ * @brief Return a string representation of this client.
+ * @return A string representation of this client.
+ */
+std::string NimBLEClient::toString() {
+ std::string res = "peer address: " + m_peerAddress.toString();
+ res += "\nServices:\n";
+
+ for(auto &it: m_servicesVector) {
+ res += it->toString() + "\n";
+ }
+
+ return res;
+} // toString
+
+
+/**
+ * @brief Get the last error code reported by the NimBLE host
+ * @return int, the NimBLE error code.
+ */
+int NimBLEClient::getLastError() {
+ return m_lastErr;
+} // getLastError
+
+
+void NimBLEClientCallbacks::onConnect(NimBLEClient* pClient) {
+ NIMBLE_LOGD("NimBLEClientCallbacks", "onConnect: default");
+}
+
+void NimBLEClientCallbacks::onDisconnect(NimBLEClient* pClient) {
+ NIMBLE_LOGD("NimBLEClientCallbacks", "onDisconnect: default");
+}
+
+bool NimBLEClientCallbacks::onConnParamsUpdateRequest(NimBLEClient* pClient, const ble_gap_upd_params* params) {
+ NIMBLE_LOGD("NimBLEClientCallbacks", "onConnParamsUpdateRequest: default");
+ return true;
+}
+
+uint32_t NimBLEClientCallbacks::onPassKeyRequest(){
+ NIMBLE_LOGD("NimBLEClientCallbacks", "onPassKeyRequest: default: 123456");
+ return 123456;
+}
+/*
+void NimBLEClientCallbacks::onPassKeyNotify(uint32_t pass_key){
+ NIMBLE_LOGD("NimBLEClientCallbacks", "onPassKeyNotify: default: %d", pass_key);
+}
+
+bool NimBLEClientCallbacks::onSecurityRequest(){
+ NIMBLE_LOGD("NimBLEClientCallbacks", "onSecurityRequest: default: true");
+ return true;
+}*/
+void NimBLEClientCallbacks::onAuthenticationComplete(ble_gap_conn_desc* desc){
+ NIMBLE_LOGD("NimBLEClientCallbacks", "onAuthenticationComplete: default");
+}
+bool NimBLEClientCallbacks::onConfirmPIN(uint32_t pin){
+ NIMBLE_LOGD("NimBLEClientCallbacks", "onConfirmPIN: default: true");
+ return true;
+}
+
+#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/NimBLEClient.h b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEClient.h
new file mode 100644
index 0000000..37700b7
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEClient.h
@@ -0,0 +1,162 @@
+/*
+ * NimBLEClient.h
+ *
+ * Created: on Jan 26 2020
+ * Author H2zero
+ *
+ * Originally:
+ * BLEClient.h
+ *
+ * Created on: Mar 22, 2017
+ * Author: kolban
+ */
+
+#ifndef MAIN_NIMBLECLIENT_H_
+#define MAIN_NIMBLECLIENT_H_
+
+#include "nimconfig.h"
+#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
+
+#include "NimBLEAddress.h"
+#include "NimBLEUUID.h"
+#include "NimBLEUtils.h"
+#include "NimBLEConnInfo.h"
+#include "NimBLEAdvertisedDevice.h"
+#include "NimBLERemoteService.h"
+
+#include
+#include
+
+class NimBLERemoteService;
+class NimBLERemoteCharacteristic;
+class NimBLEClientCallbacks;
+class NimBLEAdvertisedDevice;
+
+/**
+ * @brief A model of a %BLE client.
+ */
+class NimBLEClient {
+public:
+ bool connect(NimBLEAdvertisedDevice* device, bool deleteAttibutes = true);
+ bool connect(const NimBLEAddress &address, bool deleteAttibutes = true);
+ bool connect(bool deleteAttibutes = true);
+ int disconnect(uint8_t reason = BLE_ERR_REM_USER_CONN_TERM);
+ NimBLEAddress getPeerAddress();
+ void setPeerAddress(const NimBLEAddress &address);
+ int getRssi();
+ std::vector* getServices(bool refresh = false);
+ std::vector::iterator begin();
+ std::vector::iterator end();
+ NimBLERemoteService* getService(const char* uuid);
+ NimBLERemoteService* getService(const NimBLEUUID &uuid);
+ void deleteServices();
+ size_t deleteService(const NimBLEUUID &uuid);
+ std::string getValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID);
+ bool setValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID,
+ const std::string &value, bool response = false);
+ NimBLERemoteCharacteristic* getCharacteristic(const uint16_t handle);
+ bool isConnected();
+ void setClientCallbacks(NimBLEClientCallbacks *pClientCallbacks,
+ bool deleteCallbacks = true);
+ std::string toString();
+ uint16_t getConnId();
+ uint16_t getMTU();
+ bool secureConnection();
+ void setConnectTimeout(uint8_t timeout);
+ void setConnectionParams(uint16_t minInterval, uint16_t maxInterval,
+ uint16_t latency, uint16_t timeout,
+ uint16_t scanInterval=16, uint16_t scanWindow=16);
+ void updateConnParams(uint16_t minInterval, uint16_t maxInterval,
+ uint16_t latency, uint16_t timeout);
+ void setDataLen(uint16_t tx_octets);
+ void discoverAttributes();
+ NimBLEConnInfo getConnInfo();
+ int getLastError();
+
+private:
+ NimBLEClient(const NimBLEAddress &peerAddress);
+ ~NimBLEClient();
+
+ friend class NimBLEDevice;
+ friend class NimBLERemoteService;
+
+ static int handleGapEvent(struct ble_gap_event *event, void *arg);
+ static int serviceDiscoveredCB(uint16_t conn_handle,
+ const struct ble_gatt_error *error,
+ const struct ble_gatt_svc *service,
+ void *arg);
+ static void dcTimerCb(ble_npl_event *event);
+ bool retrieveServices(const NimBLEUUID *uuid_filter = nullptr);
+
+ NimBLEAddress m_peerAddress;
+ int m_lastErr;
+ uint16_t m_conn_id;
+ bool m_connEstablished;
+ bool m_deleteCallbacks;
+ int32_t m_connectTimeout;
+ NimBLEClientCallbacks* m_pClientCallbacks;
+ ble_task_data_t* m_pTaskData;
+ ble_npl_callout m_dcTimer;
+
+ std::vector m_servicesVector;
+
+private:
+ friend class NimBLEClientCallbacks;
+ ble_gap_conn_params m_pConnParams;
+
+}; // class NimBLEClient
+
+
+/**
+ * @brief Callbacks associated with a %BLE client.
+ */
+class NimBLEClientCallbacks {
+public:
+ virtual ~NimBLEClientCallbacks() {};
+
+ /**
+ * @brief Called after client connects.
+ * @param [in] pClient A pointer to the calling client object.
+ */
+ virtual void onConnect(NimBLEClient* pClient);
+
+ /**
+ * @brief Called when disconnected from the server.
+ * @param [in] pClient A pointer to the calling client object.
+ */
+ virtual void onDisconnect(NimBLEClient* pClient);
+
+ /**
+ * @brief Called when server requests to update the connection parameters.
+ * @param [in] pClient A pointer to the calling client object.
+ * @param [in] params A pointer to the struct containing the connection parameters requested.
+ * @return True to accept the parmeters.
+ */
+ virtual bool onConnParamsUpdateRequest(NimBLEClient* pClient, const ble_gap_upd_params* params);
+
+ /**
+ * @brief Called when server requests a passkey for pairing.
+ * @return The passkey to be sent to the server.
+ */
+ virtual uint32_t onPassKeyRequest();
+
+ /*virtual void onPassKeyNotify(uint32_t pass_key);
+ virtual bool onSecurityRequest();*/
+
+ /**
+ * @brief Called when the pairing procedure is complete.
+ * @param [in] desc A pointer to the struct containing the connection information.\n
+ * This can be used to check the status of the connection encryption/pairing.
+ */
+ virtual void onAuthenticationComplete(ble_gap_conn_desc* desc);
+
+ /**
+ * @brief Called when using numeric comparision for pairing.
+ * @param [in] pin The pin to compare with the server.
+ * @return True to accept the pin.
+ */
+ virtual bool onConfirmPIN(uint32_t pin);
+};
+
+#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
+#endif /* MAIN_NIMBLECLIENT_H_ */
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/NimBLEConnInfo.h b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEConnInfo.h
new file mode 100644
index 0000000..e357d8c
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEConnInfo.h
@@ -0,0 +1,55 @@
+#ifndef NIMBLECONNINFO_H_
+#define NIMBLECONNINFO_H_
+
+#include "NimBLEAddress.h"
+
+/**
+ * @brief Connection information.
+ */
+class NimBLEConnInfo {
+friend class NimBLEServer;
+friend class NimBLEClient;
+ ble_gap_conn_desc m_desc;
+ NimBLEConnInfo() { m_desc = {}; }
+ NimBLEConnInfo(ble_gap_conn_desc desc) { m_desc = desc; }
+public:
+ /** @brief Gets the over-the-air address of the connected peer */
+ NimBLEAddress getAddress() { return NimBLEAddress(m_desc.peer_ota_addr); }
+
+ /** @brief Gets the ID address of the connected peer */
+ NimBLEAddress getIdAddress() { return NimBLEAddress(m_desc.peer_id_addr); }
+
+ /** @brief Gets the connection handle of the connected peer */
+ uint16_t getConnHandle() { return m_desc.conn_handle; }
+
+ /** @brief Gets the connection interval for this connection (in 1.25ms units) */
+ uint16_t getConnInterval() { return m_desc.conn_itvl; }
+
+ /** @brief Gets the supervision timeout for this connection (in 10ms units) */
+ uint16_t getConnTimeout() { return m_desc.supervision_timeout; }
+
+ /** @brief Gets the allowable latency for this connection (unit = number of intervals) */
+ uint16_t getConnLatency() { return m_desc.conn_latency; }
+
+ /** @brief Gets the maximum transmission unit size for this connection (in bytes) */
+ uint16_t getMTU() { return ble_att_mtu(m_desc.conn_handle); }
+
+ /** @brief Check if we are in the master role in this connection */
+ bool isMaster() { return (m_desc.role == BLE_GAP_ROLE_MASTER); }
+
+ /** @brief Check if we are in the slave role in this connection */
+ bool isSlave() { return (m_desc.role == BLE_GAP_ROLE_SLAVE); }
+
+ /** @brief Check if we are connected to a bonded peer */
+ bool isBonded() { return (m_desc.sec_state.bonded == 1); }
+
+ /** @brief Check if the connection in encrypted */
+ bool isEncrypted() { return (m_desc.sec_state.encrypted == 1); }
+
+ /** @brief Check if the the connection has been authenticated */
+ bool isAuthenticated() { return (m_desc.sec_state.authenticated == 1); }
+
+ /** @brief Gets the key size used to encrypt the connection */
+ uint8_t getSecKeySize() { return m_desc.sec_state.key_size; }
+};
+#endif
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/NimBLEDescriptor.cpp b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEDescriptor.cpp
new file mode 100644
index 0000000..5b0db1a
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEDescriptor.cpp
@@ -0,0 +1,297 @@
+/*
+ * NimBLEDescriptor.cpp
+ *
+ * Created: on March 10, 2020
+ * Author H2zero
+ *
+ * Originally:
+ *
+ * BLEDescriptor.cpp
+ *
+ * Created on: Jun 22, 2017
+ * Author: kolban
+ */
+
+#include "nimconfig.h"
+#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
+
+#include "NimBLEService.h"
+#include "NimBLEDescriptor.h"
+#include "NimBLELog.h"
+
+#include
+
+#define NULL_HANDLE (0xffff)
+
+static const char* LOG_TAG = "NimBLEDescriptor";
+static NimBLEDescriptorCallbacks defaultCallbacks;
+
+
+/**
+ * @brief NimBLEDescriptor constructor.
+ */
+NimBLEDescriptor::NimBLEDescriptor(const char* uuid, uint16_t properties, uint16_t max_len,
+ NimBLECharacteristic* pCharacteristic)
+: NimBLEDescriptor(NimBLEUUID(uuid), max_len, properties, pCharacteristic) {
+}
+
+
+/**
+ * @brief NimBLEDescriptor constructor.
+ */
+NimBLEDescriptor::NimBLEDescriptor(NimBLEUUID uuid, uint16_t properties, uint16_t max_len,
+ NimBLECharacteristic* pCharacteristic)
+{
+ m_uuid = uuid;
+ m_value.attr_len = 0; // Initial length is 0.
+ m_value.attr_max_len = max_len; // Maximum length of the data.
+ m_handle = NULL_HANDLE; // Handle is initially unknown.
+ m_pCharacteristic = pCharacteristic;
+ m_pCallbacks = &defaultCallbacks; // No initial callback.
+ m_value.attr_value = (uint8_t*) calloc(max_len,1); // Allocate storage for the value.
+ m_properties = 0;
+ m_removed = 0;
+
+ if (properties & BLE_GATT_CHR_F_READ) { // convert uint16_t properties to uint8_t
+ m_properties |= BLE_ATT_F_READ;
+ }
+ if (properties & (BLE_GATT_CHR_F_WRITE_NO_RSP | BLE_GATT_CHR_F_WRITE)) {
+ m_properties |= BLE_ATT_F_WRITE;
+ }
+ if (properties & BLE_GATT_CHR_F_READ_ENC) {
+ m_properties |= BLE_ATT_F_READ_ENC;
+ }
+ if (properties & BLE_GATT_CHR_F_READ_AUTHEN) {
+ m_properties |= BLE_ATT_F_READ_AUTHEN;
+ }
+ if (properties & BLE_GATT_CHR_F_READ_AUTHOR) {
+ m_properties |= BLE_ATT_F_READ_AUTHOR;
+ }
+ if (properties & BLE_GATT_CHR_F_WRITE_ENC) {
+ m_properties |= BLE_ATT_F_WRITE_ENC;
+ }
+ if (properties & BLE_GATT_CHR_F_WRITE_AUTHEN) {
+ m_properties |= BLE_ATT_F_WRITE_AUTHEN;
+ }
+ if (properties & BLE_GATT_CHR_F_WRITE_AUTHOR) {
+ m_properties |= BLE_ATT_F_WRITE_AUTHOR;
+ }
+
+} // NimBLEDescriptor
+
+
+/**
+ * @brief NimBLEDescriptor destructor.
+ */
+NimBLEDescriptor::~NimBLEDescriptor() {
+ free(m_value.attr_value); // Release the storage we created in the constructor.
+} // ~NimBLEDescriptor
+
+/**
+ * @brief Get the BLE handle for this descriptor.
+ * @return The handle for this descriptor.
+ */
+uint16_t NimBLEDescriptor::getHandle() {
+ return m_handle;
+} // getHandle
+
+
+/**
+ * @brief Get the length of the value of this descriptor.
+ * @return The length (in bytes) of the value of this descriptor.
+ */
+size_t NimBLEDescriptor::getLength() {
+ return m_value.attr_len;
+} // getLength
+
+
+/**
+ * @brief Get the UUID of the descriptor.
+ */
+NimBLEUUID NimBLEDescriptor::getUUID() {
+ return m_uuid;
+} // getUUID
+
+
+/**
+ * @brief Get the value of this descriptor.
+ * @return A pointer to the value of this descriptor.
+ */
+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);
+}
+
+
+/**
+ * @brief Get the characteristic this descriptor belongs to.
+ * @return A pointer to the characteristic this descriptor belongs to.
+ */
+NimBLECharacteristic* NimBLEDescriptor::getCharacteristic() {
+ return m_pCharacteristic;
+} // getCharacteristic
+
+
+int NimBLEDescriptor::handleGapEvent(uint16_t conn_handle, uint16_t attr_handle,
+ struct ble_gatt_access_ctxt *ctxt, void *arg) {
+ (void)conn_handle;
+ (void)attr_handle;
+
+ const ble_uuid_t *uuid;
+ int rc;
+ NimBLEDescriptor* pDescriptor = (NimBLEDescriptor*)arg;
+
+ NIMBLE_LOGD(LOG_TAG, "Descriptor %s %s event", pDescriptor->getUUID().toString().c_str(),
+ ctxt->op == BLE_GATT_ACCESS_OP_READ_DSC ? "Read" : "Write");
+
+ uuid = ctxt->chr->uuid;
+ if(ble_uuid_cmp(uuid, &pDescriptor->getUUID().getNative()->u) == 0){
+ switch(ctxt->op) {
+ case BLE_GATT_ACCESS_OP_READ_DSC: {
+ // If the packet header is only 8 bytes this is a follow up of a long read
+ // so we don't want to call the onRead() callback again.
+ if(ctxt->om->om_pkthdr_len > 8) {
+ pDescriptor->m_pCallbacks->onRead(pDescriptor);
+ }
+
+ ble_npl_hw_enter_critical();
+ rc = os_mbuf_append(ctxt->om, pDescriptor->getValue(), pDescriptor->getLength());
+ ble_npl_hw_exit_critical(0);
+ return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
+ }
+
+ case BLE_GATT_ACCESS_OP_WRITE_DSC: {
+ if (ctxt->om->om_len > pDescriptor->m_value.attr_max_len) {
+ return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
+ }
+
+ uint8_t buf[pDescriptor->m_value.attr_max_len];
+ size_t len = ctxt->om->om_len;
+ memcpy(buf, ctxt->om->om_data,len);
+ os_mbuf *next;
+ next = SLIST_NEXT(ctxt->om, om_next);
+ while(next != NULL){
+ if((len + next->om_len) > pDescriptor->m_value.attr_max_len) {
+ return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
+ }
+ memcpy(&buf[len], next->om_data, next->om_len);
+ len += next->om_len;
+ next = SLIST_NEXT(next, om_next);
+ }
+
+ pDescriptor->setValue(buf, len);
+ pDescriptor->m_pCallbacks->onWrite(pDescriptor);
+ return 0;
+ }
+ default:
+ break;
+ }
+ }
+
+ return BLE_ATT_ERR_UNLIKELY;
+}
+
+/**
+ * @brief Set the callback handlers for this descriptor.
+ * @param [in] pCallbacks An instance of a callback structure used to define any callbacks for the descriptor.
+ */
+void NimBLEDescriptor::setCallbacks(NimBLEDescriptorCallbacks* pCallbacks) {
+ if (pCallbacks != nullptr){
+ m_pCallbacks = pCallbacks;
+ } else {
+ m_pCallbacks = &defaultCallbacks;
+ }
+} // setCallbacks
+
+
+/**
+ * @brief Set the handle of this descriptor.
+ * Set the handle of this descriptor to be the supplied value.
+ * @param [in] handle The handle to be associated with this descriptor.
+ * @return N/A.
+ */
+void NimBLEDescriptor::setHandle(uint16_t handle) {
+ NIMBLE_LOGD(LOG_TAG, ">> setHandle(0x%.2x): Setting descriptor handle to be 0x%.2x", handle, handle);
+ m_handle = handle;
+ NIMBLE_LOGD(LOG_TAG, "<< setHandle()");
+} // setHandle
+
+
+/**
+ * @brief Set the value of the descriptor.
+ * @param [in] data The data to set for the descriptor.
+ * @param [in] length The length of the data in bytes.
+ */
+void NimBLEDescriptor::setValue(const uint8_t* data, size_t length) {
+ if (length > m_value.attr_max_len) {
+ NIMBLE_LOGE(LOG_TAG, "Size %d too large, must be no bigger than %d", length, m_value.attr_max_len);
+ return;
+ }
+
+ ble_npl_hw_enter_critical();
+ m_value.attr_len = length;
+ memcpy(m_value.attr_value, data, length);
+ ble_npl_hw_exit_critical(0);
+
+} // setValue
+
+
+/**
+ * @brief Set the value of the descriptor.
+ * @param [in] value The value of the descriptor in string form.
+ */
+void NimBLEDescriptor::setValue(const std::string &value) {
+ setValue((uint8_t*) value.data(), value.length());
+} // setValue
+
+/**
+ * @brief Set the characteristic this descriptor belongs to.
+ * @param [in] pChar A pointer to the characteristic this descriptior belongs to.
+ */
+void NimBLEDescriptor::setCharacteristic(NimBLECharacteristic* pChar) {
+ m_pCharacteristic = pChar;
+} // setCharacteristic
+
+
+/**
+ * @brief Return a string representation of the descriptor.
+ * @return A string representation of the descriptor.
+ */
+std::string NimBLEDescriptor::toString() {
+ char hex[5];
+ snprintf(hex, sizeof(hex), "%04x", m_handle);
+ std::string res = "UUID: " + m_uuid.toString() + ", handle: 0x" + hex;
+ return res;
+} // toString
+
+
+NimBLEDescriptorCallbacks::~NimBLEDescriptorCallbacks() {}
+
+/**
+ * @brief Callback function to support a read request.
+ * @param [in] pDescriptor The descriptor that is the source of the event.
+ */
+void NimBLEDescriptorCallbacks::onRead(NimBLEDescriptor* pDescriptor) {
+ (void)pDescriptor;
+ NIMBLE_LOGD("NimBLEDescriptorCallbacks", "onRead: default");
+} // onRead
+
+
+/**
+ * @brief Callback function to support a write request.
+ * @param [in] pDescriptor The descriptor that is the source of the event.
+ */
+void NimBLEDescriptorCallbacks::onWrite(NimBLEDescriptor* pDescriptor) {
+ (void)pDescriptor;
+ NIMBLE_LOGD("NimBLEDescriptorCallbacks", "onWrite: default");
+} // onWrite
+
+#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/NimBLEDescriptor.h b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEDescriptor.h
new file mode 100644
index 0000000..fe6c733
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEDescriptor.h
@@ -0,0 +1,114 @@
+/*
+ * NimBLEDescriptor.h
+ *
+ * Created: on March 10, 2020
+ * Author H2zero
+ *
+ * Originally:
+ *
+ * BLEDescriptor.h
+ *
+ * Created on: Jun 22, 2017
+ * Author: kolban
+ */
+
+#ifndef MAIN_NIMBLEDESCRIPTOR_H_
+#define MAIN_NIMBLEDESCRIPTOR_H_
+
+#include "nimconfig.h"
+#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
+
+#include "NimBLECharacteristic.h"
+#include "NimBLEUUID.h"
+
+#include
+
+
+typedef struct
+{
+ uint16_t attr_max_len; /*!< attribute max value length */
+ uint16_t attr_len; /*!< attribute current value length */
+ uint8_t *attr_value; /*!< the pointer to attribute value */
+} attr_value_t;
+
+class NimBLEService;
+class NimBLECharacteristic;
+class NimBLEDescriptorCallbacks;
+
+
+/**
+ * @brief A model of a %BLE descriptor.
+ */
+class NimBLEDescriptor {
+public:
+ NimBLEDescriptor(const char* uuid, uint16_t properties,
+ uint16_t max_len,
+ NimBLECharacteristic* pCharacteristic = nullptr);
+
+ NimBLEDescriptor(NimBLEUUID uuid, uint16_t properties,
+ uint16_t max_len,
+ NimBLECharacteristic* pCharacteristic = nullptr);
+
+ ~NimBLEDescriptor();
+
+ uint16_t getHandle();
+ NimBLEUUID getUUID();
+ 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);
+ NimBLECharacteristic* getCharacteristic();
+
+ /**
+ * @brief Convenience template to set the descriptor value to val.
+ * @param [in] s The value to set.
+ */
+ template
+ void setValue(const T &s) {
+ setValue((uint8_t*)&s, sizeof(T));
+ }
+
+private:
+ friend class NimBLECharacteristic;
+ friend class NimBLEService;
+ friend class NimBLE2904;
+
+ static int handleGapEvent(uint16_t conn_handle, uint16_t attr_handle,
+ struct ble_gatt_access_ctxt *ctxt, void *arg);
+ void setHandle(uint16_t handle);
+ void setCharacteristic(NimBLECharacteristic* pChar);
+
+ NimBLEUUID m_uuid;
+ uint16_t m_handle;
+ NimBLEDescriptorCallbacks* m_pCallbacks;
+ NimBLECharacteristic* m_pCharacteristic;
+ uint8_t m_properties;
+ attr_value_t m_value;
+ uint8_t m_removed;
+}; // NimBLEDescriptor
+
+
+/**
+ * @brief Callbacks that can be associated with a %BLE descriptors to inform of events.
+ *
+ * When a server application creates a %BLE descriptor, we may wish to be informed when there is either
+ * a read or write request to the descriptors value. An application can register a
+ * sub-classed instance of this class and will be notified when such an event happens.
+ */
+class NimBLEDescriptorCallbacks {
+public:
+ virtual ~NimBLEDescriptorCallbacks();
+ virtual void onRead(NimBLEDescriptor* pDescriptor);
+ virtual void onWrite(NimBLEDescriptor* pDescriptor);
+};
+
+#include "NimBLE2904.h"
+
+#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
+#endif /* MAIN_NIMBLEDESCRIPTOR_H_ */
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/NimBLEDevice.cpp b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEDevice.cpp
new file mode 100644
index 0000000..8c205af
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEDevice.cpp
@@ -0,0 +1,1159 @@
+/*
+ * NimBLEDevice.cpp
+ *
+ * Created: on Jan 24 2020
+ * Author H2zero
+ *
+ * Originally:
+ *
+ * BLEDevice.cpp
+ *
+ * Created on: Mar 16, 2017
+ * Author: kolban
+ */
+
+#include "nimconfig.h"
+#if defined(CONFIG_BT_ENABLED)
+
+#include "NimBLEDevice.h"
+#include "NimBLEUtils.h"
+
+#ifdef ESP_PLATFORM
+# include "esp_err.h"
+# include "esp_bt.h"
+# include "nvs_flash.h"
+# if defined(CONFIG_NIMBLE_CPP_IDF)
+# include "esp_nimble_hci.h"
+# include "nimble/nimble_port.h"
+# include "nimble/nimble_port_freertos.h"
+# include "host/ble_hs.h"
+# include "host/ble_hs_pvcy.h"
+# include "host/util/util.h"
+# include "services/gap/ble_svc_gap.h"
+# include "services/gatt/ble_svc_gatt.h"
+# else
+# include "nimble/esp_port/esp-hci/include/esp_nimble_hci.h"
+# endif
+#else
+# include "nimble/nimble/controller/include/controller/ble_phy.h"
+#endif
+
+#ifndef CONFIG_NIMBLE_CPP_IDF
+# include "nimble/porting/nimble/include/nimble/nimble_port.h"
+# include "nimble/porting/npl/freertos/include/nimble/nimble_port_freertos.h"
+# include "nimble/nimble/host/include/host/ble_hs.h"
+# include "nimble/nimble/host/include/host/ble_hs_pvcy.h"
+# include "nimble/nimble/host/util/include/host/util/util.h"
+# include "nimble/nimble/host/services/gap/include/services/gap/ble_svc_gap.h"
+# include "nimble/nimble/host/services/gatt/include/services/gatt/ble_svc_gatt.h"
+#endif
+
+#if defined(ESP_PLATFORM) && defined(CONFIG_ENABLE_ARDUINO_DEPENDS)
+# include "esp32-hal-bt.h"
+#endif
+
+#include "NimBLELog.h"
+
+static const char* LOG_TAG = "NimBLEDevice";
+
+/**
+ * Singletons for the NimBLEDevice.
+ */
+static bool initialized = false;
+#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
+NimBLEScan* NimBLEDevice::m_pScan = nullptr;
+#endif
+#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
+NimBLEServer* NimBLEDevice::m_pServer = nullptr;
+#endif
+uint32_t NimBLEDevice::m_passkey = 123456;
+bool NimBLEDevice::m_synced = false;
+#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
+NimBLEAdvertising* NimBLEDevice::m_bleAdvertising = nullptr;
+#endif
+
+gap_event_handler NimBLEDevice::m_customGapHandler = nullptr;
+ble_gap_event_listener NimBLEDevice::m_listener;
+#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
+std::list NimBLEDevice::m_cList;
+#endif
+std::list NimBLEDevice::m_ignoreList;
+std::vector NimBLEDevice::m_whiteList;
+NimBLESecurityCallbacks* NimBLEDevice::m_securityCallbacks = nullptr;
+uint8_t NimBLEDevice::m_own_addr_type = BLE_OWN_ADDR_PUBLIC;
+#ifdef ESP_PLATFORM
+uint16_t NimBLEDevice::m_scanDuplicateSize = CONFIG_BTDM_SCAN_DUPL_CACHE_SIZE;
+uint8_t NimBLEDevice::m_scanFilterMode = CONFIG_BTDM_SCAN_DUPL_TYPE;
+#endif
+
+/**
+ * @brief Create a new instance of a server.
+ * @return A new instance of the server.
+ */
+#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
+/* STATIC */ NimBLEServer* NimBLEDevice::createServer() {
+ if(NimBLEDevice::m_pServer == nullptr) {
+ NimBLEDevice::m_pServer = new NimBLEServer();
+ ble_gatts_reset();
+ ble_svc_gap_init();
+ ble_svc_gatt_init();
+ }
+
+ return m_pServer;
+} // createServer
+
+
+/**
+ * @brief Get the instance of the server.
+ * @return A pointer to the server instance.
+ */
+/* STATIC */ NimBLEServer* NimBLEDevice::getServer() {
+ return m_pServer;
+} // getServer
+#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
+
+
+#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
+/**
+ * @brief Get the instance of the advertising object.
+ * @return A pointer to the advertising object.
+ */
+NimBLEAdvertising* NimBLEDevice::getAdvertising() {
+ if(m_bleAdvertising == nullptr) {
+ m_bleAdvertising = new NimBLEAdvertising();
+ }
+ return m_bleAdvertising;
+}
+
+
+/**
+ * @brief Convenience function to begin advertising.
+ */
+void NimBLEDevice::startAdvertising() {
+ getAdvertising()->start();
+} // startAdvertising
+
+
+/**
+ * @brief Convenience function to stop advertising.
+ */
+void NimBLEDevice::stopAdvertising() {
+ getAdvertising()->stop();
+} // stopAdvertising
+#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
+
+
+/**
+ * @brief Retrieve the Scan object that we use for scanning.
+ * @return The scanning object reference. This is a singleton object. The caller should not
+ * try and release/delete it.
+ */
+#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
+/* STATIC */
+NimBLEScan* NimBLEDevice::getScan() {
+ if (m_pScan == nullptr) {
+ m_pScan = new NimBLEScan();
+ }
+ return m_pScan;
+} // getScan
+#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
+
+
+/**
+ * @brief Creates a new client object and maintains a list of all client objects
+ * each client can connect to 1 peripheral device.
+ * @param [in] peerAddress An optional peer address that is copied to the new client
+ * object, allows for calling NimBLEClient::connect(bool) without a device or address parameter.
+ * @return A reference to the new client object.
+ */
+#if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
+/* STATIC */
+NimBLEClient* NimBLEDevice::createClient(NimBLEAddress peerAddress) {
+ if(m_cList.size() >= NIMBLE_MAX_CONNECTIONS) {
+ NIMBLE_LOGW(LOG_TAG,"Number of clients exceeds Max connections. Cur=%d Max=%d",
+ m_cList.size(), NIMBLE_MAX_CONNECTIONS);
+ }
+
+ NimBLEClient* pClient = new NimBLEClient(peerAddress);
+ m_cList.push_back(pClient);
+
+ return pClient;
+} // createClient
+
+
+/**
+ * @brief Delete the client object and remove it from the list.\n
+ * Checks if it is connected or trying to connect and disconnects/stops it first.
+ * @param [in] pClient A pointer to the client object.
+ */
+/* STATIC */
+bool NimBLEDevice::deleteClient(NimBLEClient* pClient) {
+ if(pClient == nullptr) {
+ return false;
+ }
+
+ // Set the connection established flag to false to stop notifications
+ // from accessing the attribute vectors while they are being deleted.
+ pClient->m_connEstablished = false;
+ int rc =0;
+
+ if(pClient->isConnected()) {
+ rc = pClient->disconnect();
+ if (rc != 0 && rc != BLE_HS_EALREADY && rc != BLE_HS_ENOTCONN) {
+ return false;
+ }
+
+ while(pClient->isConnected()) {
+ taskYIELD();
+ }
+ // Since we set the flag to false the app will not get a callback
+ // in the disconnect event so we call it here for good measure.
+ pClient->m_pClientCallbacks->onDisconnect(pClient);
+
+ } else if(pClient->m_pTaskData != nullptr) {
+ rc = ble_gap_conn_cancel();
+ if (rc != 0 && rc != BLE_HS_EALREADY) {
+ return false;
+ }
+ while(pClient->m_pTaskData != nullptr) {
+ taskYIELD();
+ }
+ }
+
+ m_cList.remove(pClient);
+ delete pClient;
+
+ return true;
+} // deleteClient
+
+
+/**
+ * @brief Get the list of created client objects.
+ * @return A pointer to the list of clients.
+ */
+/* STATIC */
+std::list* NimBLEDevice::getClientList() {
+ return &m_cList;
+} // getClientList
+
+
+/**
+ * @brief Get the number of created client objects.
+ * @return Number of client objects created.
+ */
+/* STATIC */
+size_t NimBLEDevice::getClientListSize() {
+ return m_cList.size();
+} // getClientList
+
+
+/**
+ * @brief Get a reference to a client by connection ID.
+ * @param [in] conn_id The client connection ID to search for.
+ * @return A pointer to the client object with the spcified connection ID.
+ */
+/* STATIC */
+NimBLEClient* NimBLEDevice::getClientByID(uint16_t conn_id) {
+ for(auto it = m_cList.cbegin(); it != m_cList.cend(); ++it) {
+ if((*it)->getConnId() == conn_id) {
+ return (*it);
+ }
+ }
+ assert(0);
+ return nullptr;
+} // getClientByID
+
+
+/**
+ * @brief Get a reference to a client by peer address.
+ * @param [in] peer_addr The address of the peer to search for.
+ * @return A pointer to the client object with the peer address.
+ */
+/* STATIC */
+NimBLEClient* NimBLEDevice::getClientByPeerAddress(const NimBLEAddress &peer_addr) {
+ for(auto it = m_cList.cbegin(); it != m_cList.cend(); ++it) {
+ if((*it)->getPeerAddress().equals(peer_addr)) {
+ return (*it);
+ }
+ }
+ return nullptr;
+} // getClientPeerAddress
+
+
+/**
+ * @brief Finds the first disconnected client in the list.
+ * @return A pointer to the first client object that is not connected to a peer.
+ */
+/* STATIC */
+NimBLEClient* NimBLEDevice::getDisconnectedClient() {
+ for(auto it = m_cList.cbegin(); it != m_cList.cend(); ++it) {
+ if(!(*it)->isConnected()) {
+ return (*it);
+ }
+ }
+ return nullptr;
+} // getDisconnectedClient
+
+#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
+
+#ifdef ESP_PLATFORM
+/**
+ * @brief Set the transmission power.
+ * @param [in] powerLevel The power level to set, can be one of:
+ * * ESP_PWR_LVL_N12 = 0, Corresponding to -12dbm
+ * * ESP_PWR_LVL_N9 = 1, Corresponding to -9dbm
+ * * ESP_PWR_LVL_N6 = 2, Corresponding to -6dbm
+ * * ESP_PWR_LVL_N3 = 3, Corresponding to -3dbm
+ * * ESP_PWR_LVL_N0 = 4, Corresponding to 0dbm
+ * * ESP_PWR_LVL_P3 = 5, Corresponding to +3dbm
+ * * ESP_PWR_LVL_P6 = 6, Corresponding to +6dbm
+ * * ESP_PWR_LVL_P9 = 7, Corresponding to +9dbm
+ * @param [in] powerType The BLE function to set the power level for, 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
+ * * ESP_BLE_PWR_TYPE_CONN_HDL2 = 2, For connection handle 2
+ * * ESP_BLE_PWR_TYPE_CONN_HDL3 = 3, For connection handle 3
+ * * ESP_BLE_PWR_TYPE_CONN_HDL4 = 4, For connection handle 4
+ * * ESP_BLE_PWR_TYPE_CONN_HDL5 = 5, For connection handle 5
+ * * ESP_BLE_PWR_TYPE_CONN_HDL6 = 6, For connection handle 6
+ * * ESP_BLE_PWR_TYPE_CONN_HDL7 = 7, For connection handle 7
+ * * ESP_BLE_PWR_TYPE_CONN_HDL8 = 8, For connection handle 8
+ * * ESP_BLE_PWR_TYPE_ADV = 9, For advertising
+ * * ESP_BLE_PWR_TYPE_SCAN = 10, For scan
+ * * ESP_BLE_PWR_TYPE_DEFAULT = 11, For default, if not set other, it will use default value
+ */
+/* STATIC */
+void NimBLEDevice::setPower(esp_power_level_t powerLevel, esp_ble_power_type_t powerType) {
+ NIMBLE_LOGD(LOG_TAG, ">> setPower: %d (type: %d)", powerLevel, powerType);
+
+ esp_err_t errRc = esp_ble_tx_power_set(powerType, powerLevel);
+ if (errRc != ESP_OK) {
+ NIMBLE_LOGE(LOG_TAG, "esp_ble_tx_power_set: rc=%d", errRc);
+ }
+
+ NIMBLE_LOGD(LOG_TAG, "<< setPower");
+} // setPower
+
+
+/**
+ * @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
+ * * ESP_BLE_PWR_TYPE_CONN_HDL2 = 2, For connection handle 2
+ * * ESP_BLE_PWR_TYPE_CONN_HDL3 = 3, For connection handle 3
+ * * ESP_BLE_PWR_TYPE_CONN_HDL4 = 4, For connection handle 4
+ * * ESP_BLE_PWR_TYPE_CONN_HDL5 = 5, For connection handle 5
+ * * ESP_BLE_PWR_TYPE_CONN_HDL6 = 6, For connection handle 6
+ * * ESP_BLE_PWR_TYPE_CONN_HDL7 = 7, For connection handle 7
+ * * ESP_BLE_PWR_TYPE_CONN_HDL8 = 8, For connection handle 8
+ * * ESP_BLE_PWR_TYPE_ADV = 9, For advertising
+ * * ESP_BLE_PWR_TYPE_SCAN = 10, For scan
+ * * ESP_BLE_PWR_TYPE_DEFAULT = 11, For default, if not set other, it will use default value
+ * @return the power level currently used by the type specified.
+ */
+/* STATIC */
+int NimBLEDevice::getPower(esp_ble_power_type_t powerType) {
+ switch(esp_ble_tx_power_get(powerType)) {
+ case ESP_PWR_LVL_N12:
+ return -12;
+ case ESP_PWR_LVL_N9:
+ return -9;
+ case ESP_PWR_LVL_N6:
+ return -6;
+ case ESP_PWR_LVL_N3:
+ return -6;
+ case ESP_PWR_LVL_N0:
+ return 0;
+ case ESP_PWR_LVL_P3:
+ return 3;
+ case ESP_PWR_LVL_P6:
+ return 6;
+ case ESP_PWR_LVL_P9:
+ return 9;
+ default:
+ return BLE_HS_ADV_TX_PWR_LVL_AUTO;
+ }
+} // getPower
+
+#else
+
+void NimBLEDevice::setPower(int dbm) {
+ ble_phy_txpwr_set(dbm);
+}
+
+
+int NimBLEDevice::getPower() {
+ return ble_phy_txpwr_get();
+}
+#endif
+
+/**
+ * @brief Get our device address.
+ * @return A NimBLEAddress object of our public address if we have one,
+ * if not then our current random address.
+ */
+/* STATIC*/
+NimBLEAddress NimBLEDevice::getAddress() {
+ ble_addr_t addr = {BLE_ADDR_PUBLIC, 0};
+
+ if(BLE_HS_ENOADDR == ble_hs_id_copy_addr(BLE_ADDR_PUBLIC, addr.val, NULL)) {
+ NIMBLE_LOGD(LOG_TAG, "Public address not found, checking random");
+ addr.type = BLE_ADDR_RANDOM;
+ ble_hs_id_copy_addr(BLE_ADDR_RANDOM, addr.val, NULL);
+ }
+
+ return NimBLEAddress(addr);
+} // getAddress
+
+
+/**
+ * @brief Return a string representation of the address of this device.
+ * @return A string representation of this device address.
+ */
+/* STATIC */
+std::string NimBLEDevice::toString() {
+ return getAddress().toString();
+} // toString
+
+
+/**
+ * @brief Setup local mtu that will be used to negotiate mtu during request from client peer.
+ * @param [in] mtu Value to set local mtu:
+ * * This should be larger than 23 and lower or equal to BLE_ATT_MTU_MAX = 527.
+ */
+/* STATIC */
+int NimBLEDevice::setMTU(uint16_t mtu) {
+ NIMBLE_LOGD(LOG_TAG, ">> setLocalMTU: %d", mtu);
+
+ int rc = ble_att_set_preferred_mtu(mtu);
+
+ if (rc != 0) {
+ NIMBLE_LOGE(LOG_TAG, "Could not set local mtu value to: %d", mtu);
+ }
+
+ NIMBLE_LOGD(LOG_TAG, "<< setLocalMTU");
+ return rc;
+} // setMTU
+
+
+/**
+ * @brief Get local MTU value set.
+ * @return The current preferred MTU setting.
+ */
+/* STATIC */
+uint16_t NimBLEDevice::getMTU() {
+ return ble_att_preferred_mtu();
+}
+
+
+#ifdef ESP_PLATFORM
+/**
+ * @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;
+}
+#endif
+
+#if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL) || defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
+/**
+ * @brief Gets the number of bonded peers stored
+ */
+/*STATIC*/
+int NimBLEDevice::getNumBonds() {
+ ble_addr_t peer_id_addrs[MYNEWT_VAL(BLE_STORE_MAX_BONDS)];
+ int num_peers, rc;
+
+ rc = ble_store_util_bonded_peers(&peer_id_addrs[0], &num_peers, MYNEWT_VAL(BLE_STORE_MAX_BONDS));
+ if (rc !=0) {
+ return 0;
+ }
+
+ return num_peers;
+}
+
+
+/**
+ * @brief Deletes all bonding information.
+ */
+/*STATIC*/
+void NimBLEDevice::deleteAllBonds() {
+ ble_store_clear();
+}
+
+
+/**
+ * @brief Deletes a peer bond.
+ * @param [in] address The address of the peer with which to delete bond info.
+ * @returns true on success.
+ */
+/*STATIC*/
+bool NimBLEDevice::deleteBond(const NimBLEAddress &address) {
+ ble_addr_t delAddr;
+ memcpy(&delAddr.val, address.getNative(),6);
+ delAddr.type = address.getType();
+
+ int rc = ble_gap_unpair(&delAddr);
+ if (rc != 0) {
+ return false;
+ }
+
+ return true;
+}
+
+
+/**
+ * @brief Checks if a peer device is bonded.
+ * @param [in] address The address to check for bonding.
+ * @returns true if bonded.
+ */
+/*STATIC*/
+bool NimBLEDevice::isBonded(const NimBLEAddress &address) {
+ ble_addr_t peer_id_addrs[MYNEWT_VAL(BLE_STORE_MAX_BONDS)];
+ int num_peers, rc;
+
+ rc = ble_store_util_bonded_peers(&peer_id_addrs[0], &num_peers, MYNEWT_VAL(BLE_STORE_MAX_BONDS));
+ if (rc != 0) {
+ return false;
+ }
+
+ for (int i = 0; i < num_peers; i++) {
+ NimBLEAddress storedAddr(peer_id_addrs[i]);
+ if(storedAddr == address) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+/**
+ * @brief Get the address of a bonded peer device by index.
+ * @param [in] index The index to retrieve the peer address of.
+ * @returns NimBLEAddress of the found bonded peer or nullptr if not found.
+ */
+/*STATIC*/
+NimBLEAddress NimBLEDevice::getBondedAddress(int index) {
+ ble_addr_t peer_id_addrs[MYNEWT_VAL(BLE_STORE_MAX_BONDS)];
+ int num_peers, rc;
+
+ rc = ble_store_util_bonded_peers(&peer_id_addrs[0], &num_peers, MYNEWT_VAL(BLE_STORE_MAX_BONDS));
+ if (rc != 0) {
+ return nullptr;
+ }
+
+ if (index > num_peers || index < 0) {
+ return nullptr;
+ }
+
+ return NimBLEAddress(peer_id_addrs[index]);
+}
+#endif
+
+/**
+ * @brief Checks if a peer device is whitelisted.
+ * @param [in] address The address to check for in the whitelist.
+ * @returns true if the address is in the whitelist.
+ */
+/*STATIC*/
+bool NimBLEDevice::onWhiteList(const NimBLEAddress & address) {
+ for (auto &it : m_whiteList) {
+ if (it == address) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+/**
+ * @brief Add a peer address to the whitelist.
+ * @param [in] address The address to add to the whitelist.
+ * @returns true if successful.
+ */
+/*STATIC*/
+bool NimBLEDevice::whiteListAdd(const NimBLEAddress & address) {
+ if (NimBLEDevice::onWhiteList(address)) {
+ return true;
+ }
+
+ m_whiteList.push_back(address);
+ std::vector wlVec;
+ wlVec.reserve(m_whiteList.size());
+
+ for (auto &it : m_whiteList) {
+ ble_addr_t wlAddr;
+ memcpy(&wlAddr.val, it.getNative(), 6);
+ wlAddr.type = it.getType();
+ wlVec.push_back(wlAddr);
+ }
+
+ int rc = ble_gap_wl_set(&wlVec[0], wlVec.size());
+ if (rc != 0) {
+ NIMBLE_LOGE(LOG_TAG, "Failed adding to whitelist rc=%d", rc);
+ return false;
+ }
+
+ return true;
+}
+
+
+/**
+ * @brief Remove a peer address from the whitelist.
+ * @param [in] address The address to remove from the whitelist.
+ * @returns true if successful.
+ */
+/*STATIC*/
+bool NimBLEDevice::whiteListRemove(const NimBLEAddress & address) {
+ if (!NimBLEDevice::onWhiteList(address)) {
+ return true;
+ }
+
+ std::vector wlVec;
+ wlVec.reserve(m_whiteList.size());
+
+ for (auto &it : m_whiteList) {
+ if (it != address) {
+ ble_addr_t wlAddr;
+ memcpy(&wlAddr.val, it.getNative(), 6);
+ wlAddr.type = it.getType();
+ wlVec.push_back(wlAddr);
+ }
+ }
+
+ int rc = ble_gap_wl_set(&wlVec[0], wlVec.size());
+ if (rc != 0) {
+ NIMBLE_LOGE(LOG_TAG, "Failed removing from whitelist rc=%d", rc);
+ return false;
+ }
+
+ // Don't remove from the list unless NimBLE returned success
+ for (auto it = m_whiteList.begin(); it < m_whiteList.end(); ++it) {
+ if ((*it) == address) {
+ m_whiteList.erase(it);
+ break;
+ }
+ }
+
+ return true;
+}
+
+
+/**
+ * @brief Gets the count of addresses in the whitelist.
+ * @returns The number of addresses in the whitelist.
+ */
+/*STATIC*/
+size_t NimBLEDevice::getWhiteListCount() {
+ return m_whiteList.size();
+}
+
+
+/**
+ * @brief Gets the address at the vector index.
+ * @param [in] index The vector index to retrieve the address from.
+ * @returns the NimBLEAddress at the whitelist index or nullptr if not found.
+ */
+/*STATIC*/
+NimBLEAddress NimBLEDevice::getWhiteListAddress(size_t index) {
+ if (index > m_whiteList.size()) {
+ NIMBLE_LOGE(LOG_TAG, "Invalid index; %u", index);
+ return nullptr;
+ }
+ return m_whiteList[index];
+}
+
+
+/**
+ * @brief Host reset, we pass the message so we don't make calls until resynced.
+ * @param [in] reason The reason code for the reset.
+ */
+/* STATIC */
+void NimBLEDevice::onReset(int reason)
+{
+ if(!m_synced) {
+ return;
+ }
+
+ m_synced = false;
+
+ NIMBLE_LOGC(LOG_TAG, "Resetting state; reason=%d, %s", reason,
+ NimBLEUtils::returnCodeToString(reason));
+
+#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
+ if(initialized) {
+ if(m_pScan != nullptr) {
+ m_pScan->onHostReset();
+ }
+ }
+#endif
+} // onReset
+
+
+/**
+ * @brief Host resynced with controller, all clear to make calls to the stack.
+ */
+/* STATIC */
+void NimBLEDevice::onSync(void)
+{
+ NIMBLE_LOGI(LOG_TAG, "NimBle host synced.");
+ // This check is needed due to potentially being called multiple times in succession
+ // If this happens, the call to scan start may get stuck or cause an advertising fault.
+ if(m_synced) {
+ return;
+ }
+
+ /* Make sure we have proper identity address set (public preferred) */
+ int rc = ble_hs_util_ensure_addr(0);
+ assert(rc == 0);
+
+#ifndef ESP_PLATFORM
+ rc = ble_hs_id_infer_auto(m_own_addr_type, &m_own_addr_type);
+ if (rc != 0) {
+ NIMBLE_LOGE(LOG_TAG, "error determining address type; rc=%d", rc);
+ return;
+ }
+#endif
+
+ // Yield for houskeeping before returning to operations.
+ // Occasionally triggers exception without.
+ taskYIELD();
+
+ m_synced = true;
+
+ if(initialized) {
+#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
+ if(m_pScan != nullptr) {
+ m_pScan->onHostSync();
+ }
+#endif
+
+#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
+ if(m_bleAdvertising != nullptr) {
+ m_bleAdvertising->onHostSync();
+ }
+#endif
+ }
+} // onSync
+
+
+/**
+ * @brief The main host task.
+ */
+/* STATIC */
+void NimBLEDevice::host_task(void *param)
+{
+ NIMBLE_LOGI(LOG_TAG, "BLE Host Task Started");
+
+ /* This function will return only when nimble_port_stop() is executed */
+ nimble_port_run();
+
+ nimble_port_freertos_deinit();
+} // host_task
+
+
+/**
+ * @brief Initialize the %BLE environment.
+ * @param [in] deviceName The device name of the device.
+ */
+/* STATIC */
+void NimBLEDevice::init(const std::string &deviceName) {
+ if(!initialized){
+ int rc=0;
+#ifdef ESP_PLATFORM
+ esp_err_t errRc = ESP_OK;
+
+#ifdef CONFIG_ENABLE_ARDUINO_DEPENDS
+ // make sure the linker includes esp32-hal-bt.c so ardruino init doesn't release BLE memory.
+ btStarted();
+#endif
+
+ errRc = nvs_flash_init();
+
+ if (errRc == ESP_ERR_NVS_NO_FREE_PAGES || errRc == ESP_ERR_NVS_NEW_VERSION_FOUND) {
+ ESP_ERROR_CHECK(nvs_flash_erase());
+ errRc = nvs_flash_init();
+ }
+
+ ESP_ERROR_CHECK(errRc);
+
+ esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT);
+
+ esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
+#if defined (CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S3)
+ bt_cfg.bluetooth_mode = ESP_BT_MODE_BLE;
+#else
+ bt_cfg.mode = ESP_BT_MODE_BLE;
+ bt_cfg.ble_max_conn = CONFIG_BT_NIMBLE_MAX_CONNECTIONS;
+#endif
+ 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());
+#endif
+ nimble_port_init();
+
+ // Setup callbacks for host events
+ ble_hs_cfg.reset_cb = NimBLEDevice::onReset;
+ ble_hs_cfg.sync_cb = NimBLEDevice::onSync;
+
+ // Set initial security capabilities
+ ble_hs_cfg.sm_io_cap = BLE_HS_IO_NO_INPUT_OUTPUT;
+ ble_hs_cfg.sm_bonding = 0;
+ ble_hs_cfg.sm_mitm = 0;
+ ble_hs_cfg.sm_sc = 1;
+ ble_hs_cfg.sm_our_key_dist = 1;
+ ble_hs_cfg.sm_their_key_dist = 3;
+
+ ble_hs_cfg.store_status_cb = ble_store_util_status_rr; /*TODO: Implement handler for this*/
+
+ // Set the device name.
+ rc = ble_svc_gap_device_name_set(deviceName.c_str());
+ assert(rc == 0);
+
+ ble_store_config_init();
+
+ nimble_port_freertos_init(NimBLEDevice::host_task);
+ }
+
+ // Wait for host and controller to sync before returning and accepting new tasks
+ while(!m_synced){
+ taskYIELD();
+ }
+
+ initialized = true; // Set the initialization flag to ensure we are only initialized once.
+} // init
+
+
+/**
+ * @brief Shutdown the NimBLE stack/controller.
+ * @param [in] clearAll If true, deletes all server/advertising/scan/client objects after deinitializing.
+ * @note If clearAll is true when called, any references to the created objects become invalid.
+ */
+/* STATIC */
+void NimBLEDevice::deinit(bool clearAll) {
+ int ret = nimble_port_stop();
+ if (ret == 0) {
+ nimble_port_deinit();
+#ifdef ESP_PLATFORM
+ ret = esp_nimble_hci_and_controller_deinit();
+ if (ret != ESP_OK) {
+ NIMBLE_LOGE(LOG_TAG, "esp_nimble_hci_and_controller_deinit() failed with error: %d", ret);
+ }
+#endif
+ initialized = false;
+ m_synced = false;
+
+ if(clearAll) {
+#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
+ if(NimBLEDevice::m_pServer != nullptr) {
+ delete NimBLEDevice::m_pServer;
+ NimBLEDevice::m_pServer = nullptr;
+ }
+#endif
+
+#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
+ if(NimBLEDevice::m_bleAdvertising != nullptr) {
+ delete NimBLEDevice::m_bleAdvertising;
+ NimBLEDevice::m_bleAdvertising = nullptr;
+ }
+#endif
+
+#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
+ if(NimBLEDevice::m_pScan != nullptr) {
+ delete NimBLEDevice::m_pScan;
+ NimBLEDevice::m_pScan= nullptr;
+ }
+#endif
+
+#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
+ for(auto &it : m_cList) {
+ deleteClient(it);
+ m_cList.clear();
+ }
+#endif
+
+ m_ignoreList.clear();
+
+ if(m_securityCallbacks != nullptr) {
+ delete m_securityCallbacks;
+ }
+ }
+ }
+} // deinit
+
+
+/**
+ * @brief Check if the initialization is complete.
+ * @return true if initialized.
+ */
+/*STATIC*/
+bool NimBLEDevice::getInitialized() {
+ return initialized;
+} // getInitialized
+
+
+/**
+ * @brief Set the authorization mode for this device.
+ * @param bonding If true we allow bonding, false no bonding will be performed.
+ * @param mitm If true we are capable of man in the middle protection, false if not.
+ * @param sc If true we will perform secure connection pairing, false we will use legacy pairing.
+ */
+/*STATIC*/
+void NimBLEDevice::setSecurityAuth(bool bonding, bool mitm, bool sc) {
+ NIMBLE_LOGD(LOG_TAG, "Setting bonding: %d, mitm: %d, sc: %d",bonding,mitm,sc);
+ ble_hs_cfg.sm_bonding = bonding;
+ ble_hs_cfg.sm_mitm = mitm;
+ ble_hs_cfg.sm_sc = sc;
+} // setSecurityAuth
+
+
+/**
+ * @brief Set the authorization mode for this device.
+ * @param auth_req A bitmap indicating what modes are supported.\n
+ * The available bits are defined as:
+ * * 0x01 BLE_SM_PAIR_AUTHREQ_BOND
+ * * 0x04 BLE_SM_PAIR_AUTHREQ_MITM
+ * * 0x08 BLE_SM_PAIR_AUTHREQ_SC
+ * * 0x10 BLE_SM_PAIR_AUTHREQ_KEYPRESS - not yet supported.
+ */
+/*STATIC*/
+void NimBLEDevice::setSecurityAuth(uint8_t auth_req) {
+ NimBLEDevice::setSecurityAuth((auth_req & BLE_SM_PAIR_AUTHREQ_BOND)>0,
+ (auth_req & BLE_SM_PAIR_AUTHREQ_MITM)>0,
+ (auth_req & BLE_SM_PAIR_AUTHREQ_SC)>0);
+} // setSecurityAuth
+
+
+/**
+ * @brief Set the Input/Output capabilities of this device.
+ * @param iocap One of the following values:
+ * * 0x00 BLE_HS_IO_DISPLAY_ONLY DisplayOnly IO capability
+ * * 0x01 BLE_HS_IO_DISPLAY_YESNO DisplayYesNo IO capability
+ * * 0x02 BLE_HS_IO_KEYBOARD_ONLY KeyboardOnly IO capability
+ * * 0x03 BLE_HS_IO_NO_INPUT_OUTPUT NoInputNoOutput IO capability
+ * * 0x04 BLE_HS_IO_KEYBOARD_DISPLAY KeyboardDisplay Only IO capability
+ */
+/*STATIC*/
+void NimBLEDevice::setSecurityIOCap(uint8_t iocap) {
+ ble_hs_cfg.sm_io_cap = iocap;
+} // setSecurityIOCap
+
+
+/**
+ * @brief If we are the initiator of the security procedure this sets the keys we will distribute.
+ * @param init_key A bitmap indicating which keys to distribute during pairing.\n
+ * The available bits are defined as:
+ * * 0x01: BLE_SM_PAIR_KEY_DIST_ENC - Distribute the encryption key.
+ * * 0x02: BLE_SM_PAIR_KEY_DIST_ID - Distribute the ID key (IRK).
+ * * 0x04: BLE_SM_PAIR_KEY_DIST_SIGN
+ * * 0x08: BLE_SM_PAIR_KEY_DIST_LINK
+ */
+/*STATIC*/
+void NimBLEDevice::setSecurityInitKey(uint8_t init_key) {
+ ble_hs_cfg.sm_our_key_dist = init_key;
+} // setsSecurityInitKey
+
+
+/**
+ * @brief Set the keys we are willing to accept during pairing.
+ * @param resp_key A bitmap indicating which keys to accept during pairing.
+ * The available bits are defined as:
+ * * 0x01: BLE_SM_PAIR_KEY_DIST_ENC - Accept the encryption key.
+ * * 0x02: BLE_SM_PAIR_KEY_DIST_ID - Accept the ID key (IRK).
+ * * 0x04: BLE_SM_PAIR_KEY_DIST_SIGN
+ * * 0x08: BLE_SM_PAIR_KEY_DIST_LINK
+ */
+/*STATIC*/
+void NimBLEDevice::setSecurityRespKey(uint8_t resp_key) {
+ ble_hs_cfg.sm_their_key_dist = resp_key;
+} // setsSecurityRespKey
+
+
+/**
+ * @brief Set the passkey the server will ask for when pairing.
+ * @param [in] pin The passkey to use.
+ */
+/*STATIC*/
+void NimBLEDevice::setSecurityPasskey(uint32_t pin) {
+ m_passkey = pin;
+} // setSecurityPasskey
+
+
+/**
+ * @brief Get the current passkey used for pairing.
+ * @return The current passkey.
+ */
+/*STATIC*/
+uint32_t NimBLEDevice::getSecurityPasskey() {
+ return m_passkey;
+} // getSecurityPasskey
+
+
+/**
+ * @brief Set callbacks that will be used to handle encryption negotiation events and authentication events
+ * @param [in] callbacks Pointer to NimBLESecurityCallbacks class
+ * @deprecated For backward compatibility, New code should use client/server callback methods.
+ */
+/*STATIC*/
+void NimBLEDevice::setSecurityCallbacks(NimBLESecurityCallbacks* callbacks) {
+ NimBLEDevice::m_securityCallbacks = callbacks;
+} // setSecurityCallbacks
+
+
+#ifdef ESP_PLATFORM
+/**
+ * @brief Set the own address type.
+ * @param [in] own_addr_type Own Bluetooth Device address type.\n
+ * The available bits are defined as:
+ * * 0x00: BLE_OWN_ADDR_PUBLIC
+ * * 0x01: BLE_OWN_ADDR_RANDOM
+ * * 0x02: BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT
+ * * 0x03: BLE_OWN_ADDR_RPA_RANDOM_DEFAULT
+ * @param [in] useNRPA If true, and address type is random, uses a non-resolvable random address.
+ */
+/*STATIC*/
+void NimBLEDevice::setOwnAddrType(uint8_t own_addr_type, bool useNRPA) {
+ m_own_addr_type = own_addr_type;
+ switch (own_addr_type) {
+#ifdef CONFIG_IDF_TARGET_ESP32
+ case BLE_OWN_ADDR_PUBLIC:
+ ble_hs_pvcy_rpa_config(NIMBLE_HOST_DISABLE_PRIVACY);
+ break;
+#endif
+ case BLE_OWN_ADDR_RANDOM:
+ setSecurityInitKey(BLE_SM_PAIR_KEY_DIST_ENC | BLE_SM_PAIR_KEY_DIST_ID);
+#ifdef CONFIG_IDF_TARGET_ESP32
+ ble_hs_pvcy_rpa_config(useNRPA ? NIMBLE_HOST_ENABLE_NRPA : NIMBLE_HOST_ENABLE_RPA);
+#endif
+ break;
+ case BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT:
+ case BLE_OWN_ADDR_RPA_RANDOM_DEFAULT:
+ setSecurityInitKey(BLE_SM_PAIR_KEY_DIST_ENC | BLE_SM_PAIR_KEY_DIST_ID);
+#ifdef CONFIG_IDF_TARGET_ESP32
+ ble_hs_pvcy_rpa_config(NIMBLE_HOST_ENABLE_RPA);
+#endif
+ break;
+ }
+} // setOwnAddrType
+#endif
+
+/**
+ * @brief Start the connection securing and authorization for this connection.
+ * @param conn_id The connection id of the peer device.
+ * @returns NimBLE stack return code, 0 = success.
+ */
+/* STATIC */
+int NimBLEDevice::startSecurity(uint16_t conn_id) {
+ int rc = ble_gap_security_initiate(conn_id);
+ if(rc != 0){
+ NIMBLE_LOGE(LOG_TAG, "ble_gap_security_initiate: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
+ }
+
+ return rc;
+} // startSecurity
+
+
+/**
+ * @brief Check if the device address is on our ignore list.
+ * @param [in] address The address to look for.
+ * @return True if ignoring.
+ */
+/*STATIC*/
+bool NimBLEDevice::isIgnored(const NimBLEAddress &address) {
+ for(auto &it : m_ignoreList) {
+ if(it.equals(address)){
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+/**
+ * @brief Add a device to the ignore list.
+ * @param [in] address The address of the device we want to ignore.
+ */
+/*STATIC*/
+void NimBLEDevice::addIgnored(const NimBLEAddress &address) {
+ m_ignoreList.push_back(address);
+}
+
+
+/**
+ * @brief Remove a device from the ignore list.
+ * @param [in] address The address of the device we want to remove from the list.
+ */
+/*STATIC*/
+void NimBLEDevice::removeIgnored(const NimBLEAddress &address) {
+ for(auto it = m_ignoreList.begin(); it != m_ignoreList.end(); ++it) {
+ if((*it).equals(address)){
+ m_ignoreList.erase(it);
+ return;
+ }
+ }
+}
+
+
+/**
+ * @brief Set a custom callback for gap events.
+ * @param [in] handler The function to call when gap events occur.
+ */
+/*STATIC*/
+void NimBLEDevice::setCustomGapHandler(gap_event_handler handler) {
+ m_customGapHandler = handler;
+ int rc = ble_gap_event_listener_register(&m_listener, m_customGapHandler, NULL);
+ if(rc == BLE_HS_EALREADY){
+ NIMBLE_LOGI(LOG_TAG, "Already listening to GAP events.");
+ }
+ else{
+ assert(rc == 0);
+ }
+} // setCustomGapHandler
+
+#endif // CONFIG_BT_ENABLED
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/NimBLEDevice.h b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEDevice.h
new file mode 100644
index 0000000..94ad294
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEDevice.h
@@ -0,0 +1,218 @@
+/*
+ * NimBLEDevice.h
+ *
+ * Created: on Jan 24 2020
+ * Author H2zero
+ *
+ * Originally:
+ *
+ * BLEDevice.h
+ *
+ * Created on: Mar 16, 2017
+ * Author: kolban
+ */
+
+#ifndef MAIN_NIMBLEDEVICE_H_
+#define MAIN_NIMBLEDEVICE_H_
+
+#include "nimconfig.h"
+#if defined(CONFIG_BT_ENABLED)
+
+#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
+#include "NimBLEScan.h"
+#endif
+
+#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
+#include "NimBLEAdvertising.h"
+#endif
+
+#if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
+#include "NimBLEClient.h"
+#endif
+
+#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
+#include "NimBLEServer.h"
+#endif
+
+#include "NimBLEUtils.h"
+#include "NimBLESecurity.h"
+#include "NimBLEAddress.h"
+
+#ifdef ESP_PLATFORM
+# include "esp_bt.h"
+#endif
+
+#include
+#include
+#include
+
+#define BLEDevice NimBLEDevice
+#define BLEClient NimBLEClient
+#define BLERemoteService NimBLERemoteService
+#define BLERemoteCharacteristic NimBLERemoteCharacteristic
+#define BLERemoteDescriptor NimBLERemoteDescriptor
+#define BLEAdvertisedDevice NimBLEAdvertisedDevice
+#define BLEScan NimBLEScan
+#define BLEUUID NimBLEUUID
+#define BLESecurity NimBLESecurity
+#define BLESecurityCallbacks NimBLESecurityCallbacks
+#define BLEAddress NimBLEAddress
+#define BLEUtils NimBLEUtils
+#define BLEClientCallbacks NimBLEClientCallbacks
+#define BLEAdvertisedDeviceCallbacks NimBLEAdvertisedDeviceCallbacks
+#define BLEScanResults NimBLEScanResults
+#define BLEServer NimBLEServer
+#define BLEService NimBLEService
+#define BLECharacteristic NimBLECharacteristic
+#define BLEAdvertising NimBLEAdvertising
+#define BLEServerCallbacks NimBLEServerCallbacks
+#define BLECharacteristicCallbacks NimBLECharacteristicCallbacks
+#define BLEAdvertisementData NimBLEAdvertisementData
+#define BLEDescriptor NimBLEDescriptor
+#define BLE2902 NimBLE2902
+#define BLE2904 NimBLE2904
+#define BLEDescriptorCallbacks NimBLEDescriptorCallbacks
+#define BLEBeacon NimBLEBeacon
+#define BLEEddystoneTLM NimBLEEddystoneTLM
+#define BLEEddystoneURL NimBLEEddystoneURL
+
+#ifdef CONFIG_BT_NIMBLE_MAX_CONNECTIONS
+#define NIMBLE_MAX_CONNECTIONS CONFIG_BT_NIMBLE_MAX_CONNECTIONS
+#else
+#define NIMBLE_MAX_CONNECTIONS CONFIG_NIMBLE_MAX_CONNECTIONS
+#endif
+
+typedef int (*gap_event_handler)(ble_gap_event *event, void *arg);
+
+extern "C" void ble_store_config_init(void);
+
+/**
+ * @brief A model of a %BLE Device from which all the BLE roles are created.
+ */
+class NimBLEDevice {
+public:
+ static void init(const std::string &deviceName);
+ static void deinit(bool clearAll = false);
+ static bool getInitialized();
+ static NimBLEAddress getAddress();
+ static std::string toString();
+ static bool whiteListAdd(const NimBLEAddress & address);
+ static bool whiteListRemove(const NimBLEAddress & address);
+ static bool onWhiteList(const NimBLEAddress & address);
+ static size_t getWhiteListCount();
+ static NimBLEAddress getWhiteListAddress(size_t index);
+
+#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
+ static NimBLEScan* getScan();
+#endif
+
+#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
+ static NimBLEServer* createServer();
+ static NimBLEServer* getServer();
+#endif
+
+#ifdef ESP_PLATFORM
+ static void setPower(esp_power_level_t powerLevel, esp_ble_power_type_t powerType=ESP_BLE_PWR_TYPE_DEFAULT);
+ static int getPower(esp_ble_power_type_t powerType=ESP_BLE_PWR_TYPE_DEFAULT);
+ static void setOwnAddrType(uint8_t own_addr_type, bool useNRPA=false);
+ static void setScanDuplicateCacheSize(uint16_t cacheSize);
+ static void setScanFilterMode(uint8_t type);
+#else
+ static void setPower(int dbm);
+ static int getPower();
+#endif
+
+ static void setCustomGapHandler(gap_event_handler handler);
+ static void setSecurityAuth(bool bonding, bool mitm, bool sc);
+ static void setSecurityAuth(uint8_t auth_req);
+ static void setSecurityIOCap(uint8_t iocap);
+ static void setSecurityInitKey(uint8_t init_key);
+ static void setSecurityRespKey(uint8_t init_key);
+ static void setSecurityPasskey(uint32_t pin);
+ static uint32_t getSecurityPasskey();
+ static void setSecurityCallbacks(NimBLESecurityCallbacks* pCallbacks);
+ static int startSecurity(uint16_t conn_id);
+ static int setMTU(uint16_t mtu);
+ static uint16_t getMTU();
+ static bool isIgnored(const NimBLEAddress &address);
+ static void addIgnored(const NimBLEAddress &address);
+ static void removeIgnored(const NimBLEAddress &address);
+
+#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
+ static NimBLEAdvertising* getAdvertising();
+ static void startAdvertising();
+ static void stopAdvertising();
+#endif
+
+#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
+ static NimBLEClient* createClient(NimBLEAddress peerAddress = NimBLEAddress(""));
+ static bool deleteClient(NimBLEClient* pClient);
+ static NimBLEClient* getClientByID(uint16_t conn_id);
+ static NimBLEClient* getClientByPeerAddress(const NimBLEAddress &peer_addr);
+ static NimBLEClient* getDisconnectedClient();
+ static size_t getClientListSize();
+ static std::list* getClientList();
+#endif
+
+#if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL) || defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
+ static bool deleteBond(const NimBLEAddress &address);
+ static int getNumBonds();
+ static bool isBonded(const NimBLEAddress &address);
+ static void deleteAllBonds();
+ static NimBLEAddress getBondedAddress(int index);
+#endif
+
+private:
+#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
+ friend class NimBLEClient;
+#endif
+
+#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
+ friend class NimBLEScan;
+#endif
+
+#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
+ friend class NimBLEServer;
+ friend class NimBLECharacteristic;
+#endif
+
+#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
+ friend class NimBLEAdvertising;
+#endif
+
+ static void onReset(int reason);
+ static void onSync(void);
+ static void host_task(void *param);
+ static bool m_synced;
+
+#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
+ static NimBLEScan* m_pScan;
+#endif
+
+#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
+ static NimBLEServer* m_pServer;
+#endif
+
+#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
+ static NimBLEAdvertising* m_bleAdvertising;
+#endif
+
+#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
+ static std::list m_cList;
+#endif
+ static std::list m_ignoreList;
+ static NimBLESecurityCallbacks* m_securityCallbacks;
+ static uint32_t m_passkey;
+ static ble_gap_event_listener m_listener;
+ static gap_event_handler m_customGapHandler;
+ static uint8_t m_own_addr_type;
+#ifdef ESP_PLATFORM
+ static uint16_t m_scanDuplicateSize;
+ static uint8_t m_scanFilterMode;
+#endif
+ static std::vector m_whiteList;
+};
+
+
+#endif // CONFIG_BT_ENABLED
+#endif // MAIN_NIMBLEDEVICE_H_
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/NimBLEEddystoneTLM.cpp b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEEddystoneTLM.cpp
new file mode 100644
index 0000000..255131c
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEEddystoneTLM.cpp
@@ -0,0 +1,227 @@
+/*
+ * NimBLEEddystoneTLM.cpp
+ *
+ * Created: on March 15 2020
+ * Author H2zero
+ *
+ * Originally:
+ *
+ * BLEEddystoneTLM.cpp
+ *
+ * Created on: Mar 12, 2018
+ * Author: pcbreflux
+ */
+
+#include "nimconfig.h"
+#if defined(CONFIG_BT_ENABLED)
+
+#include "NimBLEEddystoneTLM.h"
+#include "NimBLELog.h"
+
+#include
+#include
+
+#define ENDIAN_CHANGE_U16(x) ((((x)&0xFF00)>>8) + (((x)&0xFF)<<8))
+#define ENDIAN_CHANGE_U32(x) ((((x)&0xFF000000)>>24) + (((x)&0x00FF0000)>>8)) + ((((x)&0xFF00)<<8) + (((x)&0xFF)<<24))
+
+static const char LOG_TAG[] = "NimBLEEddystoneTLM";
+
+/**
+ * @brief Construct a default EddystoneTLM beacon object.
+ */
+NimBLEEddystoneTLM::NimBLEEddystoneTLM() {
+ beaconUUID = 0xFEAA;
+ m_eddystoneData.frameType = EDDYSTONE_TLM_FRAME_TYPE;
+ m_eddystoneData.version = 0;
+ m_eddystoneData.volt = 3300; // 3300mV = 3.3V
+ m_eddystoneData.temp = (uint16_t) ((float) 23.00 * 256); // 8.8 fixed format
+ m_eddystoneData.advCount = 0;
+ m_eddystoneData.tmil = 0;
+} // NimBLEEddystoneTLM
+
+
+/**
+ * @brief Retrieve the data that is being advertised.
+ * @return The advertised data.
+ */
+std::string NimBLEEddystoneTLM::getData() {
+ return std::string((char*) &m_eddystoneData, sizeof(m_eddystoneData));
+} // getData
+
+
+/**
+ * @brief Get the UUID being advertised.
+ * @return The UUID advertised.
+ */
+NimBLEUUID NimBLEEddystoneTLM::getUUID() {
+ return NimBLEUUID(beaconUUID);
+} // getUUID
+
+
+/**
+ * @brief Get the version being advertised.
+ * @return The version number.
+ */
+uint8_t NimBLEEddystoneTLM::getVersion() {
+ return m_eddystoneData.version;
+} // getVersion
+
+
+/**
+ * @brief Get the battery voltage.
+ * @return The battery voltage.
+ */
+uint16_t NimBLEEddystoneTLM::getVolt() {
+ return ENDIAN_CHANGE_U16(m_eddystoneData.volt);
+} // getVolt
+
+
+/**
+ * @brief Get the temperature being advertised.
+ * @return The temperature value.
+ */
+float NimBLEEddystoneTLM::getTemp() {
+ return ENDIAN_CHANGE_U16(m_eddystoneData.temp) / 256.0f;
+} // getTemp
+
+/**
+ * @brief Get the count of advertisments sent.
+ * @return The number of advertisments.
+ */
+uint32_t NimBLEEddystoneTLM::getCount() {
+ return ENDIAN_CHANGE_U32(m_eddystoneData.advCount);
+} // getCount
+
+
+/**
+ * @brief Get the advertisment time.
+ * @return The advertisment time.
+ */
+uint32_t NimBLEEddystoneTLM::getTime() {
+ return (ENDIAN_CHANGE_U32(m_eddystoneData.tmil)) / 10;
+} // getTime
+
+
+/**
+ * @brief Get a string representation of the beacon.
+ * @return The string representation.
+ */
+std::string NimBLEEddystoneTLM::toString() {
+ std::string out = "";
+ uint32_t rawsec = ENDIAN_CHANGE_U32(m_eddystoneData.tmil);
+ char val[12];
+
+ out += "Version "; // + std::string(m_eddystoneData.version);
+ snprintf(val, sizeof(val), "%d", m_eddystoneData.version);
+ out += val;
+ out += "\n";
+ out += "Battery Voltage "; // + ENDIAN_CHANGE_U16(m_eddystoneData.volt);
+ snprintf(val, sizeof(val), "%d", ENDIAN_CHANGE_U16(m_eddystoneData.volt));
+ out += val;
+ out += " mV\n";
+
+ out += "Temperature ";
+ snprintf(val, sizeof(val), "%.2f", ENDIAN_CHANGE_U16(m_eddystoneData.temp) / 256.0f);
+ out += val;
+ out += " C\n";
+
+ out += "Adv. Count ";
+ snprintf(val, sizeof(val), "%" PRIu32, ENDIAN_CHANGE_U32(m_eddystoneData.advCount));
+ out += val;
+ out += "\n";
+
+ out += "Time in seconds ";
+ snprintf(val, sizeof(val), "%" PRIu32, rawsec/10);
+ out += val;
+ out += "\n";
+
+ out += "Time ";
+
+ snprintf(val, sizeof(val), "%04" PRIu32, rawsec / 864000);
+ out += val;
+ out += ".";
+
+ snprintf(val, sizeof(val), "%02" PRIu32, (rawsec / 36000) % 24);
+ out += val;
+ out += ":";
+
+ snprintf(val, sizeof(val), "%02" PRIu32, (rawsec / 600) % 60);
+ out += val;
+ out += ":";
+
+ snprintf(val, sizeof(val), "%02" PRIu32, (rawsec / 10) % 60);
+ out += val;
+ out += "\n";
+
+ return out;
+} // toString
+
+
+/**
+ * @brief Set the raw data for the beacon advertisment.
+ * @param [in] data The raw data to advertise.
+ */
+void NimBLEEddystoneTLM::setData(const std::string &data) {
+ if (data.length() != sizeof(m_eddystoneData)) {
+ NIMBLE_LOGE(LOG_TAG, "Unable to set the data ... length passed in was %d and expected %d",
+ data.length(), sizeof(m_eddystoneData));
+ return;
+ }
+ memcpy(&m_eddystoneData, data.data(), data.length());
+} // setData
+
+
+/**
+ * @brief Set the UUID to advertise.
+ * @param [in] l_uuid The UUID.
+ */
+void NimBLEEddystoneTLM::setUUID(const NimBLEUUID &l_uuid) {
+ beaconUUID = l_uuid.getNative()->u16.value;
+} // setUUID
+
+
+/**
+ * @brief Set the version to advertise.
+ * @param [in] version The version number.
+ */
+void NimBLEEddystoneTLM::setVersion(uint8_t version) {
+ m_eddystoneData.version = version;
+} // setVersion
+
+
+/**
+ * @brief Set the battery voltage to advertise.
+ * @param [in] volt The voltage in millivolts.
+ */
+void NimBLEEddystoneTLM::setVolt(uint16_t volt) {
+ m_eddystoneData.volt = volt;
+} // setVolt
+
+
+/**
+ * @brief Set the temperature to advertise.
+ * @param [in] temp The temperature value.
+ */
+void NimBLEEddystoneTLM::setTemp(float temp) {
+ m_eddystoneData.temp = (uint16_t)temp;
+} // setTemp
+
+
+/**
+ * @brief Set the advertisment count.
+ * @param [in] advCount The advertisment number.
+ */
+void NimBLEEddystoneTLM::setCount(uint32_t advCount) {
+ m_eddystoneData.advCount = advCount;
+} // setCount
+
+
+/**
+ * @brief Set the advertisment time.
+ * @param [in] tmil The advertisment time in milliseconds.
+ */
+void NimBLEEddystoneTLM::setTime(uint32_t tmil) {
+ m_eddystoneData.tmil = tmil;
+} // setTime
+
+#endif
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/NimBLEEddystoneTLM.h b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEEddystoneTLM.h
new file mode 100644
index 0000000..265c81b
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEEddystoneTLM.h
@@ -0,0 +1,61 @@
+/*
+ * NimBLEEddystoneTLM.h
+ *
+ * Created: on March 15 2020
+ * Author H2zero
+ *
+ * Originally:
+ *
+ * BLEEddystoneTLM.h
+ *
+ * Created on: Mar 12, 2018
+ * Author: pcbreflux
+ */
+
+#ifndef _NimBLEEddystoneTLM_H_
+#define _NimBLEEddystoneTLM_H_
+
+#include "NimBLEUUID.h"
+
+#include
+
+#define EDDYSTONE_TLM_FRAME_TYPE 0x20
+
+/**
+ * @brief Representation of a beacon.
+ * See:
+ * * https://github.com/google/eddystone
+ */
+class NimBLEEddystoneTLM {
+public:
+ NimBLEEddystoneTLM();
+ std::string getData();
+ NimBLEUUID getUUID();
+ uint8_t getVersion();
+ uint16_t getVolt();
+ float getTemp();
+ uint32_t getCount();
+ uint32_t getTime();
+ std::string toString();
+ void setData(const std::string &data);
+ void setUUID(const NimBLEUUID &l_uuid);
+ void setVersion(uint8_t version);
+ void setVolt(uint16_t volt);
+ void setTemp(float temp);
+ void setCount(uint32_t advCount);
+ void setTime(uint32_t tmil);
+
+private:
+ uint16_t beaconUUID;
+ struct {
+ uint8_t frameType;
+ uint8_t version;
+ uint16_t volt;
+ uint16_t temp;
+ uint32_t advCount;
+ uint32_t tmil;
+ } __attribute__((packed)) m_eddystoneData;
+
+}; // NimBLEEddystoneTLM
+
+#endif /* _NimBLEEddystoneTLM_H_ */
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/NimBLEEddystoneURL.cpp b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEEddystoneURL.cpp
new file mode 100644
index 0000000..424df95
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEEddystoneURL.cpp
@@ -0,0 +1,204 @@
+/*
+ * NimBLEEddystoneURL.cpp
+ *
+ * Created: on March 15 2020
+ * Author H2zero
+ *
+ * Originally:
+ *
+ * BLEEddystoneURL.cpp
+ *
+ * Created on: Mar 12, 2018
+ * Author: pcbreflux
+ */
+#include "nimconfig.h"
+#if defined(CONFIG_BT_ENABLED)
+
+#include "NimBLEEddystoneURL.h"
+#include "NimBLELog.h"
+
+#include
+
+static const char LOG_TAG[] = "NimBLEEddystoneURL";
+
+
+/**
+ * @brief Construct a default EddystoneURL beacon object.
+ */
+NimBLEEddystoneURL::NimBLEEddystoneURL() {
+ beaconUUID = 0xFEAA;
+ lengthURL = 0;
+ m_eddystoneData.frameType = EDDYSTONE_URL_FRAME_TYPE;
+ m_eddystoneData.advertisedTxPower = 0;
+ memset(m_eddystoneData.url, 0, sizeof(m_eddystoneData.url));
+} // BLEEddystoneURL
+
+
+/**
+ * @brief Retrieve the data that is being advertised.
+ * @return The advertised data.
+ */
+std::string NimBLEEddystoneURL::getData() {
+ return std::string((char*) &m_eddystoneData, sizeof(m_eddystoneData));
+} // getData
+
+
+/**
+ * @brief Get the UUID being advertised.
+ * @return The UUID advertised.
+ */
+NimBLEUUID NimBLEEddystoneURL::getUUID() {
+ return NimBLEUUID(beaconUUID);
+} // getUUID
+
+
+/**
+ * @brief Get the transmit power being advertised.
+ * @return The transmit power.
+ */
+int8_t NimBLEEddystoneURL::getPower() {
+ return m_eddystoneData.advertisedTxPower;
+} // getPower
+
+
+/**
+ * @brief Get the raw URL being advertised.
+ * @return The raw URL.
+ */
+std::string NimBLEEddystoneURL::getURL() {
+ return std::string((char*) &m_eddystoneData.url, sizeof(m_eddystoneData.url));
+} // getURL
+
+
+/**
+ * @brief Get the full URL being advertised.
+ * @return The full URL.
+ */
+std::string NimBLEEddystoneURL::getDecodedURL() {
+ std::string decodedURL = "";
+
+ switch (m_eddystoneData.url[0]) {
+ case 0x00:
+ decodedURL += "http://www.";
+ break;
+ case 0x01:
+ decodedURL += "https://www.";
+ break;
+ case 0x02:
+ decodedURL += "http://";
+ break;
+ case 0x03:
+ decodedURL += "https://";
+ break;
+ default:
+ decodedURL += m_eddystoneData.url[0];
+ }
+
+ for (int i = 1; i < lengthURL; i++) {
+ if (m_eddystoneData.url[i] > 33 && m_eddystoneData.url[i] < 127) {
+ decodedURL += m_eddystoneData.url[i];
+ } else {
+ switch (m_eddystoneData.url[i]) {
+ case 0x00:
+ decodedURL += ".com/";
+ break;
+ case 0x01:
+ decodedURL += ".org/";
+ break;
+ case 0x02:
+ decodedURL += ".edu/";
+ break;
+ case 0x03:
+ decodedURL += ".net/";
+ break;
+ case 0x04:
+ decodedURL += ".info/";
+ break;
+ case 0x05:
+ decodedURL += ".biz/";
+ break;
+ case 0x06:
+ decodedURL += ".gov/";
+ break;
+ case 0x07:
+ decodedURL += ".com";
+ break;
+ case 0x08:
+ decodedURL += ".org";
+ break;
+ case 0x09:
+ decodedURL += ".edu";
+ break;
+ case 0x0A:
+ decodedURL += ".net";
+ break;
+ case 0x0B:
+ decodedURL += ".info";
+ break;
+ case 0x0C:
+ decodedURL += ".biz";
+ break;
+ case 0x0D:
+ decodedURL += ".gov";
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ return decodedURL;
+} // getDecodedURL
+
+
+
+/**
+ * @brief Set the raw data for the beacon advertisment.
+ * @param [in] data The raw data to advertise.
+ */
+void NimBLEEddystoneURL::setData(const std::string &data) {
+ if (data.length() > sizeof(m_eddystoneData)) {
+ NIMBLE_LOGE(LOG_TAG, "Unable to set the data ... length passed in was %d and max expected %d",
+ data.length(), sizeof(m_eddystoneData));
+ return;
+ }
+ memset(&m_eddystoneData, 0, sizeof(m_eddystoneData));
+ memcpy(&m_eddystoneData, data.data(), data.length());
+ lengthURL = data.length() - (sizeof(m_eddystoneData) - sizeof(m_eddystoneData.url));
+} // setData
+
+
+/**
+ * @brief Set the UUID to advertise.
+ * @param [in] l_uuid The UUID.
+ */
+void NimBLEEddystoneURL::setUUID(const NimBLEUUID &l_uuid) {
+ beaconUUID = l_uuid.getNative()->u16.value;
+} // setUUID
+
+
+/**
+ * @brief Set the transmit power to advertise.
+ * @param [in] advertisedTxPower The transmit power level.
+ */
+void NimBLEEddystoneURL::setPower(int8_t advertisedTxPower) {
+ m_eddystoneData.advertisedTxPower = advertisedTxPower;
+} // setPower
+
+
+/**
+ * @brief Set the URL to advertise.
+ * @param [in] url The URL.
+ */
+void NimBLEEddystoneURL::setURL(const std::string &url) {
+ if (url.length() > sizeof(m_eddystoneData.url)) {
+ NIMBLE_LOGE(LOG_TAG, "Unable to set the url ... length passed in was %d and max expected %d",
+ url.length(), sizeof(m_eddystoneData.url));
+ return;
+ }
+ memset(m_eddystoneData.url, 0, sizeof(m_eddystoneData.url));
+ memcpy(m_eddystoneData.url, url.data(), url.length());
+ lengthURL = url.length();
+} // setURL
+
+
+#endif
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/NimBLEEddystoneURL.h b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEEddystoneURL.h
new file mode 100644
index 0000000..9c5f37f
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEEddystoneURL.h
@@ -0,0 +1,52 @@
+/*
+ * NimBLEEddystoneURL.h
+ *
+ * Created: on March 15 2020
+ * Author H2zero
+ *
+ * Originally:
+ *
+ * BLEEddystoneURL.h
+ *
+ * Created on: Mar 12, 2018
+ * Author: pcbreflux
+ */
+
+#ifndef _NIMBLEEddystoneURL_H_
+#define _NIMBLEEddystoneURL_H_
+#include "NimBLEUUID.h"
+
+#include
+
+#define EDDYSTONE_URL_FRAME_TYPE 0x10
+
+/**
+ * @brief Representation of a beacon.
+ * See:
+ * * https://github.com/google/eddystone
+ */
+class NimBLEEddystoneURL {
+public:
+ NimBLEEddystoneURL();
+ std::string getData();
+ NimBLEUUID getUUID();
+ int8_t getPower();
+ std::string getURL();
+ std::string getDecodedURL();
+ void setData(const std::string &data);
+ void setUUID(const NimBLEUUID &l_uuid);
+ void setPower(int8_t advertisedTxPower);
+ void setURL(const std::string &url);
+
+private:
+ uint16_t beaconUUID;
+ uint8_t lengthURL;
+ struct {
+ uint8_t frameType;
+ int8_t advertisedTxPower;
+ uint8_t url[16];
+ } __attribute__((packed)) m_eddystoneData;
+
+}; // NIMBLEEddystoneURL
+
+#endif /* _NIMBLEEddystoneURL_H_ */
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/NimBLEHIDDevice.cpp b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEHIDDevice.cpp
new file mode 100644
index 0000000..78c8fea
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEHIDDevice.cpp
@@ -0,0 +1,248 @@
+/*
+ * NimBLEHIDDevice.cpp
+ *
+ * Created: on Oct 06 2020
+ * Author wakwak-koba
+ *
+ * Originally:
+ *
+ * BLEHIDDevice.cpp
+ *
+ * Created on: Jan 03, 2018
+ * Author: chegewara
+ */
+
+#include "nimconfig.h"
+#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
+
+#include "NimBLEHIDDevice.h"
+#include "NimBLE2904.h"
+
+/**
+ * @brief Construct a default NimBLEHIDDevice object.
+ * @param [in] server A pointer to the server instance this HID Device will use.
+ */
+NimBLEHIDDevice::NimBLEHIDDevice(NimBLEServer* server) {
+ /*
+ * Here we create mandatory services described in bluetooth specification
+ */
+ m_deviceInfoService = server->createService(NimBLEUUID((uint16_t) 0x180a));
+ m_hidService = server->createService(NimBLEUUID((uint16_t) 0x1812));
+ m_batteryService = server->createService(NimBLEUUID((uint16_t) 0x180f));
+
+ /*
+ * Mandatory characteristic for device info service
+ */
+ m_pnpCharacteristic = m_deviceInfoService->createCharacteristic((uint16_t) 0x2a50, NIMBLE_PROPERTY::READ);
+
+ /*
+ * Mandatory characteristics for HID service
+ */
+ m_hidInfoCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4a, NIMBLE_PROPERTY::READ);
+ m_reportMapCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4b, NIMBLE_PROPERTY::READ);
+ m_hidControlCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4c, NIMBLE_PROPERTY::WRITE_NR);
+ m_protocolModeCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4e, NIMBLE_PROPERTY::WRITE_NR | NIMBLE_PROPERTY::READ);
+
+ /*
+ * Mandatory battery level characteristic with notification and presence descriptor
+ */
+ m_batteryLevelCharacteristic = m_batteryService->createCharacteristic((uint16_t) 0x2a19, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::NOTIFY);
+ NimBLE2904* batteryLevelDescriptor = (NimBLE2904*)m_batteryLevelCharacteristic->createDescriptor((uint16_t) 0x2904);
+ batteryLevelDescriptor->setFormat(NimBLE2904::FORMAT_UINT8);
+ batteryLevelDescriptor->setNamespace(1);
+ batteryLevelDescriptor->setUnit(0x27ad);
+
+ /*
+ * This value is setup here because its default value in most usage cases, its very rare to use boot mode
+ * and we want to simplify library using as much as possible
+ */
+ const uint8_t pMode[] = { 0x01 };
+ protocolMode()->setValue((uint8_t*) pMode, 1);
+}
+
+NimBLEHIDDevice::~NimBLEHIDDevice() {
+}
+
+/**
+ * @brief Set the report map data formatting information.
+ * @param [in] map A pointer to an array with the values to set.
+ * @param [in] size The number of values in the array.
+ */
+void NimBLEHIDDevice::reportMap(uint8_t* map, uint16_t size) {
+ m_reportMapCharacteristic->setValue(map, size);
+}
+
+/**
+ * @brief Start the HID device services.\n
+ * This function called when all the services have been created.
+ */
+void NimBLEHIDDevice::startServices() {
+ m_deviceInfoService->start();
+ m_hidService->start();
+ m_batteryService->start();
+}
+
+/**
+ * @brief Create a manufacturer characteristic (this characteristic is optional).
+ */
+NimBLECharacteristic* NimBLEHIDDevice::manufacturer() {
+ m_manufacturerCharacteristic = m_deviceInfoService->createCharacteristic((uint16_t) 0x2a29, NIMBLE_PROPERTY::READ);
+ return m_manufacturerCharacteristic;
+}
+
+/**
+ * @brief Set manufacturer name
+ * @param [in] name The manufacturer name of this HID device.
+ */
+void NimBLEHIDDevice::manufacturer(std::string name) {
+ m_manufacturerCharacteristic->setValue(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] pid The product ID number.
+ * @param [in] version The produce version number.
+ */
+void NimBLEHIDDevice::pnp(uint8_t sig, uint16_t vid, uint16_t pid, uint16_t version) {
+ uint8_t pnp[] = { sig, (uint8_t) (vid >> 8), (uint8_t) vid, (uint8_t) (pid >> 8), (uint8_t) pid, (uint8_t) (version >> 8), (uint8_t) version };
+ m_pnpCharacteristic->setValue(pnp, sizeof(pnp));
+}
+
+/**
+ * @brief Sets the HID Information characteristic value.
+ * @param [in] country The country code for the device.
+ * @param [in] flags The HID Class Specification release number to use.
+ */
+void NimBLEHIDDevice::hidInfo(uint8_t country, uint8_t flags) {
+ uint8_t info[] = { 0x11, 0x1, country, flags };
+ m_hidInfoCharacteristic->setValue(info, sizeof(info));
+}
+
+/**
+ * @brief Create input report characteristic
+ * @param [in] reportID input report ID, the same as in report map for input object related to the characteristic
+ * @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 | 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);
+
+ return inputReportCharacteristic;
+}
+
+/**
+ * @brief Create output report characteristic
+ * @param [in] reportID Output report ID, the same as in report map for output object related to the characteristic
+ * @return Pointer to new output report characteristic
+ */
+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, 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);
+
+ return outputReportCharacteristic;
+}
+
+/**
+ * @brief Create feature report characteristic.
+ * @param [in] reportID Feature report ID, the same as in report map for feature object related to the characteristic
+ * @return Pointer to new feature report characteristic
+ */
+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, 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);
+
+ return featureReportCharacteristic;
+}
+
+/**
+ * @brief Creates a keyboard boot input report characteristic
+ */
+NimBLECharacteristic* NimBLEHIDDevice::bootInput() {
+ return m_hidService->createCharacteristic((uint16_t) 0x2a22, NIMBLE_PROPERTY::NOTIFY);
+}
+
+/**
+ * @brief Create a keyboard boot output report characteristic
+ */
+NimBLECharacteristic* NimBLEHIDDevice::bootOutput() {
+ return m_hidService->createCharacteristic((uint16_t) 0x2a32, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::WRITE_NR);
+}
+
+/**
+ * @brief Returns a pointer to the HID control point characteristic.
+ */
+NimBLECharacteristic* NimBLEHIDDevice::hidControl() {
+ return m_hidControlCharacteristic;
+}
+
+/**
+ * @brief Returns a pointer to the protocol mode characteristic.
+ */
+NimBLECharacteristic* NimBLEHIDDevice::protocolMode() {
+ return m_protocolModeCharacteristic;
+}
+
+/**
+ * @brief Set the battery level characteristic value.
+ * @param [in] level The battery level value.
+ */
+void NimBLEHIDDevice::setBatteryLevel(uint8_t level) {
+ m_batteryLevelCharacteristic->setValue(&level, 1);
+}
+/*
+ * @brief Returns battery level characteristic
+ * @ return battery level characteristic
+ *//*
+BLECharacteristic* BLEHIDDevice::batteryLevel() {
+ return m_batteryLevelCharacteristic;
+}
+
+
+
+BLECharacteristic* BLEHIDDevice::reportMap() {
+ return m_reportMapCharacteristic;
+}
+
+BLECharacteristic* BLEHIDDevice::pnp() {
+ return m_pnpCharacteristic;
+}
+
+
+BLECharacteristic* BLEHIDDevice::hidInfo() {
+ return m_hidInfoCharacteristic;
+}
+*/
+
+/**
+ * @brief Returns a pointer to the device information service.
+ */
+NimBLEService* NimBLEHIDDevice::deviceInfo() {
+ return m_deviceInfoService;
+}
+
+/**
+ * @brief Returns a pointer to the HID service.
+ */
+NimBLEService* NimBLEHIDDevice::hidService() {
+ return m_hidService;
+}
+
+/**
+ * @brief @brief Returns a pointer to the battery service.
+ */
+NimBLEService* NimBLEHIDDevice::batteryService() {
+ return m_batteryService;
+}
+
+#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/NimBLEHIDDevice.h b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEHIDDevice.h
new file mode 100644
index 0000000..ef2ed73
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEHIDDevice.h
@@ -0,0 +1,86 @@
+/*
+ * NimBLEHIDDevice.h
+ *
+ * Created: on Oct 06 2020
+ * Author wakwak-koba
+ *
+ * Originally:
+ *
+ * BLEHIDDevice.h
+ *
+ * Created on: Jan 03, 2018
+ * Author: chegewara
+ */
+
+#ifndef _BLEHIDDEVICE_H_
+#define _BLEHIDDEVICE_H_
+
+#include "nimconfig.h"
+#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
+
+#include "NimBLECharacteristic.h"
+#include "NimBLEService.h"
+#include "NimBLEDescriptor.h"
+#include "HIDTypes.h"
+
+#define GENERIC_HID 0x03C0
+#define HID_KEYBOARD 0x03C1
+#define HID_MOUSE 0x03C2
+#define HID_JOYSTICK 0x03C3
+#define HID_GAMEPAD 0x03C4
+#define HID_TABLET 0x03C5
+#define HID_CARD_READER 0x03C6
+#define HID_DIGITAL_PEN 0x03C7
+#define HID_BARCODE 0x03C8
+
+
+/**
+ * @brief A model of a %BLE Human Interface Device.
+ */
+class NimBLEHIDDevice {
+public:
+ NimBLEHIDDevice(NimBLEServer*);
+ virtual ~NimBLEHIDDevice();
+
+ void reportMap(uint8_t* map, uint16_t);
+ void startServices();
+
+ NimBLEService* deviceInfo();
+ NimBLEService* hidService();
+ NimBLEService* batteryService();
+
+ NimBLECharacteristic* manufacturer();
+ void manufacturer(std::string name);
+ //NimBLECharacteristic* pnp();
+ void pnp(uint8_t sig, uint16_t vid, uint16_t pid, uint16_t version);
+ //NimBLECharacteristic* hidInfo();
+ void hidInfo(uint8_t country, uint8_t flags);
+ //NimBLECharacteristic* batteryLevel();
+ void setBatteryLevel(uint8_t level);
+
+
+ //NimBLECharacteristic* reportMap();
+ NimBLECharacteristic* hidControl();
+ NimBLECharacteristic* inputReport(uint8_t reportID);
+ NimBLECharacteristic* outputReport(uint8_t reportID);
+ NimBLECharacteristic* featureReport(uint8_t reportID);
+ NimBLECharacteristic* protocolMode();
+ NimBLECharacteristic* bootInput();
+ NimBLECharacteristic* bootOutput();
+
+private:
+ NimBLEService* m_deviceInfoService; //0x180a
+ NimBLEService* m_hidService; //0x1812
+ NimBLEService* m_batteryService = 0; //0x180f
+
+ NimBLECharacteristic* m_manufacturerCharacteristic; //0x2a29
+ NimBLECharacteristic* m_pnpCharacteristic; //0x2a50
+ NimBLECharacteristic* m_hidInfoCharacteristic; //0x2a4a
+ NimBLECharacteristic* m_reportMapCharacteristic; //0x2a4b
+ NimBLECharacteristic* m_hidControlCharacteristic; //0x2a4c
+ NimBLECharacteristic* m_protocolModeCharacteristic; //0x2a4e
+ NimBLECharacteristic* m_batteryLevelCharacteristic; //0x2a19
+};
+
+#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER */
+#endif /* _BLEHIDDEVICE_H_ */
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/NimBLELog.h b/src/components/esp-nimble-cpp-1.3.3/src/NimBLELog.h
new file mode 100644
index 0000000..dda9073
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/NimBLELog.h
@@ -0,0 +1,80 @@
+/*
+ * NimBLELog.h
+ *
+ * Created: on Feb 24 2020
+ * Author H2zero
+ *
+ */
+#ifndef MAIN_NIMBLELOG_H_
+#define MAIN_NIMBLELOG_H_
+
+#include "nimconfig.h"
+
+#if defined(CONFIG_BT_ENABLED)
+
+#if defined(CONFIG_NIMBLE_CPP_IDF) // using esp-idf
+# include "esp_log.h"
+# ifndef CONFIG_NIMBLE_CPP_LOG_LEVEL
+# define CONFIG_NIMBLE_CPP_LOG_LEVEL 0
+# endif
+
+# define NIMBLE_CPP_LOG_PRINT(level, tag, format, ...) do { \
+ if (CONFIG_NIMBLE_CPP_LOG_LEVEL >= level) \
+ ESP_LOG_LEVEL_LOCAL(level, tag, format, ##__VA_ARGS__); \
+ } while(0)
+
+# define NIMBLE_LOGD(tag, format, ...) \
+ NIMBLE_CPP_LOG_PRINT(ESP_LOG_DEBUG, tag, format, ##__VA_ARGS__)
+
+# define NIMBLE_LOGI(tag, format, ...) \
+ NIMBLE_CPP_LOG_PRINT(ESP_LOG_INFO, tag, format, ##__VA_ARGS__)
+
+# define NIMBLE_LOGW(tag, format, ...) \
+ NIMBLE_CPP_LOG_PRINT(ESP_LOG_WARN, tag, format, ##__VA_ARGS__)
+
+# define NIMBLE_LOGE(tag, format, ...) \
+ NIMBLE_CPP_LOG_PRINT(ESP_LOG_ERROR, tag, format, ##__VA_ARGS__)
+
+# define NIMBLE_LOGC(tag, format, ...) \
+ NIMBLE_CPP_LOG_PRINT(ESP_LOG_ERROR, tag, format, ##__VA_ARGS__)
+
+#else // using Arduino
+# include "nimble/porting/nimble/include/syscfg/syscfg.h"
+# include "nimble/console/console.h"
+# ifndef CONFIG_NIMBLE_CPP_LOG_LEVEL
+# if defined(ARDUINO_ARCH_ESP32) && defined(CORE_DEBUG_LEVEL)
+# define CONFIG_NIMBLE_CPP_LOG_LEVEL CORE_DEBUG_LEVEL
+# else
+# define CONFIG_NIMBLE_CPP_LOG_LEVEL 0
+# endif
+# endif
+
+# if CONFIG_NIMBLE_CPP_LOG_LEVEL >= 4
+# define NIMBLE_LOGD( tag, format, ... ) console_printf("D %s: " format "\n", tag, ##__VA_ARGS__)
+# else
+# define NIMBLE_LOGD( tag, format, ... ) (void)tag
+# endif
+
+# if CONFIG_NIMBLE_CPP_LOG_LEVEL >= 3
+# define NIMBLE_LOGI( tag, format, ... ) console_printf("I %s: " format "\n", tag, ##__VA_ARGS__)
+# else
+# define NIMBLE_LOGI( tag, format, ... ) (void)tag
+# endif
+
+# if CONFIG_NIMBLE_CPP_LOG_LEVEL >= 2
+# define NIMBLE_LOGW( tag, format, ... ) console_printf("W %s: " format "\n", tag, ##__VA_ARGS__)
+# else
+# define NIMBLE_LOGW( tag, format, ... ) (void)tag
+# endif
+
+# if CONFIG_NIMBLE_CPP_LOG_LEVEL >= 1
+# define NIMBLE_LOGE( tag, format, ... ) console_printf("E %s: " format "\n", tag, ##__VA_ARGS__)
+# define NIMBLE_LOGC( tag, format, ... ) console_printf("CRIT %s: " format "\n", tag, ##__VA_ARGS__)
+# else
+# define NIMBLE_LOGE( tag, format, ... ) (void)tag
+# define NIMBLE_LOGC( tag, format, ... ) (void)tag
+# endif
+
+#endif /* CONFIG_NIMBLE_CPP_IDF */
+#endif /* CONFIG_BT_ENABLED */
+#endif /* MAIN_NIMBLELOG_H_ */
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/NimBLERemoteCharacteristic.cpp b/src/components/esp-nimble-cpp-1.3.3/src/NimBLERemoteCharacteristic.cpp
new file mode 100644
index 0000000..ab64da7
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/NimBLERemoteCharacteristic.cpp
@@ -0,0 +1,857 @@
+/*
+ * NimBLERemoteCharacteristic.cpp
+ *
+ * Created: on Jan 27 2020
+ * Author H2zero
+ *
+ * Originally:
+ *
+ * BLERemoteCharacteristic.cpp
+ *
+ * Created on: Mar 16, 2017
+ * Author: kolban
+ */
+
+#include "nimconfig.h"
+#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
+
+#include "NimBLERemoteCharacteristic.h"
+#include "NimBLEUtils.h"
+#include "NimBLELog.h"
+
+#include
+
+static const char* LOG_TAG = "NimBLERemoteCharacteristic";
+
+/**
+ * @brief Constructor.
+ * @param [in] reference to the service this characteristic belongs to.
+ * @param [in] ble_gatt_chr struct defined as:
+ * struct ble_gatt_chr {
+ * uint16_t def_handle;
+ * uint16_t val_handle;
+ * uint8_t properties;
+ * ble_uuid_any_t uuid;
+ * };
+ */
+ NimBLERemoteCharacteristic::NimBLERemoteCharacteristic(NimBLERemoteService *pRemoteService,
+ const struct ble_gatt_chr *chr)
+{
+ NIMBLE_LOGD(LOG_TAG, ">> NimBLERemoteCharacteristic()");
+ switch (chr->uuid.u.type) {
+ case BLE_UUID_TYPE_16:
+ m_uuid = NimBLEUUID(chr->uuid.u16.value);
+ break;
+ case BLE_UUID_TYPE_32:
+ m_uuid = NimBLEUUID(chr->uuid.u32.value);
+ break;
+ case BLE_UUID_TYPE_128:
+ m_uuid = NimBLEUUID(const_cast(&chr->uuid.u128));
+ break;
+ default:
+ break;
+ }
+
+ m_handle = chr->val_handle;
+ m_defHandle = chr->def_handle;
+ m_endHandle = 0;
+ m_charProp = chr->properties;
+ m_pRemoteService = pRemoteService;
+ m_notifyCallback = nullptr;
+ m_timestamp = 0;
+
+ NIMBLE_LOGD(LOG_TAG, "<< NimBLERemoteCharacteristic(): %s", m_uuid.toString().c_str());
+ } // NimBLERemoteCharacteristic
+
+
+/**
+ *@brief Destructor.
+ */
+NimBLERemoteCharacteristic::~NimBLERemoteCharacteristic() {
+ deleteDescriptors();
+} // ~NimBLERemoteCharacteristic
+
+/*
+#define BLE_GATT_CHR_PROP_BROADCAST 0x01
+#define BLE_GATT_CHR_PROP_READ 0x02
+#define BLE_GATT_CHR_PROP_WRITE_NO_RSP 0x04
+#define BLE_GATT_CHR_PROP_WRITE 0x08
+#define BLE_GATT_CHR_PROP_NOTIFY 0x10
+#define BLE_GATT_CHR_PROP_INDICATE 0x20
+#define BLE_GATT_CHR_PROP_AUTH_SIGN_WRITE 0x40
+#define BLE_GATT_CHR_PROP_EXTENDED 0x80
+*/
+
+/**
+ * @brief Does the characteristic support broadcasting?
+ * @return True if the characteristic supports broadcasting.
+ */
+bool NimBLERemoteCharacteristic::canBroadcast() {
+ return (m_charProp & BLE_GATT_CHR_PROP_BROADCAST) != 0;
+} // canBroadcast
+
+
+/**
+ * @brief Does the characteristic support indications?
+ * @return True if the characteristic supports indications.
+ */
+bool NimBLERemoteCharacteristic::canIndicate() {
+ return (m_charProp & BLE_GATT_CHR_PROP_INDICATE) != 0;
+} // canIndicate
+
+
+/**
+ * @brief Does the characteristic support notifications?
+ * @return True if the characteristic supports notifications.
+ */
+bool NimBLERemoteCharacteristic::canNotify() {
+ return (m_charProp & BLE_GATT_CHR_PROP_NOTIFY) != 0;
+} // canNotify
+
+
+/**
+ * @brief Does the characteristic support reading?
+ * @return True if the characteristic supports reading.
+ */
+bool NimBLERemoteCharacteristic::canRead() {
+ return (m_charProp & BLE_GATT_CHR_PROP_READ) != 0;
+} // canRead
+
+
+/**
+ * @brief Does the characteristic support writing?
+ * @return True if the characteristic supports writing.
+ */
+bool NimBLERemoteCharacteristic::canWrite() {
+ return (m_charProp & BLE_GATT_CHR_PROP_WRITE) != 0;
+} // canWrite
+
+
+/**
+ * @brief Does the characteristic support writing with no response?
+ * @return True if the characteristic supports writing with no response.
+ */
+bool NimBLERemoteCharacteristic::canWriteNoResponse() {
+ return (m_charProp & BLE_GATT_CHR_PROP_WRITE_NO_RSP) != 0;
+} // canWriteNoResponse
+
+
+/**
+ * @brief Callback used by the API when a descriptor is discovered or search complete.
+ */
+int NimBLERemoteCharacteristic::descriptorDiscCB(uint16_t conn_handle,
+ const struct ble_gatt_error *error,
+ uint16_t chr_val_handle,
+ const struct ble_gatt_dsc *dsc,
+ void *arg)
+{
+ int rc = error->status;
+ NIMBLE_LOGD(LOG_TAG, "Descriptor Discovered >> status: %d handle: %d",
+ rc, (rc == 0) ? dsc->handle : -1);
+
+ desc_filter_t *filter = (desc_filter_t*)arg;
+ const NimBLEUUID *uuid_filter = filter->uuid;
+ ble_task_data_t *pTaskData = (ble_task_data_t*)filter->task_data;
+ NimBLERemoteCharacteristic *characteristic = (NimBLERemoteCharacteristic*)pTaskData->pATT;
+
+ if (characteristic->getRemoteService()->getClient()->getConnId() != conn_handle){
+ return 0;
+ }
+
+ switch (rc) {
+ case 0: {
+ if (uuid_filter != nullptr) {
+ if (ble_uuid_cmp(&uuid_filter->getNative()->u, &dsc->uuid.u) != 0) {
+ return 0;
+ } else {
+ rc = BLE_HS_EDONE;
+ }
+ }
+
+ NimBLERemoteDescriptor* pNewRemoteDescriptor = new NimBLERemoteDescriptor(characteristic, dsc);
+ characteristic->m_descriptorVector.push_back(pNewRemoteDescriptor);
+ break;
+ }
+ default:
+ break;
+ }
+
+ /* If rc == BLE_HS_EDONE, resume the task with a success error code and stop the discovery process.
+ * Else if rc == 0, just return 0 to continue the discovery until we get BLE_HS_EDONE.
+ * If we get any other error code tell the application to abort by returning non-zero in the rc.
+ */
+ if (rc == BLE_HS_EDONE) {
+ pTaskData->rc = 0;
+ xTaskNotifyGive(pTaskData->task);
+ } else if(rc != 0) {
+ // Error; abort discovery.
+ pTaskData->rc = rc;
+ xTaskNotifyGive(pTaskData->task);
+ }
+
+ NIMBLE_LOGD(LOG_TAG,"<< Descriptor Discovered. status: %d", pTaskData->rc);
+ return rc;
+}
+
+
+/**
+ * @brief callback from NimBLE when the next characteristic of the service is discovered.
+ */
+int NimBLERemoteCharacteristic::nextCharCB(uint16_t conn_handle,
+ const struct ble_gatt_error *error,
+ const struct ble_gatt_chr *chr, void *arg)
+{
+ int rc = error->status;
+ NIMBLE_LOGD(LOG_TAG, "Next Characteristic >> status: %d handle: %d",
+ rc, (rc == 0) ? chr->val_handle : -1);
+
+ ble_task_data_t *pTaskData = (ble_task_data_t*)arg;
+ NimBLERemoteCharacteristic *pChar = (NimBLERemoteCharacteristic*)pTaskData->pATT;
+
+ if (pChar->getRemoteService()->getClient()->getConnId() != conn_handle) {
+ return 0;
+ }
+
+ if (rc == 0) {
+ pChar->m_endHandle = chr->def_handle - 1;
+ rc = BLE_HS_EDONE;
+ } else if (rc == BLE_HS_EDONE) {
+ pChar->m_endHandle = pChar->getRemoteService()->getEndHandle();
+ } else {
+ pTaskData->rc = rc;
+ }
+
+ xTaskNotifyGive(pTaskData->task);
+ return rc;
+}
+
+
+/**
+ * @brief Populate the descriptors (if any) for this characteristic.
+ * @param [in] the end handle of the characteristic, or the service, whichever comes first.
+ */
+bool NimBLERemoteCharacteristic::retrieveDescriptors(const NimBLEUUID *uuid_filter) {
+ NIMBLE_LOGD(LOG_TAG, ">> retrieveDescriptors() for characteristic: %s", getUUID().toString().c_str());
+
+ // If this is the last handle then there are no descriptors
+ if (m_handle == getRemoteService()->getEndHandle()) {
+ return true;
+ }
+
+ int rc = 0;
+ TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
+ ble_task_data_t taskData = {this, cur_task, 0, nullptr};
+
+ // If we don't know the end handle of this characteristic retrieve the next one in the service
+ // The end handle is the next characteristic definition handle -1.
+ if (m_endHandle == 0) {
+ rc = ble_gattc_disc_all_chrs(getRemoteService()->getClient()->getConnId(),
+ m_handle,
+ getRemoteService()->getEndHandle(),
+ NimBLERemoteCharacteristic::nextCharCB,
+ &taskData);
+ if (rc != 0) {
+ NIMBLE_LOGE(LOG_TAG, "Error getting end handle rc=%d", rc);
+ return false;
+ }
+
+#ifdef ulTaskNotifyValueClear
+ // Clear the task notification value to ensure we block
+ ulTaskNotifyValueClear(cur_task, ULONG_MAX);
+#endif
+ ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
+
+ if (taskData.rc != 0) {
+ NIMBLE_LOGE(LOG_TAG, "Could not retrieve end handle rc=%d", taskData.rc);
+ return false;
+ }
+ }
+
+ desc_filter_t filter = {uuid_filter, &taskData};
+
+ rc = ble_gattc_disc_all_dscs(getRemoteService()->getClient()->getConnId(),
+ m_handle,
+ m_endHandle,
+ NimBLERemoteCharacteristic::descriptorDiscCB,
+ &filter);
+
+ if (rc != 0) {
+ NIMBLE_LOGE(LOG_TAG, "ble_gattc_disc_all_dscs: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
+ return false;
+ }
+
+#ifdef ulTaskNotifyValueClear
+ // Clear the task notification value to ensure we block
+ ulTaskNotifyValueClear(cur_task, ULONG_MAX);
+#endif
+ ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
+
+ if (taskData.rc != 0) {
+ NIMBLE_LOGE(LOG_TAG, "Failed to retrieve descriptors; startHandle:%d endHandle:%d taskData.rc=%d",
+ m_handle, m_endHandle, taskData.rc);
+ }
+
+ NIMBLE_LOGD(LOG_TAG, "<< retrieveDescriptors(): Found %d descriptors.", m_descriptorVector.size());
+ return (taskData.rc == 0);
+} // retrieveDescriptors
+
+
+/**
+ * @brief Get the descriptor instance with the given UUID that belongs to this characteristic.
+ * @param [in] uuid The UUID of the descriptor to find.
+ * @return The Remote descriptor (if present) or null if not present.
+ */
+NimBLERemoteDescriptor* NimBLERemoteCharacteristic::getDescriptor(const NimBLEUUID &uuid) {
+ NIMBLE_LOGD(LOG_TAG, ">> getDescriptor: uuid: %s", uuid.toString().c_str());
+
+ for(auto &it: m_descriptorVector) {
+ if(it->getUUID() == uuid) {
+ NIMBLE_LOGD(LOG_TAG, "<< getDescriptor: found the descriptor with uuid: %s", uuid.toString().c_str());
+ return it;
+ }
+ }
+
+ size_t prev_size = m_descriptorVector.size();
+ if(retrieveDescriptors(&uuid)) {
+ if(m_descriptorVector.size() > prev_size) {
+ return m_descriptorVector.back();
+ }
+
+ // If the request was successful but 16/32 bit uuid not found
+ // try again with the 128 bit uuid.
+ if(uuid.bitSize() == BLE_UUID_TYPE_16 ||
+ uuid.bitSize() == BLE_UUID_TYPE_32)
+ {
+ NimBLEUUID uuid128(uuid);
+ uuid128.to128();
+ if(retrieveDescriptors(&uuid128)) {
+ if(m_descriptorVector.size() > prev_size) {
+ return m_descriptorVector.back();
+ }
+ }
+ } else {
+ // If the request was successful but the 128 bit uuid not found
+ // try again with the 16 bit uuid.
+ NimBLEUUID uuid16(uuid);
+ uuid16.to16();
+ // if the uuid was 128 bit but not of the BLE base type this check will fail
+ if (uuid16.bitSize() == BLE_UUID_TYPE_16) {
+ if(retrieveDescriptors(&uuid16)) {
+ if(m_descriptorVector.size() > prev_size) {
+ return m_descriptorVector.back();
+ }
+ }
+ }
+ }
+ }
+
+ NIMBLE_LOGD(LOG_TAG, "<< getDescriptor: Not found");
+ return nullptr;
+} // getDescriptor
+
+
+/**
+ * @brief Get a pointer to the vector of found descriptors.
+ * @param [in] refresh If true the current descriptor vector will be cleared and\n
+ * all descriptors for this characteristic retrieved from the peripheral.\n
+ * If false the vector will be returned with the currently stored descriptors
+ * of this characteristic.
+ * @return A pointer to the vector of descriptors for this characteristic.
+ */
+std::vector* NimBLERemoteCharacteristic::getDescriptors(bool refresh) {
+ if(refresh) {
+ deleteDescriptors();
+
+ if (!retrieveDescriptors()) {
+ NIMBLE_LOGE(LOG_TAG, "Error: Failed to get descriptors");
+ }
+ else{
+ NIMBLE_LOGI(LOG_TAG, "Found %d descriptor(s)", m_descriptorVector.size());
+ }
+ }
+ return &m_descriptorVector;
+} // getDescriptors
+
+
+/**
+ * @brief Get iterator to the beginning of the vector of remote descriptor pointers.
+ * @return An iterator to the beginning of the vector of remote descriptor pointers.
+ */
+std::vector::iterator NimBLERemoteCharacteristic::begin() {
+ return m_descriptorVector.begin();
+}
+
+
+/**
+ * @brief Get iterator to the end of the vector of remote descriptor pointers.
+ * @return An iterator to the end of the vector of remote descriptor pointers.
+ */
+std::vector::iterator NimBLERemoteCharacteristic::end() {
+ return m_descriptorVector.end();
+}
+
+
+/**
+ * @brief Get the handle for this characteristic.
+ * @return The handle for this characteristic.
+ */
+uint16_t NimBLERemoteCharacteristic::getHandle() {
+ return m_handle;
+} // getHandle
+
+/**
+ * @brief Get the handle for this characteristics definition.
+ * @return The handle for this characteristic definition.
+ */
+uint16_t NimBLERemoteCharacteristic::getDefHandle() {
+ return m_defHandle;
+} // getDefHandle
+
+
+/**
+ * @brief Get the remote service associated with this characteristic.
+ * @return The remote service associated with this characteristic.
+ */
+NimBLERemoteService* NimBLERemoteCharacteristic::getRemoteService() {
+ return m_pRemoteService;
+} // getRemoteService
+
+
+/**
+ * @brief Get the UUID for this characteristic.
+ * @return The UUID for this characteristic.
+ */
+NimBLEUUID NimBLERemoteCharacteristic::getUUID() {
+ return m_uuid;
+} // getUUID
+
+
+/**
+ * @brief Get the value of the remote characteristic.
+ * @param [in] timestamp A pointer to a time_t struct to store the time the value was read.
+ * @return The value of the remote characteristic.
+ */
+std::string NimBLERemoteCharacteristic::getValue(time_t *timestamp) {
+ ble_npl_hw_enter_critical();
+ std::string value = m_value;
+ if(timestamp != nullptr) {
+ *timestamp = m_timestamp;
+ }
+ ble_npl_hw_exit_critical(0);
+
+ return value;
+}
+
+
+/**
+ * @brief Read an unsigned 16 bit value
+ * @return The unsigned 16 bit value.
+ * @deprecated Use readValue().
+ */
+uint16_t NimBLERemoteCharacteristic::readUInt16() {
+ return readValue();
+} // readUInt16
+
+
+/**
+ * @brief Read an unsigned 32 bit value.
+ * @return the unsigned 32 bit value.
+ * @deprecated Use readValue().
+ */
+uint32_t NimBLERemoteCharacteristic::readUInt32() {
+ return readValue();
+} // readUInt32
+
+
+/**
+ * @brief Read a byte value
+ * @return The value as a byte
+ * @deprecated Use readValue().
+ */
+uint8_t NimBLERemoteCharacteristic::readUInt8() {
+ return readValue();
+} // readUInt8
+
+
+/**
+ * @brief Read a float value.
+ * @return the float value.
+ */
+float NimBLERemoteCharacteristic::readFloat() {
+ return readValue();
+} // readFloat
+
+
+/**
+ * @brief Read the value of the remote characteristic.
+ * @param [in] timestamp A pointer to a time_t struct to store the time the value was read.
+ * @return The value of the remote characteristic.
+ */
+std::string NimBLERemoteCharacteristic::readValue(time_t *timestamp) {
+ NIMBLE_LOGD(LOG_TAG, ">> readValue(): uuid: %s, handle: %d 0x%.2x",
+ getUUID().toString().c_str(), getHandle(), getHandle());
+
+ NimBLEClient* pClient = getRemoteService()->getClient();
+ std::string value;
+
+ if (!pClient->isConnected()) {
+ NIMBLE_LOGE(LOG_TAG, "Disconnected");
+ return value;
+ }
+
+ int rc = 0;
+ int retryCount = 1;
+ TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
+ ble_task_data_t taskData = {this, cur_task, 0, &value};
+
+ do {
+ rc = ble_gattc_read_long(pClient->getConnId(), m_handle, 0,
+ NimBLERemoteCharacteristic::onReadCB,
+ &taskData);
+ if (rc != 0) {
+ NIMBLE_LOGE(LOG_TAG, "Error: Failed to read characteristic; rc=%d, %s",
+ rc, NimBLEUtils::returnCodeToString(rc));
+ return value;
+ }
+
+#ifdef ulTaskNotifyValueClear
+ // Clear the task notification value to ensure we block
+ ulTaskNotifyValueClear(cur_task, ULONG_MAX);
+#endif
+ ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
+ rc = taskData.rc;
+
+ switch(rc){
+ case 0:
+ case BLE_HS_EDONE:
+ rc = 0;
+ break;
+ // Characteristic is not long-readable, return with what we have.
+ case BLE_HS_ATT_ERR(BLE_ATT_ERR_ATTR_NOT_LONG):
+ NIMBLE_LOGI(LOG_TAG, "Attribute not long");
+ rc = 0;
+ break;
+ case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHEN):
+ case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHOR):
+ case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_ENC):
+ if (retryCount && pClient->secureConnection())
+ break;
+ /* Else falls through. */
+ default:
+ NIMBLE_LOGE(LOG_TAG, "<< readValue rc=%d", rc);
+ return value;
+ }
+ } while(rc != 0 && retryCount--);
+
+ time_t t = time(nullptr);
+ ble_npl_hw_enter_critical();
+ m_value = value;
+ m_timestamp = t;
+ if(timestamp != nullptr) {
+ *timestamp = m_timestamp;
+ }
+ ble_npl_hw_exit_critical(0);
+
+ NIMBLE_LOGD(LOG_TAG, "<< readValue length: %d rc=%d", value.length(), rc);
+ return value;
+} // readValue
+
+
+/**
+ * @brief Callback for characteristic read operation.
+ * @return success == 0 or error code.
+ */
+int NimBLERemoteCharacteristic::onReadCB(uint16_t conn_handle,
+ const struct ble_gatt_error *error,
+ struct ble_gatt_attr *attr, void *arg)
+{
+ ble_task_data_t *pTaskData = (ble_task_data_t*)arg;
+ NimBLERemoteCharacteristic *characteristic = (NimBLERemoteCharacteristic*)pTaskData->pATT;
+ uint16_t conn_id = characteristic->getRemoteService()->getClient()->getConnId();
+
+ if(conn_id != conn_handle) {
+ return 0;
+ }
+
+ NIMBLE_LOGI(LOG_TAG, "Read complete; status=%d conn_handle=%d", error->status, conn_handle);
+
+ std::string *strBuf = (std::string*)pTaskData->buf;
+ int rc = error->status;
+
+ if(rc == 0) {
+ if(attr) {
+ uint16_t data_len = OS_MBUF_PKTLEN(attr->om);
+ if(((*strBuf).length() + data_len) > BLE_ATT_ATTR_MAX_LEN) {
+ rc = BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
+ } else {
+ NIMBLE_LOGD(LOG_TAG, "Got %u bytes", data_len);
+ (*strBuf) += std::string((char*) attr->om->om_data, data_len);
+ return 0;
+ }
+ }
+ }
+
+ pTaskData->rc = rc;
+ xTaskNotifyGive(pTaskData->task);
+
+ return rc;
+}
+
+
+/**
+ * @brief Subscribe or unsubscribe for notifications or indications.
+ * @param [in] val 0x00 to unsubscribe, 0x01 for notifications, 0x02 for indications.
+ * @param [in] notifyCallback A callback to be invoked for a notification.
+ * @param [in] response If write response required set this to true.
+ * If NULL is provided then no callback is performed.
+ * @return false if writing to the descriptor failed.
+ */
+bool NimBLERemoteCharacteristic::setNotify(uint16_t val, notify_callback notifyCallback, bool response) {
+ NIMBLE_LOGD(LOG_TAG, ">> setNotify(): %s, %02x", toString().c_str(), val);
+
+ m_notifyCallback = notifyCallback;
+
+ NimBLERemoteDescriptor* desc = getDescriptor(NimBLEUUID((uint16_t)0x2902));
+ if(desc == nullptr) {
+ NIMBLE_LOGW(LOG_TAG, "<< setNotify(): Callback set, CCCD not found");
+ return true;
+ }
+
+ NIMBLE_LOGD(LOG_TAG, "<< setNotify()");
+
+ return desc->writeValue((uint8_t *)&val, 2, response);
+} // setNotify
+
+
+/**
+ * @brief Subscribe for notifications or indications.
+ * @param [in] notifications If true, subscribe for notifications, false subscribe for indications.
+ * @param [in] notifyCallback A callback to be invoked for a notification.
+ * @param [in] response If true, require a write response from the descriptor write operation.
+ * If NULL is provided then no callback is performed.
+ * @return false if writing to the descriptor failed.
+ */
+bool NimBLERemoteCharacteristic::subscribe(bool notifications, notify_callback notifyCallback, bool response) {
+ if(notifications) {
+ return setNotify(0x01, notifyCallback, response);
+ } else {
+ return setNotify(0x02, notifyCallback, response);
+ }
+} // subscribe
+
+
+/**
+ * @brief Unsubscribe for notifications or indications.
+ * @param [in] response bool if true, require a write response from the descriptor write operation.
+ * @return false if writing to the descriptor failed.
+ */
+bool NimBLERemoteCharacteristic::unsubscribe(bool response) {
+ return setNotify(0x00, nullptr, response);
+} // unsubscribe
+
+
+ /**
+ * @brief backward-compatibility method for subscribe/unsubscribe notifications/indications
+ * @param [in] notifyCallback A callback to be invoked for a notification. If NULL is provided then we
+ * will unregister for notifications.
+ * @param [in] notifications If true, register for notifications, false register for indications.
+ * @param [in] response If true, require a write response from the descriptor write operation.
+ * @return true if successful.
+ * @deprecated Use subscribe() / unsubscribe() instead.
+ */
+bool NimBLERemoteCharacteristic::registerForNotify(notify_callback notifyCallback, bool notifications, bool response) {
+ bool success;
+ if(notifyCallback != nullptr) {
+ success = subscribe(notifications, notifyCallback, response);
+ } else {
+ success = unsubscribe(response);
+ }
+ return success;
+} // registerForNotify
+
+
+/**
+ * @brief Delete the descriptors in the descriptor vector.
+ * @details We maintain a vector called m_descriptorVector that contains pointers to NimBLERemoteDescriptors
+ * object references. Since we allocated these in this class, we are also responsible for deleting
+ * them. This method does just that.
+ */
+void NimBLERemoteCharacteristic::deleteDescriptors() {
+ NIMBLE_LOGD(LOG_TAG, ">> deleteDescriptors");
+
+ for(auto &it: m_descriptorVector) {
+ delete it;
+ }
+ m_descriptorVector.clear();
+ NIMBLE_LOGD(LOG_TAG, "<< deleteDescriptors");
+} // deleteDescriptors
+
+
+/**
+ * @brief Delete descriptor by UUID
+ * @param [in] uuid The UUID of the descriptor to be deleted.
+ * @return Number of descriptors left in the vector.
+ */
+size_t NimBLERemoteCharacteristic::deleteDescriptor(const NimBLEUUID &uuid) {
+ NIMBLE_LOGD(LOG_TAG, ">> deleteDescriptor");
+
+ for(auto it = m_descriptorVector.begin(); it != m_descriptorVector.end(); ++it) {
+ if((*it)->getUUID() == uuid) {
+ delete *it;
+ m_descriptorVector.erase(it);
+ break;
+ }
+ }
+
+ NIMBLE_LOGD(LOG_TAG, "<< deleteDescriptor");
+
+ return m_descriptorVector.size();
+} // deleteDescriptor
+
+
+/**
+ * @brief Convert a NimBLERemoteCharacteristic to a string representation;
+ * @return a String representation.
+ */
+std::string NimBLERemoteCharacteristic::toString() {
+ std::string res = "Characteristic: uuid: " + m_uuid.toString();
+ char val[6];
+ res += ", handle: ";
+ snprintf(val, sizeof(val), "%d", getHandle());
+ res += val;
+ res += " 0x";
+ snprintf(val, sizeof(val), "%04x", getHandle());
+ res += val;
+ res += ", props: ";
+ res += " 0x";
+ snprintf(val, sizeof(val), "%02x", m_charProp);
+ res += val;
+
+ for(auto &it: m_descriptorVector) {
+ res += "\n" + it->toString();
+ }
+
+ return res;
+} // toString
+
+
+/**
+ * @brief Write the new value for the characteristic.
+ * @param [in] newValue The new value to write.
+ * @param [in] response Do we expect a response?
+ * @return false if not connected or cant perform write for some reason.
+ */
+bool NimBLERemoteCharacteristic::writeValue(const std::string &newValue, bool response) {
+ return writeValue((uint8_t*)newValue.c_str(), newValue.length(), response);
+} // writeValue
+
+
+/**
+ * @brief Write the new value for the characteristic from a data buffer.
+ * @param [in] data A pointer to a data buffer.
+ * @param [in] length The length of the data in the data buffer.
+ * @param [in] response Whether we require a response from the write.
+ * @return false if not connected or cant perform write for some reason.
+ */
+bool NimBLERemoteCharacteristic::writeValue(const uint8_t* data, size_t length, bool response) {
+
+ NIMBLE_LOGD(LOG_TAG, ">> writeValue(), length: %d", length);
+
+ NimBLEClient* pClient = getRemoteService()->getClient();
+
+ if (!pClient->isConnected()) {
+ NIMBLE_LOGE(LOG_TAG, "Disconnected");
+ return false;
+ }
+
+ int rc = 0;
+ int retryCount = 1;
+ uint16_t mtu = ble_att_mtu(pClient->getConnId()) - 3;
+
+ // Check if the data length is longer than we can write in one connection event.
+ // If so we must do a long write which requires a response.
+ if(length <= mtu && !response) {
+ rc = ble_gattc_write_no_rsp_flat(pClient->getConnId(), m_handle, data, length);
+ return (rc==0);
+ }
+
+ TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
+ ble_task_data_t taskData = {this, cur_task, 0, nullptr};
+
+ do {
+ if(length > mtu) {
+ NIMBLE_LOGI(LOG_TAG,"long write %d bytes", length);
+ os_mbuf *om = ble_hs_mbuf_from_flat(data, length);
+ rc = ble_gattc_write_long(pClient->getConnId(), m_handle, 0, om,
+ NimBLERemoteCharacteristic::onWriteCB,
+ &taskData);
+ } else {
+ rc = ble_gattc_write_flat(pClient->getConnId(), m_handle,
+ data, length,
+ NimBLERemoteCharacteristic::onWriteCB,
+ &taskData);
+ }
+ if (rc != 0) {
+ NIMBLE_LOGE(LOG_TAG, "Error: Failed to write characteristic; rc=%d", rc);
+ return false;
+ }
+
+#ifdef ulTaskNotifyValueClear
+ // Clear the task notification value to ensure we block
+ ulTaskNotifyValueClear(cur_task, ULONG_MAX);
+#endif
+ ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
+ rc = taskData.rc;
+
+ switch(rc){
+ case 0:
+ case BLE_HS_EDONE:
+ rc = 0;
+ break;
+ case BLE_HS_ATT_ERR(BLE_ATT_ERR_ATTR_NOT_LONG):
+ NIMBLE_LOGE(LOG_TAG, "Long write not supported by peer; Truncating length to %d", mtu);
+ retryCount++;
+ length = mtu;
+ break;
+
+ case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHEN):
+ case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHOR):
+ case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_ENC):
+ if (retryCount && pClient->secureConnection())
+ break;
+ /* Else falls through. */
+ default:
+ NIMBLE_LOGE(LOG_TAG, "<< writeValue, rc: %d", rc);
+ return false;
+ }
+ } while(rc != 0 && retryCount--);
+
+ NIMBLE_LOGD(LOG_TAG, "<< writeValue, rc: %d", rc);
+ return (rc == 0);
+} // writeValue
+
+
+/**
+ * @brief Callback for characteristic write operation.
+ * @return success == 0 or error code.
+ */
+int NimBLERemoteCharacteristic::onWriteCB(uint16_t conn_handle,
+ const struct ble_gatt_error *error,
+ struct ble_gatt_attr *attr, void *arg)
+{
+ ble_task_data_t *pTaskData = (ble_task_data_t*)arg;
+ NimBLERemoteCharacteristic *characteristic = (NimBLERemoteCharacteristic*)pTaskData->pATT;
+
+ if(characteristic->getRemoteService()->getClient()->getConnId() != conn_handle){
+ return 0;
+ }
+
+ NIMBLE_LOGI(LOG_TAG, "Write complete; status=%d conn_handle=%d", error->status, conn_handle);
+
+ pTaskData->rc = error->status;
+ xTaskNotifyGive(pTaskData->task);
+
+ return 0;
+}
+
+#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/NimBLERemoteCharacteristic.h b/src/components/esp-nimble-cpp-1.3.3/src/NimBLERemoteCharacteristic.h
new file mode 100644
index 0000000..41ae816
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/NimBLERemoteCharacteristic.h
@@ -0,0 +1,168 @@
+/*
+ * NimBLERemoteCharacteristic.h
+ *
+ * Created: on Jan 27 2020
+ * Author H2zero
+ *
+ * Originally:
+ *
+ * BLERemoteCharacteristic.h
+ *
+ * Created on: Jul 8, 2017
+ * Author: kolban
+ */
+
+#ifndef COMPONENTS_NIMBLEREMOTECHARACTERISTIC_H_
+#define COMPONENTS_NIMBLEREMOTECHARACTERISTIC_H_
+
+#include "nimconfig.h"
+#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
+
+#include "NimBLERemoteService.h"
+#include "NimBLERemoteDescriptor.h"
+
+#include
+#include
+
+class NimBLERemoteService;
+class NimBLERemoteDescriptor;
+
+
+typedef std::function notify_callback;
+
+typedef struct {
+ const NimBLEUUID *uuid;
+ void *task_data;
+} desc_filter_t;
+
+
+/**
+ * @brief A model of a remote %BLE characteristic.
+ */
+class NimBLERemoteCharacteristic {
+public:
+ ~NimBLERemoteCharacteristic();
+
+ // Public member functions
+ bool canBroadcast();
+ bool canIndicate();
+ bool canNotify();
+ bool canRead();
+ bool canWrite();
+ bool canWriteNoResponse();
+ std::vector::iterator begin();
+ std::vector::iterator end();
+ NimBLERemoteDescriptor* getDescriptor(const NimBLEUUID &uuid);
+ std::vector* getDescriptors(bool refresh = false);
+ void deleteDescriptors();
+ size_t deleteDescriptor(const NimBLEUUID &uuid);
+ uint16_t getHandle();
+ uint16_t getDefHandle();
+ NimBLEUUID getUUID();
+ std::string readValue(time_t *timestamp = nullptr);
+
+ /**
+ * @brief A template to convert the remote characteristic data to .
+ * @tparam T The type to convert the data to.
+ * @param [in] timestamp A pointer to a time_t struct to store the time the value was read.
+ * @param [in] skipSizeCheck If true it will skip checking if the data size is less than sizeof() .
+ * @return The data converted to or NULL if skipSizeCheck is false and the data is
+ * less than sizeof() .
+ * @details Use: readValue(×tamp, skipSizeCheck);
+ */
+ template
+ T readValue(time_t *timestamp = nullptr, bool skipSizeCheck = false) {
+ std::string value = readValue(timestamp);
+ if(!skipSizeCheck && value.size() < sizeof(T)) return T();
+ const char *pData = value.data();
+ return *((T *)pData);
+ }
+
+ uint8_t readUInt8() __attribute__ ((deprecated("Use template readValue()")));
+ uint16_t readUInt16() __attribute__ ((deprecated("Use template readValue()")));
+ uint32_t readUInt32() __attribute__ ((deprecated("Use template readValue()")));
+ float readFloat() __attribute__ ((deprecated("Use template readValue()")));
+ std::string getValue(time_t *timestamp = nullptr);
+
+ /**
+ * @brief A template to convert the remote characteristic data to .
+ * @tparam T The type to convert the data to.
+ * @param [in] timestamp A pointer to a time_t struct to store the time the value was read.
+ * @param [in] skipSizeCheck If true it will skip checking if the data size is less than sizeof() .
+ * @return The data converted to or NULL if skipSizeCheck is false and the data is
+ * less than sizeof() .
+ * @details Use: getValue(×tamp, skipSizeCheck);
+ */
+ template
+ T getValue(time_t *timestamp = nullptr, bool skipSizeCheck = false) {
+ std::string value = getValue(timestamp);
+ if(!skipSizeCheck && value.size() < sizeof(T)) return T();
+ const char *pData = value.data();
+ return *((T *)pData);
+ }
+
+ bool subscribe(bool notifications = true,
+ notify_callback notifyCallback = nullptr,
+ bool response = false);
+ bool unsubscribe(bool response = false);
+ bool registerForNotify(notify_callback notifyCallback,
+ bool notifications = true,
+ bool response = true)
+ __attribute__ ((deprecated("Use subscribe()/unsubscribe()")));
+ bool writeValue(const uint8_t* data,
+ size_t length,
+ bool response = false);
+ bool writeValue(const std::string &newValue,
+ bool response = false);
+ /**
+ * @brief Convenience template to set the remote characteristic value to val.
+ * @param [in] s The value to write.
+ * @param [in] response True == request write response.
+ */
+ template
+ bool writeValue(const T &s, bool response = false) {
+ return writeValue((uint8_t*)&s, sizeof(T), response);
+ }
+
+ std::string toString();
+ NimBLERemoteService* getRemoteService();
+
+private:
+
+ NimBLERemoteCharacteristic(NimBLERemoteService *pRemoteservice, const struct ble_gatt_chr *chr);
+
+ friend class NimBLEClient;
+ friend class NimBLERemoteService;
+ friend class NimBLERemoteDescriptor;
+
+ // Private member functions
+ bool setNotify(uint16_t val, notify_callback notifyCallback = nullptr, bool response = true);
+ bool retrieveDescriptors(const NimBLEUUID *uuid_filter = nullptr);
+ static int onReadCB(uint16_t conn_handle, const struct ble_gatt_error *error,
+ struct ble_gatt_attr *attr, void *arg);
+ static int onWriteCB(uint16_t conn_handle, const struct ble_gatt_error *error,
+ struct ble_gatt_attr *attr, void *arg);
+ static int descriptorDiscCB(uint16_t conn_handle, const struct ble_gatt_error *error,
+ uint16_t chr_val_handle, const struct ble_gatt_dsc *dsc,
+ void *arg);
+ static int nextCharCB(uint16_t conn_handle, const struct ble_gatt_error *error,
+ const struct ble_gatt_chr *chr, void *arg);
+
+ // Private properties
+ NimBLEUUID m_uuid;
+ uint8_t m_charProp;
+ uint16_t m_handle;
+ uint16_t m_defHandle;
+ uint16_t m_endHandle;
+ NimBLERemoteService* m_pRemoteService;
+ std::string m_value;
+ notify_callback m_notifyCallback;
+ time_t m_timestamp;
+
+ // We maintain a vector of descriptors owned by this characteristic.
+ std::vector m_descriptorVector;
+}; // NimBLERemoteCharacteristic
+
+#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
+#endif /* COMPONENTS_NIMBLEREMOTECHARACTERISTIC_H_ */
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/NimBLERemoteDescriptor.cpp b/src/components/esp-nimble-cpp-1.3.3/src/NimBLERemoteDescriptor.cpp
new file mode 100644
index 0000000..64ce06d
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/NimBLERemoteDescriptor.cpp
@@ -0,0 +1,365 @@
+/*
+ * NimBLERemoteDescriptor.cpp
+ *
+ * Created: on Jan 27 2020
+ * Author H2zero
+ *
+ * Originally:
+ *
+ * BLERemoteDescriptor.cpp
+ *
+ * Created on: Jul 8, 2017
+ * Author: kolban
+ */
+
+#include "nimconfig.h"
+#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
+
+#include "NimBLERemoteDescriptor.h"
+#include "NimBLEUtils.h"
+#include "NimBLELog.h"
+
+#include
+
+static const char* LOG_TAG = "NimBLERemoteDescriptor";
+
+/**
+ * @brief Remote descriptor constructor.
+ * @param [in] pRemoteCharacteristic A pointer to the Characteristic that this belongs to.
+ * @param [in] dsc A pointer to the struct that contains the descriptor information.
+ */
+NimBLERemoteDescriptor::NimBLERemoteDescriptor(NimBLERemoteCharacteristic* pRemoteCharacteristic,
+ const struct ble_gatt_dsc *dsc)
+{
+ NIMBLE_LOGD(LOG_TAG, ">> NimBLERemoteDescriptor()");
+ switch (dsc->uuid.u.type) {
+ case BLE_UUID_TYPE_16:
+ m_uuid = NimBLEUUID(dsc->uuid.u16.value);
+ break;
+ case BLE_UUID_TYPE_32:
+ m_uuid = NimBLEUUID(dsc->uuid.u32.value);
+ break;
+ case BLE_UUID_TYPE_128:
+ m_uuid = NimBLEUUID(const_cast(&dsc->uuid.u128));
+ break;
+ default:
+ break;
+ }
+
+ m_handle = dsc->handle;
+ m_pRemoteCharacteristic = pRemoteCharacteristic;
+
+ NIMBLE_LOGD(LOG_TAG, "<< NimBLERemoteDescriptor(): %s", m_uuid.toString().c_str());
+}
+
+
+/**
+ * @brief Retrieve the handle associated with this remote descriptor.
+ * @return The handle associated with this remote descriptor.
+ */
+uint16_t NimBLERemoteDescriptor::getHandle() {
+ return m_handle;
+} // getHandle
+
+
+/**
+ * @brief Get the characteristic that owns this descriptor.
+ * @return The characteristic that owns this descriptor.
+ */
+NimBLERemoteCharacteristic* NimBLERemoteDescriptor::getRemoteCharacteristic() {
+ return m_pRemoteCharacteristic;
+} // getRemoteCharacteristic
+
+
+/**
+ * @brief Retrieve the UUID associated this remote descriptor.
+ * @return The UUID associated this remote descriptor.
+ */
+NimBLEUUID NimBLERemoteDescriptor::getUUID() {
+ return m_uuid;
+} // getUUID
+
+
+/**
+ * @brief Read a byte value
+ * @return The value as a byte
+ * @deprecated Use readValue().
+ */
+uint8_t NimBLERemoteDescriptor::readUInt8() {
+ std::string value = readValue();
+ if (value.length() >= 1) {
+ return (uint8_t) value[0];
+ }
+ return 0;
+} // readUInt8
+
+
+/**
+ * @brief Read an unsigned 16 bit value
+ * @return The unsigned 16 bit value.
+ * @deprecated Use readValue().
+ */
+uint16_t NimBLERemoteDescriptor::readUInt16() {
+ std::string value = readValue();
+ if (value.length() >= 2) {
+ return *(uint16_t*) value.data();
+ }
+ return 0;
+} // readUInt16
+
+
+/**
+ * @brief Read an unsigned 32 bit value.
+ * @return the unsigned 32 bit value.
+ * @deprecated Use readValue().
+ */
+uint32_t NimBLERemoteDescriptor::readUInt32() {
+ std::string value = readValue();
+ if (value.length() >= 4) {
+ return *(uint32_t*) value.data();
+ }
+ return 0;
+} // readUInt32
+
+
+/**
+ * @brief Read the value of the remote descriptor.
+ * @return The value of the remote descriptor.
+ */
+std::string NimBLERemoteDescriptor::readValue() {
+ NIMBLE_LOGD(LOG_TAG, ">> Descriptor readValue: %s", toString().c_str());
+
+ NimBLEClient* pClient = getRemoteCharacteristic()->getRemoteService()->getClient();
+ std::string value;
+
+ if (!pClient->isConnected()) {
+ NIMBLE_LOGE(LOG_TAG, "Disconnected");
+ return value;
+ }
+
+ int rc = 0;
+ int retryCount = 1;
+ TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
+ ble_task_data_t taskData = {this, cur_task, 0, &value};
+
+ do {
+ rc = ble_gattc_read_long(pClient->getConnId(), m_handle, 0,
+ NimBLERemoteDescriptor::onReadCB,
+ &taskData);
+ if (rc != 0) {
+ NIMBLE_LOGE(LOG_TAG, "Error: Failed to read descriptor; rc=%d, %s",
+ rc, NimBLEUtils::returnCodeToString(rc));
+ return value;
+ }
+
+#ifdef ulTaskNotifyValueClear
+ // Clear the task notification value to ensure we block
+ ulTaskNotifyValueClear(cur_task, ULONG_MAX);
+#endif
+ ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
+ rc = taskData.rc;
+
+ switch(rc){
+ case 0:
+ case BLE_HS_EDONE:
+ rc = 0;
+ break;
+ // Descriptor is not long-readable, return with what we have.
+ case BLE_HS_ATT_ERR(BLE_ATT_ERR_ATTR_NOT_LONG):
+ NIMBLE_LOGI(LOG_TAG, "Attribute not long");
+ rc = 0;
+ break;
+ case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHEN):
+ case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHOR):
+ case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_ENC):
+ if (retryCount && pClient->secureConnection())
+ break;
+ /* Else falls through. */
+ default:
+ return value;
+ }
+ } while(rc != 0 && retryCount--);
+
+ NIMBLE_LOGD(LOG_TAG, "<< Descriptor readValue(): length: %u rc=%d", value.length(), rc);
+ return value;
+} // readValue
+
+
+/**
+ * @brief Callback for Descriptor read operation.
+ * @return success == 0 or error code.
+ */
+int NimBLERemoteDescriptor::onReadCB(uint16_t conn_handle,
+ const struct ble_gatt_error *error,
+ struct ble_gatt_attr *attr, void *arg)
+{
+ (void)attr;
+ ble_task_data_t *pTaskData = (ble_task_data_t*)arg;
+ NimBLERemoteDescriptor* desc = (NimBLERemoteDescriptor*)pTaskData->pATT;
+ uint16_t conn_id = desc->getRemoteCharacteristic()->getRemoteService()->getClient()->getConnId();
+
+ if(conn_id != conn_handle){
+ return 0;
+ }
+
+ NIMBLE_LOGD(LOG_TAG, "Read complete; status=%d conn_handle=%d", error->status, conn_handle);
+
+ std::string *strBuf = (std::string*)pTaskData->buf;
+ int rc = error->status;
+
+ if(rc == 0) {
+ if(attr) {
+ uint16_t data_len = OS_MBUF_PKTLEN(attr->om);
+ if(((*strBuf).length() + data_len) > BLE_ATT_ATTR_MAX_LEN) {
+ rc = BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
+ } else {
+ NIMBLE_LOGD(LOG_TAG, "Got %u bytes", data_len);
+ (*strBuf) += std::string((char*) attr->om->om_data, data_len);
+ return 0;
+ }
+ }
+ }
+
+ pTaskData->rc = rc;
+ xTaskNotifyGive(pTaskData->task);
+
+ return rc;
+}
+
+
+/**
+ * @brief Return a string representation of this Remote Descriptor.
+ * @return A string representation of this Remote Descriptor.
+ */
+std::string NimBLERemoteDescriptor::toString() {
+ std::string res = "Descriptor: uuid: " + getUUID().toString();
+ char val[6];
+ res += ", handle: ";
+ snprintf(val, sizeof(val), "%d", getHandle());
+ res += val;
+
+ return res;
+} // toString
+
+
+/**
+ * @brief Callback for descriptor write operation.
+ * @return success == 0 or error code.
+ */
+int NimBLERemoteDescriptor::onWriteCB(uint16_t conn_handle,
+ const struct ble_gatt_error *error,
+ struct ble_gatt_attr *attr, void *arg)
+{
+ ble_task_data_t *pTaskData = (ble_task_data_t*)arg;
+ NimBLERemoteDescriptor* descriptor = (NimBLERemoteDescriptor*)pTaskData->pATT;
+
+ if(descriptor->getRemoteCharacteristic()->getRemoteService()->getClient()->getConnId() != conn_handle){
+ return 0;
+ }
+
+ NIMBLE_LOGI(LOG_TAG, "Write complete; status=%d conn_handle=%d", error->status, conn_handle);
+
+ pTaskData->rc = error->status;
+ xTaskNotifyGive(pTaskData->task);
+
+ return 0;
+}
+
+
+/**
+ * @brief Write data to the BLE Remote Descriptor.
+ * @param [in] data The data to send to the remote descriptor.
+ * @param [in] length The length of the data to send.
+ * @param [in] response True if we expect a write response.
+ * @return True if successful
+ */
+bool NimBLERemoteDescriptor::writeValue(const uint8_t* data, size_t length, bool response) {
+
+ NIMBLE_LOGD(LOG_TAG, ">> Descriptor writeValue: %s", toString().c_str());
+
+ NimBLEClient* pClient = getRemoteCharacteristic()->getRemoteService()->getClient();
+
+ // Check to see that we are connected.
+ if (!pClient->isConnected()) {
+ NIMBLE_LOGE(LOG_TAG, "Disconnected");
+ return false;
+ }
+
+ int rc = 0;
+ int retryCount = 1;
+ uint16_t mtu = ble_att_mtu(pClient->getConnId()) - 3;
+
+ // Check if the data length is longer than we can write in 1 connection event.
+ // If so we must do a long write which requires a response.
+ if(length <= mtu && !response) {
+ rc = ble_gattc_write_no_rsp_flat(pClient->getConnId(), m_handle, data, length);
+ return (rc == 0);
+ }
+
+ TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
+ ble_task_data_t taskData = {this, cur_task, 0, nullptr};
+
+ do {
+ if(length > mtu) {
+ NIMBLE_LOGI(LOG_TAG,"long write %d bytes", length);
+ os_mbuf *om = ble_hs_mbuf_from_flat(data, length);
+ rc = ble_gattc_write_long(pClient->getConnId(), m_handle, 0, om,
+ NimBLERemoteDescriptor::onWriteCB,
+ &taskData);
+ } else {
+ rc = ble_gattc_write_flat(pClient->getConnId(), m_handle,
+ data, length,
+ NimBLERemoteDescriptor::onWriteCB,
+ &taskData);
+ }
+
+ if (rc != 0) {
+ NIMBLE_LOGE(LOG_TAG, "Error: Failed to write descriptor; rc=%d", rc);
+ return false;
+ }
+
+#ifdef ulTaskNotifyValueClear
+ // Clear the task notification value to ensure we block
+ ulTaskNotifyValueClear(cur_task, ULONG_MAX);
+#endif
+ ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
+ rc = taskData.rc;
+
+ switch(rc) {
+ case 0:
+ case BLE_HS_EDONE:
+ rc = 0;
+ break;
+ case BLE_HS_ATT_ERR(BLE_ATT_ERR_ATTR_NOT_LONG):
+ NIMBLE_LOGE(LOG_TAG, "Long write not supported by peer; Truncating length to %d", mtu);
+ retryCount++;
+ length = mtu;
+ break;
+
+ case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHEN):
+ case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHOR):
+ case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_ENC):
+ if (retryCount && pClient->secureConnection())
+ break;
+ /* Else falls through. */
+ default:
+ return false;
+ }
+ } while(rc != 0 && retryCount--);
+
+ NIMBLE_LOGD(LOG_TAG, "<< Descriptor writeValue, rc: %d",rc);
+ return (rc == 0);
+} // writeValue
+
+
+/**
+ * @brief Write data represented as a string to the BLE Remote Descriptor.
+ * @param [in] newValue The data to send to the remote descriptor.
+ * @param [in] response True if we expect a response.
+ * @return True if successful
+ */
+bool NimBLERemoteDescriptor::writeValue(const std::string &newValue, bool response) {
+ return writeValue((uint8_t*) newValue.data(), newValue.length(), response);
+} // writeValue
+
+#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/NimBLERemoteDescriptor.h b/src/components/esp-nimble-cpp-1.3.3/src/NimBLERemoteDescriptor.h
new file mode 100644
index 0000000..13e8351
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/NimBLERemoteDescriptor.h
@@ -0,0 +1,83 @@
+/*
+ * NimBLERemoteDescriptor.h
+ *
+ * Created: on Jan 27 2020
+ * Author H2zero
+ *
+ * Originally:
+ *
+ * BLERemoteDescriptor.h
+ *
+ * Created on: Jul 8, 2017
+ * Author: kolban
+ */
+
+#ifndef COMPONENTS_NIMBLEREMOTEDESCRIPTOR_H_
+#define COMPONENTS_NIMBLEREMOTEDESCRIPTOR_H_
+
+#include "nimconfig.h"
+#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
+
+#include "NimBLERemoteCharacteristic.h"
+
+class NimBLERemoteCharacteristic;
+/**
+ * @brief A model of remote %BLE descriptor.
+ */
+class NimBLERemoteDescriptor {
+public:
+ uint16_t getHandle();
+ NimBLERemoteCharacteristic* getRemoteCharacteristic();
+ NimBLEUUID getUUID();
+ std::string readValue();
+
+ /**
+ * @brief A template to convert the remote descriptor data to .
+ * @tparam T The type to convert the data to.
+ * @param [in] skipSizeCheck If true it will skip checking if the data size is less than sizeof() .
+ * @return The data converted to or NULL if skipSizeCheck is false and the data is
+ * less than sizeof() .
+ * @details Use: readValue(skipSizeCheck);
+ */
+ template
+ T readValue(bool skipSizeCheck = false) {
+ std::string value = readValue();
+ if(!skipSizeCheck && value.size() < sizeof(T)) return T();
+ const char *pData = value.data();
+ return *((T *)pData);
+ }
+
+ uint8_t readUInt8() __attribute__ ((deprecated("Use template readValue()")));
+ uint16_t readUInt16() __attribute__ ((deprecated("Use template readValue()")));
+ uint32_t readUInt32() __attribute__ ((deprecated("Use template readValue()")));
+ std::string toString(void);
+ bool writeValue(const uint8_t* data, size_t length, bool response = false);
+ bool writeValue(const std::string &newValue, bool response = false);
+
+ /**
+ * @brief Convenience template to set the remote descriptor value to val.
+ * @param [in] s The value to write.
+ * @param [in] response True == request write response.
+ */
+ template
+ bool writeValue(const T &s, bool response = false) {
+ return writeValue((uint8_t*)&s, sizeof(T), response);
+ }
+
+private:
+ friend class NimBLERemoteCharacteristic;
+
+ NimBLERemoteDescriptor (NimBLERemoteCharacteristic* pRemoteCharacteristic,
+ const struct ble_gatt_dsc *dsc);
+ static int onWriteCB(uint16_t conn_handle, const struct ble_gatt_error *error,
+ struct ble_gatt_attr *attr, void *arg);
+ static int onReadCB(uint16_t conn_handle, const struct ble_gatt_error *error,
+ struct ble_gatt_attr *attr, void *arg);
+
+ uint16_t m_handle;
+ NimBLEUUID m_uuid;
+ NimBLERemoteCharacteristic* m_pRemoteCharacteristic;
+};
+
+#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
+#endif /* COMPONENTS_NIMBLEREMOTEDESCRIPTOR_H_ */
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/NimBLERemoteService.cpp b/src/components/esp-nimble-cpp-1.3.3/src/NimBLERemoteService.cpp
new file mode 100644
index 0000000..cd3d528
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/NimBLERemoteService.cpp
@@ -0,0 +1,411 @@
+/*
+ * NimBLERemoteService.cpp
+ *
+ * Created: on Jan 27 2020
+ * Author H2zero
+ *
+ * Originally:
+ *
+ * BLERemoteService.cpp
+ *
+ * Created on: Jul 8, 2017
+ * Author: kolban
+ */
+
+#include "nimconfig.h"
+#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
+
+#include "NimBLERemoteService.h"
+#include "NimBLEUtils.h"
+#include "NimBLEDevice.h"
+#include "NimBLELog.h"
+
+#include
+
+static const char* LOG_TAG = "NimBLERemoteService";
+
+/**
+ * @brief Remote Service constructor.
+ * @param [in] pClient A pointer to the client this belongs to.
+ * @param [in] service A pointer to the structure with the service information.
+ */
+NimBLERemoteService::NimBLERemoteService(NimBLEClient* pClient, const struct ble_gatt_svc* service) {
+
+ NIMBLE_LOGD(LOG_TAG, ">> NimBLERemoteService()");
+ m_pClient = pClient;
+ switch (service->uuid.u.type) {
+ case BLE_UUID_TYPE_16:
+ m_uuid = NimBLEUUID(service->uuid.u16.value);
+ break;
+ case BLE_UUID_TYPE_32:
+ m_uuid = NimBLEUUID(service->uuid.u32.value);
+ break;
+ case BLE_UUID_TYPE_128:
+ m_uuid = NimBLEUUID(const_cast(&service->uuid.u128));
+ break;
+ default:
+ break;
+ }
+ m_startHandle = service->start_handle;
+ m_endHandle = service->end_handle;
+ NIMBLE_LOGD(LOG_TAG, "<< NimBLERemoteService(): %s", m_uuid.toString().c_str());
+}
+
+
+/**
+ * @brief When deleting the service make sure we delete all characteristics and descriptors.
+ */
+NimBLERemoteService::~NimBLERemoteService() {
+ deleteCharacteristics();
+}
+
+
+/**
+ * @brief Get iterator to the beginning of the vector of remote characteristic pointers.
+ * @return An iterator to the beginning of the vector of remote characteristic pointers.
+ */
+std::vector::iterator NimBLERemoteService::begin() {
+ return m_characteristicVector.begin();
+}
+
+
+/**
+ * @brief Get iterator to the end of the vector of remote characteristic pointers.
+ * @return An iterator to the end of the vector of remote characteristic pointers.
+ */
+std::vector::iterator NimBLERemoteService::end() {
+ return m_characteristicVector.end();
+}
+
+
+/**
+ * @brief Get the remote characteristic object for the characteristic UUID.
+ * @param [in] uuid Remote characteristic uuid.
+ * @return A pointer to the remote characteristic object.
+ */
+NimBLERemoteCharacteristic* NimBLERemoteService::getCharacteristic(const char* uuid) {
+ return getCharacteristic(NimBLEUUID(uuid));
+} // getCharacteristic
+
+
+/**
+ * @brief Get the characteristic object for the UUID.
+ * @param [in] uuid Characteristic uuid.
+ * @return A pointer to the characteristic object, or nullptr if not found.
+ */
+NimBLERemoteCharacteristic* NimBLERemoteService::getCharacteristic(const NimBLEUUID &uuid) {
+ NIMBLE_LOGD(LOG_TAG, ">> getCharacteristic: uuid: %s", uuid.toString().c_str());
+
+ for(auto &it: m_characteristicVector) {
+ if(it->getUUID() == uuid) {
+ NIMBLE_LOGD(LOG_TAG, "<< getCharacteristic: found the characteristic with uuid: %s", uuid.toString().c_str());
+ return it;
+ }
+ }
+
+ size_t prev_size = m_characteristicVector.size();
+ if(retrieveCharacteristics(&uuid)) {
+ if(m_characteristicVector.size() > prev_size) {
+ return m_characteristicVector.back();
+ }
+
+ // If the request was successful but 16/32 bit uuid not found
+ // try again with the 128 bit uuid.
+ if(uuid.bitSize() == BLE_UUID_TYPE_16 ||
+ uuid.bitSize() == BLE_UUID_TYPE_32)
+ {
+ NimBLEUUID uuid128(uuid);
+ uuid128.to128();
+ if (retrieveCharacteristics(&uuid128)) {
+ if(m_characteristicVector.size() > prev_size) {
+ return m_characteristicVector.back();
+ }
+ }
+ } else {
+ // If the request was successful but the 128 bit uuid not found
+ // try again with the 16 bit uuid.
+ NimBLEUUID uuid16(uuid);
+ uuid16.to16();
+ // if the uuid was 128 bit but not of the BLE base type this check will fail
+ if (uuid16.bitSize() == BLE_UUID_TYPE_16) {
+ if(retrieveCharacteristics(&uuid16)) {
+ if(m_characteristicVector.size() > prev_size) {
+ return m_characteristicVector.back();
+ }
+ }
+ }
+ }
+ }
+
+ NIMBLE_LOGD(LOG_TAG, "<< getCharacteristic: not found");
+ return nullptr;
+} // getCharacteristic
+
+
+/**
+ * @brief Get a pointer to the vector of found characteristics.
+ * @param [in] refresh If true the current characteristics vector will cleared and
+ * all characteristics for this service retrieved from the peripheral.
+ * If false the vector will be returned with the currently stored characteristics of this service.
+ * @return A pointer to the vector of descriptors for this characteristic.
+ */
+std::vector* NimBLERemoteService::getCharacteristics(bool refresh) {
+ if(refresh) {
+ deleteCharacteristics();
+
+ if (!retrieveCharacteristics()) {
+ NIMBLE_LOGE(LOG_TAG, "Error: Failed to get characteristics");
+ }
+ else{
+ NIMBLE_LOGI(LOG_TAG, "Found %d characteristics", m_characteristicVector.size());
+ }
+ }
+ return &m_characteristicVector;
+} // getCharacteristics
+
+
+/**
+ * @brief Callback for Characterisic discovery.
+ * @return success == 0 or error code.
+ */
+int NimBLERemoteService::characteristicDiscCB(uint16_t conn_handle,
+ const struct ble_gatt_error *error,
+ const struct ble_gatt_chr *chr, void *arg)
+{
+ NIMBLE_LOGD(LOG_TAG,"Characteristic Discovered >> status: %d handle: %d",
+ error->status, (error->status == 0) ? chr->val_handle : -1);
+
+ ble_task_data_t *pTaskData = (ble_task_data_t*)arg;
+ NimBLERemoteService *service = (NimBLERemoteService*)pTaskData->pATT;
+
+ // Make sure the discovery is for this device
+ if(service->getClient()->getConnId() != conn_handle){
+ return 0;
+ }
+
+ if(error->status == 0) {
+ // Found a service - add it to the vector
+ NimBLERemoteCharacteristic* pRemoteCharacteristic = new NimBLERemoteCharacteristic(service, chr);
+ service->m_characteristicVector.push_back(pRemoteCharacteristic);
+ return 0;
+ }
+
+ if(error->status == BLE_HS_EDONE) {
+ pTaskData->rc = 0;
+ } else {
+ NIMBLE_LOGE(LOG_TAG, "characteristicDiscCB() rc=%d %s",
+ error->status,
+ NimBLEUtils::returnCodeToString(error->status));
+ pTaskData->rc = error->status;
+ }
+
+ xTaskNotifyGive(pTaskData->task);
+
+ NIMBLE_LOGD(LOG_TAG,"<< Characteristic Discovered");
+ return error->status;
+}
+
+
+/**
+ * @brief Retrieve all the characteristics for this service.
+ * This function will not return until we have all the characteristics.
+ * @return True if successful.
+ */
+bool NimBLERemoteService::retrieveCharacteristics(const NimBLEUUID *uuid_filter) {
+ NIMBLE_LOGD(LOG_TAG, ">> retrieveCharacteristics() for service: %s", getUUID().toString().c_str());
+
+ int rc = 0;
+ TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
+ ble_task_data_t taskData = {this, cur_task, 0, nullptr};
+
+ if(uuid_filter == nullptr) {
+ rc = ble_gattc_disc_all_chrs(m_pClient->getConnId(),
+ m_startHandle,
+ m_endHandle,
+ NimBLERemoteService::characteristicDiscCB,
+ &taskData);
+ } else {
+ rc = ble_gattc_disc_chrs_by_uuid(m_pClient->getConnId(),
+ m_startHandle,
+ m_endHandle,
+ &uuid_filter->getNative()->u,
+ NimBLERemoteService::characteristicDiscCB,
+ &taskData);
+ }
+
+ if (rc != 0) {
+ NIMBLE_LOGE(LOG_TAG, "ble_gattc_disc_all_chrs: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
+ return false;
+ }
+
+#ifdef ulTaskNotifyValueClear
+ // Clear the task notification value to ensure we block
+ ulTaskNotifyValueClear(cur_task, ULONG_MAX);
+#endif
+ ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
+
+ if(taskData.rc == 0){
+ if (uuid_filter == nullptr) {
+ if (m_characteristicVector.size() > 1) {
+ for (auto it = m_characteristicVector.begin(); it != m_characteristicVector.end(); ++it ) {
+ auto nx = std::next(it, 1);
+ if (nx == m_characteristicVector.end()) {
+ break;
+ }
+ (*it)->m_endHandle = (*nx)->m_defHandle - 1;
+ }
+ }
+
+ m_characteristicVector.back()->m_endHandle = getEndHandle();
+ }
+
+ NIMBLE_LOGD(LOG_TAG, "<< retrieveCharacteristics()");
+ return true;
+ }
+
+ NIMBLE_LOGE(LOG_TAG, "Could not retrieve characteristics");
+ return false;
+
+} // retrieveCharacteristics
+
+
+/**
+ * @brief Get the client associated with this service.
+ * @return A reference to the client associated with this service.
+ */
+NimBLEClient* NimBLERemoteService::getClient() {
+ return m_pClient;
+} // getClient
+
+
+/**
+ * @brief Get the service end handle.
+ */
+uint16_t NimBLERemoteService::getEndHandle() {
+ return m_endHandle;
+} // getEndHandle
+
+
+/**
+ * @brief Get the service start handle.
+ */
+uint16_t NimBLERemoteService::getStartHandle() {
+ return m_startHandle;
+} // getStartHandle
+
+
+/**
+ * @brief Get the service UUID.
+ */
+NimBLEUUID NimBLERemoteService::getUUID() {
+ return m_uuid;
+}
+
+
+/**
+ * @brief Read the value of a characteristic associated with this service.
+ * @param [in] characteristicUuid The characteristic to read.
+ * @returns a string containing the value or an empty string if not found or error.
+ */
+std::string NimBLERemoteService::getValue(const NimBLEUUID &characteristicUuid) {
+ NIMBLE_LOGD(LOG_TAG, ">> readValue: uuid: %s", characteristicUuid.toString().c_str());
+
+ std::string ret = "";
+ NimBLERemoteCharacteristic* pChar = getCharacteristic(characteristicUuid);
+
+ if(pChar != nullptr) {
+ ret = pChar->readValue();
+ }
+
+ NIMBLE_LOGD(LOG_TAG, "<< readValue");
+ return ret;
+} // readValue
+
+
+/**
+ * @brief Set the value of a characteristic.
+ * @param [in] characteristicUuid The characteristic to set.
+ * @param [in] value The value to set.
+ * @returns true on success, false if not found or error
+ */
+bool NimBLERemoteService::setValue(const NimBLEUUID &characteristicUuid, const std::string &value) {
+ NIMBLE_LOGD(LOG_TAG, ">> setValue: uuid: %s", characteristicUuid.toString().c_str());
+
+ bool ret = false;
+ NimBLERemoteCharacteristic* pChar = getCharacteristic(characteristicUuid);
+
+ if(pChar != nullptr) {
+ ret = pChar->writeValue(value);
+ }
+
+ NIMBLE_LOGD(LOG_TAG, "<< setValue");
+ return ret;
+} // setValue
+
+
+/**
+ * @brief Delete the characteristics in the characteristics vector.
+ * @details We maintain a vector called m_characteristicsVector that contains pointers to BLERemoteCharacteristic
+ * object references. Since we allocated these in this class, we are also responsible for deleting
+ * them. This method does just that.
+ */
+void NimBLERemoteService::deleteCharacteristics() {
+ NIMBLE_LOGD(LOG_TAG, ">> deleteCharacteristics");
+ for(auto &it: m_characteristicVector) {
+ delete it;
+ }
+ m_characteristicVector.clear();
+ NIMBLE_LOGD(LOG_TAG, "<< deleteCharacteristics");
+} // deleteCharacteristics
+
+
+/**
+ * @brief Delete characteristic by UUID
+ * @param [in] uuid The UUID of the characteristic to be removed from the local database.
+ * @return Number of characteristics left.
+ */
+size_t NimBLERemoteService::deleteCharacteristic(const NimBLEUUID &uuid) {
+ NIMBLE_LOGD(LOG_TAG, ">> deleteCharacteristic");
+
+ for(auto it = m_characteristicVector.begin(); it != m_characteristicVector.end(); ++it) {
+ if((*it)->getUUID() == uuid) {
+ delete *it;
+ m_characteristicVector.erase(it);
+ break;
+ }
+ }
+
+ NIMBLE_LOGD(LOG_TAG, "<< deleteCharacteristic");
+
+ return m_characteristicVector.size();
+} // deleteCharacteristic
+
+
+/**
+ * @brief Create a string representation of this remote service.
+ * @return A string representation of this remote service.
+ */
+std::string NimBLERemoteService::toString() {
+ std::string res = "Service: uuid: " + m_uuid.toString();
+ char val[6];
+ res += ", start_handle: ";
+ snprintf(val, sizeof(val), "%d", m_startHandle);
+ res += val;
+ snprintf(val, sizeof(val), "%04x", m_startHandle);
+ res += " 0x";
+ res += val;
+ res += ", end_handle: ";
+ snprintf(val, sizeof(val), "%d", m_endHandle);
+ res += val;
+ snprintf(val, sizeof(val), "%04x", m_endHandle);
+ res += " 0x";
+ res += val;
+
+ for (auto &it: m_characteristicVector) {
+ res += "\n" + it->toString();
+ }
+
+ return res;
+} // toString
+
+#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/NimBLERemoteService.h b/src/components/esp-nimble-cpp-1.3.3/src/NimBLERemoteService.h
new file mode 100644
index 0000000..0443cfd
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/NimBLERemoteService.h
@@ -0,0 +1,85 @@
+/*
+ * NimBLERemoteService.h
+ *
+ * Created: on Jan 27 2020
+ * Author H2zero
+ *
+ * Originally:
+ *
+ * BLERemoteService.h
+ *
+ * Created on: Jul 8, 2017
+ * Author: kolban
+ */
+
+#ifndef COMPONENTS_NIMBLEREMOTESERVICE_H_
+#define COMPONENTS_NIMBLEREMOTESERVICE_H_
+
+#include "nimconfig.h"
+#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
+
+#include "NimBLEClient.h"
+#include "NimBLEUUID.h"
+#include "NimBLERemoteCharacteristic.h"
+
+#include
+
+class NimBLEClient;
+class NimBLERemoteCharacteristic;
+
+
+/**
+ * @brief A model of a remote %BLE service.
+ */
+class NimBLERemoteService {
+public:
+ virtual ~NimBLERemoteService();
+
+ // Public methods
+ std::vector::iterator begin();
+ std::vector::iterator end();
+ NimBLERemoteCharacteristic* getCharacteristic(const char* uuid);
+ NimBLERemoteCharacteristic* getCharacteristic(const NimBLEUUID &uuid);
+ void deleteCharacteristics();
+ size_t deleteCharacteristic(const NimBLEUUID &uuid);
+ NimBLEClient* getClient(void);
+ //uint16_t getHandle();
+ NimBLEUUID getUUID(void);
+ std::string getValue(const NimBLEUUID &characteristicUuid);
+ bool setValue(const NimBLEUUID &characteristicUuid,
+ const std::string &value);
+ std::string toString(void);
+ std::vector* getCharacteristics(bool refresh = false);
+
+private:
+ // Private constructor ... never meant to be created by a user application.
+ NimBLERemoteService(NimBLEClient* pClient, const struct ble_gatt_svc *service);
+
+ // Friends
+ friend class NimBLEClient;
+ friend class NimBLERemoteCharacteristic;
+
+ // Private methods
+ bool retrieveCharacteristics(const NimBLEUUID *uuid_filter = nullptr);
+ static int characteristicDiscCB(uint16_t conn_handle,
+ const struct ble_gatt_error *error,
+ const struct ble_gatt_chr *chr,
+ void *arg);
+
+ uint16_t getStartHandle();
+ uint16_t getEndHandle();
+ void releaseSemaphores();
+
+ // Properties
+
+ // We maintain a vector of characteristics owned by this service.
+ std::vector m_characteristicVector;
+
+ NimBLEClient* m_pClient;
+ NimBLEUUID m_uuid;
+ uint16_t m_startHandle;
+ uint16_t m_endHandle;
+}; // NimBLERemoteService
+
+#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
+#endif /* COMPONENTS_NIMBLEREMOTESERVICE_H_ */
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/NimBLEScan.cpp b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEScan.cpp
new file mode 100644
index 0000000..57a5df3
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEScan.cpp
@@ -0,0 +1,541 @@
+/*
+ * NimBLEScan.cpp
+ *
+ * Created: on Jan 24 2020
+ * Author H2zero
+ *
+ * Originally:
+ *
+ * BLEScan.cpp
+ *
+ * Created on: Jul 1, 2017
+ * Author: kolban
+ */
+
+#include "nimconfig.h"
+#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
+
+#include "NimBLEScan.h"
+#include "NimBLEDevice.h"
+#include "NimBLELog.h"
+
+#include
+#include
+
+static const char* LOG_TAG = "NimBLEScan";
+
+
+/**
+ * @brief Scan constuctor.
+ */
+NimBLEScan::NimBLEScan() {
+ m_scan_params.filter_policy = BLE_HCI_SCAN_FILT_NO_WL;
+ m_scan_params.passive = 1; // If set, don’t send scan requests to advertisers (i.e., don’t request additional advertising data).
+ m_scan_params.itvl = 0; // This is defined as the time interval from when the Controller started its last LE scan until it begins the subsequent LE scan. (units=0.625 msec)
+ m_scan_params.window = 0; // The duration of the LE scan. LE_Scan_Window shall be less than or equal to LE_Scan_Interval (units=0.625 msec)
+ m_scan_params.limited = 0; // If set, only discover devices in limited discoverable mode.
+ m_scan_params.filter_duplicates = 0; // If set, the controller ignores all but the first advertisement from each device.
+ m_pAdvertisedDeviceCallbacks = nullptr;
+ m_ignoreResults = false;
+ m_pTaskData = nullptr;
+ m_duration = BLE_HS_FOREVER; // make sure this is non-zero in the event of a host reset
+ m_maxResults = 0xFF;
+}
+
+
+/**
+ * @brief Scan destructor, release any allocated resources.
+ */
+NimBLEScan::~NimBLEScan() {
+ clearResults();
+}
+
+/**
+ * @brief Handle GAP events related to scans.
+ * @param [in] event The event type for this event.
+ * @param [in] param Parameter data for this event.
+ */
+/*STATIC*/int NimBLEScan::handleGapEvent(ble_gap_event* event, void* arg) {
+
+ NimBLEScan* pScan = (NimBLEScan*)arg;
+
+ switch(event->type) {
+
+ case BLE_GAP_EVENT_DISC: {
+ if(pScan->m_ignoreResults) {
+ NIMBLE_LOGI(LOG_TAG, "Scan op in progress - ignoring results");
+ return 0;
+ }
+
+ NimBLEAddress advertisedAddress(event->disc.addr);
+
+ // Examine our list of ignored addresses and stop processing if we don't want to see it or are already connected
+ if(NimBLEDevice::isIgnored(advertisedAddress)) {
+ NIMBLE_LOGI(LOG_TAG, "Ignoring device: address: %s", advertisedAddress.toString().c_str());
+ return 0;
+ }
+
+ NimBLEAdvertisedDevice* advertisedDevice = nullptr;
+
+ // If we've seen this device before get a pointer to it from the vector
+ for(auto &it: pScan->m_scanResults.m_advertisedDevicesVector) {
+ if(it->getAddress() == advertisedAddress) {
+ advertisedDevice = it;
+ break;
+ }
+ }
+
+ // 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 && 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 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 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 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);
+ }
+ }
+
+ return 0;
+ }
+ case BLE_GAP_EVENT_DISC_COMPLETE: {
+ NIMBLE_LOGD(LOG_TAG, "discovery complete; reason=%d",
+ 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);
+ }
+
+ if(pScan->m_pTaskData != nullptr) {
+ pScan->m_pTaskData->rc = event->disc_complete.reason;
+ xTaskNotifyGive(pScan->m_pTaskData->task);
+ }
+
+ return 0;
+ }
+
+ default:
+ return 0;
+ }
+} // gapEventHandler
+
+
+/**
+ * @brief Should we perform an active or passive scan?
+ * 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) {
+ m_scan_params.passive = !active;
+} // setActiveScan
+
+
+/**
+ * @brief Set whether or not the BLE controller should only report results
+ * from devices it has not already seen.
+ * @param [in] enabled If true, scanned devices will only be reported once.
+ * @details The controller has a limited buffer and will start reporting
+ * dupicate devices once the limit is reached.
+ */
+void NimBLEScan::setDuplicateFilter(bool enabled) {
+ m_scan_params.filter_duplicates = enabled;
+} // setDuplicateFilter
+
+
+/**
+ * @brief Set whether or not the BLE controller only report scan results
+ * from devices advertising in limited discovery mode, i.e. directed advertising.
+ * @param [in] enabled If true, only limited discovery devices will be in scan results.
+ */
+void NimBLEScan::setLimitedOnly(bool enabled) {
+ m_scan_params.limited = enabled;
+} // setLimited
+
+
+/**
+ * @brief Sets the scan filter policy.
+ * @param [in] filter Can be one of:
+ * * BLE_HCI_SCAN_FILT_NO_WL (0)
+ * Scanner processes all advertising packets (white list not used) except\n
+ * directed, connectable advertising packets not sent to the scanner.
+ * * BLE_HCI_SCAN_FILT_USE_WL (1)
+ * Scanner processes advertisements from white list only. A connectable,\n
+ * directed advertisment is ignored unless it contains scanners address.
+ * * BLE_HCI_SCAN_FILT_NO_WL_INITA (2)
+ * Scanner process all advertising packets (white list not used). A\n
+ * connectable, directed advertisement shall not be ignored if the InitA
+ * is a resolvable private address.
+ * * BLE_HCI_SCAN_FILT_USE_WL_INITA (3)
+ * Scanner process advertisements from white list only. A connectable,\n
+ * directed advertisement shall not be ignored if the InitA is a
+ * resolvable private address.
+ */
+void NimBLEScan::setFilterPolicy(uint8_t filter) {
+ m_scan_params.filter_policy = 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.
+ * @param [in] wantDuplicates True if we wish to be called back with duplicates. Default is false.
+ */
+void NimBLEScan::setAdvertisedDeviceCallbacks(NimBLEAdvertisedDeviceCallbacks* pAdvertisedDeviceCallbacks,
+ bool wantDuplicates) {
+ setDuplicateFilter(!wantDuplicates);
+ m_pAdvertisedDeviceCallbacks = pAdvertisedDeviceCallbacks;
+} // setAdvertisedDeviceCallbacks
+
+
+/**
+ * @brief Set the interval to scan.
+ * @param [in] intervalMSecs The scan interval (how often) in milliseconds.
+ */
+void NimBLEScan::setInterval(uint16_t intervalMSecs) {
+ m_scan_params.itvl = intervalMSecs / 0.625;
+} // setInterval
+
+
+/**
+ * @brief Set the window to actively scan.
+ * @param [in] windowMSecs How long to actively scan.
+ */
+void NimBLEScan::setWindow(uint16_t windowMSecs) {
+ m_scan_params.window = windowMSecs / 0.625;
+} // setWindow
+
+
+/**
+ * @brief Get the status of the scanner.
+ * @return true if scanning or scan starting.
+ */
+bool NimBLEScan::isScanning() {
+ return ble_gap_disc_active();
+}
+
+
+/**
+ * @brief Start scanning.
+ * @param [in] duration The duration in seconds for which to scan.
+ * @param [in] scanCompleteCB A function to be called when scanning has completed.
+ * @param [in] is_continue Set to true to save previous scan results, false to clear them.
+ * @return True if scan started or false if there was an error.
+ */
+bool NimBLEScan::start(uint32_t duration, void (*scanCompleteCB)(NimBLEScanResults), bool is_continue) {
+ NIMBLE_LOGD(LOG_TAG, ">> start: duration=%" PRIu32, duration);
+
+ // Save the callback to be invoked when the scan completes.
+ m_scanCompleteCB = scanCompleteCB;
+ // Save the duration in the case that the host is reset so we can reuse it.
+ m_duration = duration;
+
+ // If 0 duration specified then we assume a continuous scan is desired.
+ if(duration == 0){
+ duration = BLE_HS_FOREVER;
+ }
+ else{
+ // convert duration to milliseconds
+ duration = duration * 1000;
+ }
+
+ // Set the flag to ignore the results while we are deleting the vector
+ if(!is_continue) {
+ m_ignoreResults = true;
+ }
+
+ int rc = ble_gap_disc(NimBLEDevice::m_own_addr_type, duration, &m_scan_params,
+ NimBLEScan::handleGapEvent, this);
+
+ switch(rc) {
+ case 0:
+ if(!is_continue) {
+ clearResults();
+ }
+ break;
+
+ case BLE_HS_EALREADY:
+ // Clear the cache if already scanning in case an advertiser was missed.
+ clearDuplicateCache();
+ break;
+
+ case BLE_HS_EBUSY:
+ NIMBLE_LOGE(LOG_TAG, "Unable to scan - connection in progress.");
+ break;
+
+ case BLE_HS_ETIMEOUT_HCI:
+ case BLE_HS_EOS:
+ case BLE_HS_ECONTROLLER:
+ case BLE_HS_ENOTSYNCED:
+ NIMBLE_LOGC(LOG_TAG, "Unable to scan - Host Reset");
+ break;
+
+ default:
+ NIMBLE_LOGE(LOG_TAG, "Error initiating GAP discovery procedure; rc=%d, %s",
+ rc, NimBLEUtils::returnCodeToString(rc));
+ break;
+ }
+
+ m_ignoreResults = false;
+ NIMBLE_LOGD(LOG_TAG, "<< start()");
+
+ if(rc != 0 && rc != BLE_HS_EALREADY) {
+ return false;
+ }
+ return true;
+} // start
+
+
+/**
+ * @brief Start scanning and block until scanning has been completed.
+ * @param [in] duration The duration in seconds for which to scan.
+ * @param [in] is_continue Set to true to save previous scan results, false to clear them.
+ * @return The NimBLEScanResults.
+ */
+NimBLEScanResults NimBLEScan::start(uint32_t duration, bool is_continue) {
+ if(duration == 0) {
+ NIMBLE_LOGW(LOG_TAG, "Blocking scan called with duration = forever");
+ }
+
+ TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
+ ble_task_data_t taskData = {nullptr, cur_task, 0, nullptr};
+ m_pTaskData = &taskData;
+
+ if(start(duration, nullptr, is_continue)) {
+#ifdef ulTaskNotifyValueClear
+ // Clear the task notification value to ensure we block
+ ulTaskNotifyValueClear(cur_task, ULONG_MAX);
+#endif
+ ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
+ }
+
+ m_pTaskData = nullptr;
+ return m_scanResults;
+} // start
+
+
+/**
+ * @brief Stop an in progress scan.
+ * @return True if successful.
+ */
+bool NimBLEScan::stop() {
+ NIMBLE_LOGD(LOG_TAG, ">> stop()");
+
+ int rc = ble_gap_disc_cancel();
+ if (rc != 0 && rc != BLE_HS_EALREADY) {
+ 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);
+ }
+
+ if(m_pTaskData != nullptr) {
+ xTaskNotifyGive(m_pTaskData->task);
+ }
+
+ NIMBLE_LOGD(LOG_TAG, "<< stop()");
+ return true;
+} // stop
+
+
+/**
+ * @brief Clears the duplicate scan filter cache.
+ */
+void NimBLEScan::clearDuplicateCache() {
+#ifdef CONFIG_IDF_TARGET_ESP32 // Not available for ESP32C3
+ esp_ble_scan_dupilcate_list_flush();
+#endif
+}
+
+
+/**
+ * @brief Delete peer device from the scan results vector.
+ * @param [in] address The address of the device to delete from the results.
+ * @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_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) {
+ delete *it;
+ m_scanResults.m_advertisedDevicesVector.erase(it);
+ break;
+ }
+ }
+}
+
+
+/**
+ * @brief Called when host reset, we set a flag to stop scanning until synced.
+ */
+void NimBLEScan::onHostReset() {
+ m_ignoreResults = true;
+}
+
+
+/**
+ * @brief If the host reset and re-synced this is called.
+ * If the application was scanning indefinitely with a callback, restart it.
+ */
+void NimBLEScan::onHostSync() {
+ m_ignoreResults = false;
+
+ if(m_duration == 0 && m_pAdvertisedDeviceCallbacks != nullptr) {
+ start(m_duration, m_scanCompleteCB);
+ }
+}
+
+/**
+ * @brief Get the results of the scan.
+ * @return NimBLEScanResults object.
+ */
+NimBLEScanResults NimBLEScan::getResults() {
+ return m_scanResults;
+}
+
+
+/**
+ * @brief Clear the results of the scan.
+ */
+void NimBLEScan::clearResults() {
+ for(auto &it: m_scanResults.m_advertisedDevicesVector) {
+ delete it;
+ }
+ m_scanResults.m_advertisedDevicesVector.clear();
+ clearDuplicateCache();
+}
+
+
+/**
+ * @brief Dump the scan results to the log.
+ */
+void NimBLEScanResults::dump() {
+ NIMBLE_LOGD(LOG_TAG, ">> Dump scan results:");
+ for (int i=0; i::iterator NimBLEScanResults::begin() {
+ return m_advertisedDevicesVector.begin();
+}
+
+
+/**
+ * @brief Get iterator to the end of the vector of advertised device pointers.
+ * @return An iterator to the end of the vector of advertised device pointers.
+ */
+std::vector::iterator NimBLEScanResults::end() {
+ return m_advertisedDevicesVector.end();
+}
+
+
+/**
+ * @brief Get a pointer to the specified device at the given address.
+ * If the address is not found a nullptr is returned.
+ * @param [in] address The address of the device.
+ * @return A pointer to the device at the specified address.
+ */
+NimBLEAdvertisedDevice *NimBLEScanResults::getDevice(const NimBLEAddress &address) {
+ for(size_t index = 0; index < m_advertisedDevicesVector.size(); index++) {
+ if(m_advertisedDevicesVector[index]->getAddress() == address) {
+ return m_advertisedDevicesVector[index];
+ }
+ }
+
+ return nullptr;
+}
+
+#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_OBSERVER */
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/NimBLEScan.h b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEScan.h
new file mode 100644
index 0000000..76a1142
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEScan.h
@@ -0,0 +1,103 @@
+/*
+ * NimBLEScan.h
+ *
+ * Created: on Jan 24 2020
+ * Author H2zero
+ *
+ * Originally:
+ *
+ * BLEScan.h
+ *
+ * Created on: Jul 1, 2017
+ * Author: kolban
+ */
+#ifndef COMPONENTS_NIMBLE_SCAN_H_
+#define COMPONENTS_NIMBLE_SCAN_H_
+
+#include "nimconfig.h"
+#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
+
+#include "NimBLEAdvertisedDevice.h"
+#include "NimBLEUtils.h"
+
+#if defined(CONFIG_NIMBLE_CPP_IDF)
+#include "host/ble_gap.h"
+#else
+#include "nimble/nimble/host/include/host/ble_gap.h"
+#endif
+
+#include
+
+class NimBLEDevice;
+class NimBLEScan;
+class NimBLEAdvertisedDevice;
+class NimBLEAdvertisedDeviceCallbacks;
+class NimBLEAddress;
+
+/**
+ * @brief A class that contains and operates on the results of a BLE scan.
+ * @details When a scan completes, we have a set of found devices. Each device is described
+ * by a NimBLEAdvertisedDevice object. The number of items in the set is given by
+ * getCount(). We can retrieve a device by calling getDevice() passing in the
+ * index (starting at 0) of the desired device.
+ */
+class NimBLEScanResults {
+public:
+ void dump();
+ int getCount();
+ NimBLEAdvertisedDevice getDevice(uint32_t i);
+ std::vector::iterator begin();
+ std::vector::iterator end();
+ NimBLEAdvertisedDevice *getDevice(const NimBLEAddress &address);
+
+private:
+ friend NimBLEScan;
+ std::vector m_advertisedDevicesVector;
+};
+
+/**
+ * @brief Perform and manage %BLE scans.
+ *
+ * Scanning is associated with a %BLE client that is attempting to locate BLE servers.
+ */
+class NimBLEScan {
+public:
+ bool start(uint32_t duration, void (*scanCompleteCB)(NimBLEScanResults), bool is_continue = false);
+ NimBLEScanResults start(uint32_t duration, bool is_continue = false);
+ bool isScanning();
+ void setAdvertisedDeviceCallbacks(NimBLEAdvertisedDeviceCallbacks* pAdvertisedDeviceCallbacks, bool wantDuplicates = false);
+ void setActiveScan(bool active);
+ void setInterval(uint16_t intervalMSecs);
+ void setWindow(uint16_t windowMSecs);
+ void setDuplicateFilter(bool enabled);
+ void setLimitedOnly(bool enabled);
+ void setFilterPolicy(uint8_t filter);
+ void clearDuplicateCache();
+ bool stop();
+ void clearResults();
+ NimBLEScanResults getResults();
+ void setMaxResults(uint8_t maxResults);
+ void erase(const NimBLEAddress &address);
+
+
+private:
+ friend class NimBLEDevice;
+
+ NimBLEScan();
+ ~NimBLEScan();
+ static int handleGapEvent(ble_gap_event* event, void* arg);
+ void onHostReset();
+ void onHostSync();
+
+ NimBLEAdvertisedDeviceCallbacks* m_pAdvertisedDeviceCallbacks = nullptr;
+ void (*m_scanCompleteCB)(NimBLEScanResults scanResults);
+ ble_gap_disc_params m_scan_params;
+ bool m_ignoreResults;
+ NimBLEScanResults m_scanResults;
+ uint32_t m_duration;
+ ble_task_data_t *m_pTaskData;
+ uint8_t m_maxResults;
+};
+
+#endif /* CONFIG_BT_ENABLED CONFIG_BT_NIMBLE_ROLE_OBSERVER */
+#endif /* COMPONENTS_NIMBLE_SCAN_H_ */
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/NimBLESecurity.cpp b/src/components/esp-nimble-cpp-1.3.3/src/NimBLESecurity.cpp
new file mode 100644
index 0000000..df6d192
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/NimBLESecurity.cpp
@@ -0,0 +1,158 @@
+/*
+ * NimBLESecurity.cpp
+ *
+ * Created: on Feb 22 2020
+ * Author H2zero
+ *
+ * Originally:
+ *
+ * BLESecurity.cpp
+ *
+ * Created on: Dec 17, 2017
+ * Author: chegewara
+ */
+
+#include "nimconfig.h"
+#if defined(CONFIG_BT_ENABLED)
+
+#include "NimBLESecurity.h"
+#include "NimBLEDevice.h"
+
+NimBLESecurity::NimBLESecurity() {
+}
+
+NimBLESecurity::~NimBLESecurity() {
+}
+
+
+/**
+ * @brief Set requested authentication mode
+ * @param [in] auth_req A bitmask containing one or more of:
+ * * ESP_LE_AUTH_NO_BOND 0x00
+ * * ESP_LE_AUTH_BOND 0x01
+ * * ESP_LE_AUTH_REQ_MITM (1 << 2)
+ * * ESP_LE_AUTH_REQ_BOND_MITM (ESP_LE_AUTH_BOND | ESP_LE_AUTH_REQ_MITM)
+ * * ESP_LE_AUTH_REQ_SC_ONLY (1 << 3)
+ * * ESP_LE_AUTH_REQ_SC_BOND (ESP_LE_AUTH_BOND | ESP_LE_AUTH_REQ_SC_ONLY)
+ * * ESP_LE_AUTH_REQ_SC_MITM (ESP_LE_AUTH_REQ_MITM | ESP_LE_AUTH_REQ_SC_ONLY)
+ * * ESP_LE_AUTH_REQ_SC_MITM_BOND (ESP_LE_AUTH_REQ_MITM | ESP_LE_AUTH_REQ_SC_ONLY | ESP_LE_AUTH_BOND)
+ */
+void NimBLESecurity::setAuthenticationMode(esp_ble_auth_req_t auth_req) {
+ NimBLEDevice::setSecurityAuth((auth_req & BLE_SM_PAIR_AUTHREQ_BOND)>0,
+ (auth_req & BLE_SM_PAIR_AUTHREQ_MITM)>0,
+ (auth_req & BLE_SM_PAIR_AUTHREQ_SC)>0);
+}
+
+
+/**
+ * @brief Set our device IO capability to let end user perform authorization
+ * either by displaying or entering generated 6-digit pin code or use \"just works\".
+ * @param [in] iocap The IO capabilites our device has.\n
+ * Can be set to one of:
+ * * ESP_IO_CAP_OUT 0
+ * * ESP_IO_CAP_IO 1
+ * * ESP_IO_CAP_IN 2
+ * * ESP_IO_CAP_NONE 3
+ * * ESP_IO_CAP_KBDISP 4
+ */
+void NimBLESecurity::setCapability(esp_ble_io_cap_t iocap) {
+ NimBLEDevice::setSecurityIOCap(iocap);
+} // setCapability
+
+
+/**
+ * @brief Sets the keys we will distibute during encryption.
+ * @param [in] init_key A bitmask of the keys we will distibute.\n
+ * Can be one or more of:
+ * * ESP_BLE_ENC_KEY_MASK (1 << 0)
+ * * ESP_BLE_ID_KEY_MASK (1 << 1)
+ * * ESP_BLE_CSR_KEY_MASK (1 << 2)
+ * * ESP_BLE_LINK_KEY_MASK (1 << 3)
+ */
+void NimBLESecurity::setInitEncryptionKey(uint8_t init_key) {
+ NimBLEDevice::setSecurityInitKey(init_key);
+} // setInitEncryptionKey
+
+
+/**
+ * @brief Sets the keys we will accept during encryption.
+ * @param [in] resp_key A bitmask of the keys we will accept.\n
+ * Can be one or more of:
+ * * ESP_BLE_ENC_KEY_MASK (1 << 0)
+ * * ESP_BLE_ID_KEY_MASK (1 << 1)
+ * * ESP_BLE_CSR_KEY_MASK (1 << 2)
+ * * ESP_BLE_LINK_KEY_MASK (1 << 3)
+ */
+void NimBLESecurity::setRespEncryptionKey(uint8_t resp_key) {
+ NimBLEDevice::setSecurityRespKey(resp_key);
+} // setRespEncryptionKey
+
+
+/**
+ *@todo Requires implementation
+ */
+void NimBLESecurity::setKeySize(uint8_t key_size) {
+
+ //m_keySize = key_size;
+ //esp_ble_gap_set_security_param(ESP_BLE_SM_MAX_KEY_SIZE, &m_keySize, sizeof(uint8_t));
+} //setKeySize
+
+
+/**
+ * @brief Sets a static PIN used to authenticate/encrypt the connection.
+ * @param [in] pin The 6 digit pin code to accept.
+ */
+void NimBLESecurity::setStaticPIN(uint32_t pin){
+ //uint32_t passkey = pin;
+ //esp_ble_gap_set_security_param(ESP_BLE_SM_SET_STATIC_PASSKEY, &passkey, sizeof(uint32_t));
+ NimBLEDevice::setSecurityPasskey(pin);
+ setCapability(ESP_IO_CAP_OUT);
+ setKeySize();
+ setAuthenticationMode(ESP_LE_AUTH_REQ_SC_ONLY);
+ setInitEncryptionKey(ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK);
+}
+
+
+/**
+ * @brief Debug function to display what keys are exchanged by peers
+ */
+ /*
+char* BLESecurity::esp_key_type_to_str(esp_ble_key_type_t key_type) {
+ char* key_str = nullptr;
+ switch (key_type) {
+ case ESP_LE_KEY_NONE:
+ key_str = (char*) "ESP_LE_KEY_NONE";
+ break;
+ case ESP_LE_KEY_PENC:
+ key_str = (char*) "ESP_LE_KEY_PENC";
+ break;
+ case ESP_LE_KEY_PID:
+ key_str = (char*) "ESP_LE_KEY_PID";
+ break;
+ case ESP_LE_KEY_PCSRK:
+ key_str = (char*) "ESP_LE_KEY_PCSRK";
+ break;
+ case ESP_LE_KEY_PLK:
+ key_str = (char*) "ESP_LE_KEY_PLK";
+ break;
+ case ESP_LE_KEY_LLK:
+ key_str = (char*) "ESP_LE_KEY_LLK";
+ break;
+ case ESP_LE_KEY_LENC:
+ key_str = (char*) "ESP_LE_KEY_LENC";
+ break;
+ case ESP_LE_KEY_LID:
+ key_str = (char*) "ESP_LE_KEY_LID";
+ break;
+ case ESP_LE_KEY_LCSRK:
+ key_str = (char*) "ESP_LE_KEY_LCSRK";
+ break;
+ default:
+ key_str = (char*) "INVALID BLE KEY TYPE";
+ break;
+ }
+ return key_str;
+
+} // esp_key_type_to_str
+*/
+#endif // CONFIG_BT_ENABLED
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/NimBLESecurity.h b/src/components/esp-nimble-cpp-1.3.3/src/NimBLESecurity.h
new file mode 100644
index 0000000..157577d
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/NimBLESecurity.h
@@ -0,0 +1,131 @@
+/*
+ * NimBLESecurity.h
+ *
+ * Created: on Feb 22 2020
+ * Author H2zero
+ *
+ * Originally:
+ *
+ * BLESecurity.h
+ *
+ * Created on: Dec 17, 2017
+ * Author: chegewara
+ */
+
+#ifndef COMPONENTS_NIMBLESECURITY_H_
+#define COMPONENTS_NIMBLESECURITY_H_
+
+#include "nimconfig.h"
+#if defined(CONFIG_BT_ENABLED)
+
+#if defined(CONFIG_NIMBLE_CPP_IDF)
+#include "host/ble_gap.h"
+#else
+#include "nimble/nimble/host/include/host/ble_gap.h"
+#endif
+
+/**** FIX COMPILATION ****/
+#undef min
+#undef max
+/**************************/
+
+#include
+
+#define ESP_LE_AUTH_NO_BOND 0x00 /*!< 0*/ /* relate to BTM_LE_AUTH_NO_BOND in stack/btm_api.h */
+#define ESP_LE_AUTH_BOND 0x01 /*!< 1 << 0 */ /* relate to BTM_LE_AUTH_BOND in stack/btm_api.h */
+#define ESP_LE_AUTH_REQ_MITM (1 << 2) /*!< 1 << 2 */ /* relate to BTM_LE_AUTH_REQ_MITM in stack/btm_api.h */
+#define ESP_LE_AUTH_REQ_BOND_MITM (ESP_LE_AUTH_BOND | ESP_LE_AUTH_REQ_MITM)/*!< 0101*/
+#define ESP_LE_AUTH_REQ_SC_ONLY (1 << 3) /*!< 1 << 3 */ /* relate to BTM_LE_AUTH_REQ_SC_ONLY in stack/btm_api.h */
+#define ESP_LE_AUTH_REQ_SC_BOND (ESP_LE_AUTH_BOND | ESP_LE_AUTH_REQ_SC_ONLY) /*!< 1001 */ /* relate to BTM_LE_AUTH_REQ_SC_BOND in stack/btm_api.h */
+#define ESP_LE_AUTH_REQ_SC_MITM (ESP_LE_AUTH_REQ_MITM | ESP_LE_AUTH_REQ_SC_ONLY) /*!< 1100 */ /* relate to BTM_LE_AUTH_REQ_SC_MITM in stack/btm_api.h */
+#define ESP_LE_AUTH_REQ_SC_MITM_BOND (ESP_LE_AUTH_REQ_MITM | ESP_LE_AUTH_REQ_SC_ONLY | ESP_LE_AUTH_BOND) /*!< 1101 */ /* relate to BTM_LE_AUTH_REQ_SC_MITM_BOND in stack/btm_api.h */
+
+#define ESP_IO_CAP_OUT 0 /*!< DisplayOnly */ /* relate to BTM_IO_CAP_OUT in stack/btm_api.h */
+#define ESP_IO_CAP_IO 1 /*!< DisplayYesNo */ /* relate to BTM_IO_CAP_IO in stack/btm_api.h */
+#define ESP_IO_CAP_IN 2 /*!< KeyboardOnly */ /* relate to BTM_IO_CAP_IN in stack/btm_api.h */
+#define ESP_IO_CAP_NONE 3 /*!< NoInputNoOutput */ /* relate to BTM_IO_CAP_NONE in stack/btm_api.h */
+#define ESP_IO_CAP_KBDISP 4 /*!< Keyboard display */ /* relate to BTM_IO_CAP_KBDISP in stack/btm_api.h */
+
+/// Used to exchange the encryption key in the init key & response key
+#define ESP_BLE_ENC_KEY_MASK (1 << 0) /* relate to BTM_BLE_ENC_KEY_MASK in stack/btm_api.h */
+/// Used to exchange the IRK key in the init key & response key
+#define ESP_BLE_ID_KEY_MASK (1 << 1) /* relate to BTM_BLE_ID_KEY_MASK in stack/btm_api.h */
+/// Used to exchange the CSRK key in the init key & response key
+#define ESP_BLE_CSR_KEY_MASK (1 << 2) /* relate to BTM_BLE_CSR_KEY_MASK in stack/btm_api.h */
+/// Used to exchange the link key(this key just used in the BLE & BR/EDR coexist mode) in the init key & response key
+#define ESP_BLE_LINK_KEY_MASK (1 << 3) /* relate to BTM_BLE_LINK_KEY_MASK in stack/btm_api.h */
+
+typedef uint8_t esp_ble_auth_req_t; /*!< combination of the above bit pattern */
+typedef uint8_t esp_ble_io_cap_t; /*!< combination of the io capability */
+
+
+/**
+ * @brief A class to handle BLE security operations.
+ * Deprecated - provided for backward compatibility only.
+ * @deprecated Use the security methods provided in NimBLEDevice instead.
+ */
+class NimBLESecurity {
+public:
+ NimBLESecurity();
+ virtual ~NimBLESecurity();
+ void setAuthenticationMode(esp_ble_auth_req_t auth_req);
+ void setCapability(esp_ble_io_cap_t iocap);
+ void setInitEncryptionKey(uint8_t init_key);
+ void setRespEncryptionKey(uint8_t resp_key);
+ void setKeySize(uint8_t key_size = 16);
+ void setStaticPIN(uint32_t pin);
+ //static char* esp_key_type_to_str(esp_ble_key_type_t key_type);
+/*
+private:
+ esp_ble_auth_req_t m_authReq;
+ esp_ble_io_cap_t m_iocap;
+ uint8_t m_initKey;
+ uint8_t m_respKey;
+ uint8_t m_keySize;
+*/
+}; // BLESecurity
+
+
+/**
+ * @brief Callbacks to handle GAP events related to authorization.
+ * Deprecated - provided for backward compatibility only.
+ * @deprecated Use the callbacks provided in NimBLEClientCallbacks and NimBLEServerCallbacks instead.
+ */
+class NimBLESecurityCallbacks {
+public:
+ virtual ~NimBLESecurityCallbacks() {};
+
+ /**
+ * @brief Its request from peer device to input authentication pin code displayed on peer device.
+ * It requires that our device is capable to input 6-digits code by end user
+ * @return Return 6-digits integer value from input device
+ */
+ virtual uint32_t onPassKeyRequest() = 0;
+
+ /**
+ * @brief Provide us 6-digits code to perform authentication.
+ * It requires that our device is capable to display this code to end user
+ * @param [in] pass_key The PIN provided by the peer.
+ */
+ virtual void onPassKeyNotify(uint32_t pass_key) = 0;
+
+ /**
+ * @brief Here we can make decision if we want to let negotiate authorization with peer device or not
+ * @return Return true if we accept this peer device request
+ */
+ virtual bool onSecurityRequest() = 0 ;
+ /**
+ * @brief Provides us information when authentication process is completed
+ */
+ virtual void onAuthenticationComplete(ble_gap_conn_desc*) = 0;
+
+ /**
+ * @brief Called when using numeric comparison for authentication.
+ * @param [in] pin The PIN to compare.
+ * @return True to accept and pair.
+ */
+ virtual bool onConfirmPIN(uint32_t pin) = 0;
+}; // BLESecurityCallbacks
+
+#endif // CONFIG_BT_ENABLED
+#endif // COMPONENTS_NIMBLESECURITY_H_
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/NimBLEServer.cpp b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEServer.cpp
new file mode 100644
index 0000000..03ee785
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEServer.cpp
@@ -0,0 +1,867 @@
+/*
+ * NimBLEServer.cpp
+ *
+ * Created: on March 2, 2020
+ * Author H2zero
+ *
+ * Originally:
+ *
+ * BLEServer.cpp
+ *
+ * Created on: Apr 16, 2017
+ * Author: kolban
+ */
+
+#include "nimconfig.h"
+#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
+
+#include "NimBLEServer.h"
+#include "NimBLEDevice.h"
+#include "NimBLELog.h"
+
+#if defined(CONFIG_NIMBLE_CPP_IDF)
+#include "services/gap/ble_svc_gap.h"
+#include "services/gatt/ble_svc_gatt.h"
+#else
+#include "nimble/nimble/host/services/gap/include/services/gap/ble_svc_gap.h"
+#include "nimble/nimble/host/services/gatt/include/services/gatt/ble_svc_gatt.h"
+#endif
+
+static const char* LOG_TAG = "NimBLEServer";
+static NimBLEServerCallbacks defaultCallbacks;
+
+
+/**
+ * @brief Construct a %BLE Server
+ *
+ * This class is not designed to be individually instantiated. Instead one should create a server by asking
+ * the NimBLEDevice class.
+ */
+NimBLEServer::NimBLEServer() {
+ memset(m_indWait, BLE_HS_CONN_HANDLE_NONE, sizeof(m_indWait));
+// m_svcChgChrHdl = 0xffff; // Future Use
+ m_pServerCallbacks = &defaultCallbacks;
+ m_gattsStarted = false;
+ m_advertiseOnDisconnect = true;
+ m_svcChanged = false;
+ m_deleteCallbacks = true;
+} // NimBLEServer
+
+
+/**
+ * @brief Destructor: frees all resources / attributes created.
+ */
+NimBLEServer::~NimBLEServer() {
+ for(auto &it : m_svcVec) {
+ delete it;
+ }
+
+ if(m_deleteCallbacks && m_pServerCallbacks != &defaultCallbacks) {
+ delete m_pServerCallbacks;
+ }
+}
+
+
+/**
+ * @brief Create a %BLE Service.
+ * @param [in] uuid The UUID of the new service.
+ * @return A reference to the new service object.
+ */
+NimBLEService* NimBLEServer::createService(const char* uuid) {
+ return createService(NimBLEUUID(uuid));
+} // createService
+
+
+/**
+ * @brief Create a %BLE Service.
+ * @param [in] uuid The UUID of the new service.
+ * @return A reference to the new service object.
+ */
+NimBLEService* NimBLEServer::createService(const NimBLEUUID &uuid) {
+ NIMBLE_LOGD(LOG_TAG, ">> createService - %s", uuid.toString().c_str());
+
+ // Check that a service with the supplied UUID does not already exist.
+ if(getServiceByUUID(uuid) != nullptr) {
+ NIMBLE_LOGW(LOG_TAG, "Warning creating a duplicate service UUID: %s",
+ std::string(uuid).c_str());
+ }
+
+ NimBLEService* pService = new NimBLEService(uuid);
+ m_svcVec.push_back(pService);
+ serviceChanged();
+
+ NIMBLE_LOGD(LOG_TAG, "<< createService");
+ return pService;
+} // createService
+
+
+/**
+ * @brief Get a %BLE Service by its UUID
+ * @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, uint16_t instanceId) {
+ return getServiceByUUID(NimBLEUUID(uuid), instanceId);
+} // getServiceByUUID
+
+
+/**
+ * @brief Get a %BLE Service by its UUID
+ * @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, uint16_t instanceId) {
+ uint16_t position = 0;
+ for (auto &it : m_svcVec) {
+ if (it->getUUID() == uuid) {
+ 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.
+ *
+ * @return An advertising object.
+ */
+NimBLEAdvertising* NimBLEServer::getAdvertising() {
+ return NimBLEDevice::getAdvertising();
+} // getAdvertising
+
+
+/**
+ * @brief Sends a service changed notification and resets the GATT server.
+ */
+void NimBLEServer::serviceChanged() {
+ if(m_gattsStarted) {
+ m_svcChanged = true;
+ ble_svc_gatt_changed(0x0001, 0xffff);
+ resetGATT();
+ }
+}
+
+
+/**
+ * @brief Start the GATT server. Required to be called after setup of all
+ * services and characteristics / descriptors for the NimBLE host to register them.
+ */
+void NimBLEServer::start() {
+ if(m_gattsStarted) {
+ NIMBLE_LOGW(LOG_TAG, "Gatt server already started");
+ return;
+ }
+
+ int rc = ble_gatts_start();
+ if (rc != 0) {
+ NIMBLE_LOGE(LOG_TAG, "ble_gatts_start; rc=%d, %s", rc,
+ NimBLEUtils::returnCodeToString(rc));
+ abort();
+ }
+
+#if CONFIG_NIMBLE_CPP_LOG_LEVEL >= 4
+ ble_gatts_show_local();
+#endif
+/*** Future use ***
+ * TODO: implement service changed handling
+
+ ble_uuid16_t svc = {BLE_UUID_TYPE_16, 0x1801};
+ ble_uuid16_t chr = {BLE_UUID_TYPE_16, 0x2a05};
+
+ rc = ble_gatts_find_chr(&svc.u, &chr.u, NULL, &m_svcChgChrHdl);
+ if(rc != 0) {
+ NIMBLE_LOGE(LOG_TAG, "ble_gatts_find_chr: rc=%d, %s", rc,
+ NimBLEUtils::returnCodeToString(rc));
+ abort();
+ }
+
+ NIMBLE_LOGI(LOG_TAG, "Service changed characterisic handle: %d", m_svcChgChrHdl);
+*/
+ // Get the assigned service handles and build a vector of characteristics
+ // with Notify / Indicate capabilities for event handling
+ for(auto &svc : m_svcVec) {
+ if(svc->m_removed == 0) {
+ rc = ble_gatts_find_svc(&svc->getUUID().getNative()->u, &svc->m_handle);
+ if(rc != 0) {
+ abort();
+ }
+ }
+
+ for(auto &chr : svc->m_chrVec) {
+ // if Notify / Indicate is enabled but we didn't create the descriptor
+ // we do it now.
+ if((chr->m_properties & BLE_GATT_CHR_F_INDICATE) ||
+ (chr->m_properties & BLE_GATT_CHR_F_NOTIFY)) {
+ m_notifyChrVec.push_back(chr);
+ }
+ }
+ }
+
+ m_gattsStarted = true;
+} // start
+
+
+/**
+ * @brief Disconnect the specified client with optional reason.
+ * @param [in] connId Connection Id of the client to disconnect.
+ * @param [in] reason code for disconnecting.
+ * @return NimBLE host return code.
+ */
+int NimBLEServer::disconnect(uint16_t connId, uint8_t reason) {
+ NIMBLE_LOGD(LOG_TAG, ">> disconnect()");
+
+ int rc = ble_gap_terminate(connId, reason);
+ if(rc != 0){
+ NIMBLE_LOGE(LOG_TAG, "ble_gap_terminate failed: rc=%d %s", rc,
+ NimBLEUtils::returnCodeToString(rc));
+ }
+
+ NIMBLE_LOGD(LOG_TAG, "<< disconnect()");
+ return rc;
+} // disconnect
+
+
+/**
+ * @brief Set the server to automatically start advertising when a client disconnects.
+ * @param [in] aod true == advertise, false == don't advertise.
+ */
+void NimBLEServer::advertiseOnDisconnect(bool aod) {
+ m_advertiseOnDisconnect = aod;
+} // advertiseOnDisconnect
+
+
+/**
+ * @brief Return the number of connected clients.
+ * @return The number of connected clients.
+ */
+size_t NimBLEServer::getConnectedCount() {
+ return m_connectedPeersVec.size();
+} // getConnectedCount
+
+
+/**
+ * @brief Get the vector of the connected client ID's.
+ */
+std::vector NimBLEServer::getPeerDevices() {
+ return m_connectedPeersVec;
+} // getPeerDevices
+
+
+/**
+ * @brief Get the connection information of a connected peer by vector index.
+ * @param [in] index The vector index of the peer.
+ */
+NimBLEConnInfo NimBLEServer::getPeerInfo(size_t index) {
+ if (index >= m_connectedPeersVec.size()) {
+ NIMBLE_LOGE(LOG_TAG, "No peer at index %u", index);
+ return NimBLEConnInfo();
+ }
+
+ return getPeerIDInfo(m_connectedPeersVec[index]);
+} // getPeerInfo
+
+
+/**
+ * @brief Get the connection information of a connected peer by address.
+ * @param [in] address The address of the peer.
+ */
+NimBLEConnInfo NimBLEServer::getPeerInfo(const NimBLEAddress& address) {
+ ble_addr_t peerAddr;
+ memcpy(&peerAddr.val, address.getNative(),6);
+ peerAddr.type = address.getType();
+
+ NimBLEConnInfo peerInfo;
+ int rc = ble_gap_conn_find_by_addr(&peerAddr, &peerInfo.m_desc);
+ if (rc != 0) {
+ NIMBLE_LOGE(LOG_TAG, "Peer info not found");
+ }
+
+ return peerInfo;
+} // getPeerInfo
+
+
+/**
+ * @brief Get the connection information of a connected peer by connection ID.
+ * @param [in] id The connection id of the peer.
+ */
+NimBLEConnInfo NimBLEServer::getPeerIDInfo(uint16_t id) {
+ NimBLEConnInfo peerInfo;
+
+ int rc = ble_gap_conn_find(id, &peerInfo.m_desc);
+ if (rc != 0) {
+ NIMBLE_LOGE(LOG_TAG, "Peer info not found");
+ }
+
+ return peerInfo;
+} // getPeerIDInfo
+
+
+/**
+ * @brief Handle a GATT Server Event.
+ *
+ * @param [in] event
+ * @param [in] gatts_if
+ * @param [in] param
+ *
+ */
+/*STATIC*/
+int NimBLEServer::handleGapEvent(struct ble_gap_event *event, void *arg) {
+ NimBLEServer* server = (NimBLEServer*)arg;
+ NIMBLE_LOGD(LOG_TAG, ">> handleGapEvent: %s",
+ NimBLEUtils::gapEventToString(event->type));
+ int rc = 0;
+ struct ble_gap_conn_desc desc;
+
+ switch(event->type) {
+
+ case BLE_GAP_EVENT_CONNECT: {
+ if (event->connect.status != 0) {
+ /* Connection failed; resume advertising */
+ NIMBLE_LOGE(LOG_TAG, "Connection failed");
+ NimBLEDevice::startAdvertising();
+ }
+ else {
+ server->m_connectedPeersVec.push_back(event->connect.conn_handle);
+
+ rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
+ if (rc != 0) {
+ return 0;
+ }
+
+ server->m_pServerCallbacks->onConnect(server);
+ server->m_pServerCallbacks->onConnect(server, &desc);
+ }
+
+ return 0;
+ } // BLE_GAP_EVENT_CONNECT
+
+
+ case BLE_GAP_EVENT_DISCONNECT: {
+ // If Host reset tell the device now before returning to prevent
+ // any errors caused by calling host functions before resyncing.
+ switch(event->disconnect.reason) {
+ case BLE_HS_ETIMEOUT_HCI:
+ case BLE_HS_EOS:
+ case BLE_HS_ECONTROLLER:
+ case BLE_HS_ENOTSYNCED:
+ NIMBLE_LOGC(LOG_TAG, "Disconnect - host reset, rc=%d", event->disconnect.reason);
+ NimBLEDevice::onReset(event->disconnect.reason);
+ break;
+ default:
+ break;
+ }
+
+ server->m_connectedPeersVec.erase(std::remove(server->m_connectedPeersVec.begin(),
+ server->m_connectedPeersVec.end(),
+ event->disconnect.conn.conn_handle),
+ server->m_connectedPeersVec.end());
+
+ if(server->m_svcChanged) {
+ server->resetGATT();
+ }
+
+ server->m_pServerCallbacks->onDisconnect(server);
+ server->m_pServerCallbacks->onDisconnect(server, &event->disconnect.conn);
+
+ if(server->m_advertiseOnDisconnect) {
+ server->startAdvertising();
+ }
+ return 0;
+ } // BLE_GAP_EVENT_DISCONNECT
+
+ case BLE_GAP_EVENT_SUBSCRIBE: {
+ NIMBLE_LOGI(LOG_TAG, "subscribe event; attr_handle=%d, subscribed: %s",
+ event->subscribe.attr_handle,
+ (event->subscribe.cur_notify ? "true":"false"));
+
+ for(auto &it : server->m_notifyChrVec) {
+ if(it->getHandle() == event->subscribe.attr_handle) {
+ if((it->getProperties() & BLE_GATT_CHR_F_READ_AUTHEN) ||
+ (it->getProperties() & BLE_GATT_CHR_F_READ_AUTHOR) ||
+ (it->getProperties() & BLE_GATT_CHR_F_READ_ENC))
+ {
+ rc = ble_gap_conn_find(event->subscribe.conn_handle, &desc);
+ if (rc != 0) {
+ break;
+ }
+
+ if(!desc.sec_state.encrypted) {
+ NimBLEDevice::startSecurity(event->subscribe.conn_handle);
+ }
+ }
+
+ it->setSubscribe(event);
+ break;
+ }
+ }
+
+ return 0;
+ } // BLE_GAP_EVENT_SUBSCRIBE
+
+ case BLE_GAP_EVENT_MTU: {
+ NIMBLE_LOGI(LOG_TAG, "mtu update event; conn_handle=%d mtu=%d",
+ event->mtu.conn_handle,
+ event->mtu.value);
+ rc = ble_gap_conn_find(event->mtu.conn_handle, &desc);
+ if (rc != 0) {
+ return 0;
+ }
+
+ server->m_pServerCallbacks->onMTUChange(event->mtu.value, &desc);
+ return 0;
+ } // BLE_GAP_EVENT_MTU
+
+ case BLE_GAP_EVENT_NOTIFY_TX: {
+ NimBLECharacteristic *pChar = nullptr;
+
+ for(auto &it : server->m_notifyChrVec) {
+ if(it->getHandle() == event->notify_tx.attr_handle) {
+ pChar = it;
+ }
+ }
+
+ if(pChar == nullptr) {
+ return 0;
+ }
+
+ NimBLECharacteristicCallbacks::Status statusRC;
+
+ if(event->notify_tx.indication) {
+ if(event->notify_tx.status != 0) {
+ if(event->notify_tx.status == BLE_HS_EDONE) {
+ statusRC = NimBLECharacteristicCallbacks::Status::SUCCESS_INDICATE;
+ } else if(rc == BLE_HS_ETIMEOUT) {
+ statusRC = NimBLECharacteristicCallbacks::Status::ERROR_INDICATE_TIMEOUT;
+ } else {
+ statusRC = NimBLECharacteristicCallbacks::Status::ERROR_INDICATE_FAILURE;
+ }
+ } else {
+ return 0;
+ }
+
+ server->clearIndicateWait(event->notify_tx.conn_handle);
+ } else {
+ if(event->notify_tx.status == 0) {
+ statusRC = NimBLECharacteristicCallbacks::Status::SUCCESS_NOTIFY;
+ } else {
+ statusRC = NimBLECharacteristicCallbacks::Status::ERROR_GATT;
+ }
+ }
+
+ pChar->m_pCallbacks->onStatus(pChar, statusRC, event->notify_tx.status);
+
+ return 0;
+ } // BLE_GAP_EVENT_NOTIFY_TX
+
+ case BLE_GAP_EVENT_ADV_COMPLETE: {
+ NIMBLE_LOGD(LOG_TAG, "Advertising Complete");
+ NimBLEDevice::getAdvertising()->advCompleteCB();
+ return 0;
+ }
+
+ case BLE_GAP_EVENT_CONN_UPDATE: {
+ NIMBLE_LOGD(LOG_TAG, "Connection parameters updated.");
+ return 0;
+ } // BLE_GAP_EVENT_CONN_UPDATE
+
+ case BLE_GAP_EVENT_REPEAT_PAIRING: {
+ /* We already have a bond with the peer, but it is attempting to
+ * establish a new secure link. This app sacrifices security for
+ * convenience: just throw away the old bond and accept the new link.
+ */
+
+ /* Delete the old bond. */
+ rc = ble_gap_conn_find(event->repeat_pairing.conn_handle, &desc);
+ if (rc != 0){
+ return BLE_GAP_REPEAT_PAIRING_IGNORE;
+ }
+
+ ble_store_util_delete_peer(&desc.peer_id_addr);
+
+ /* Return BLE_GAP_REPEAT_PAIRING_RETRY to indicate that the host should
+ * continue with the pairing operation.
+ */
+ return BLE_GAP_REPEAT_PAIRING_RETRY;
+ } // BLE_GAP_EVENT_REPEAT_PAIRING
+
+ case BLE_GAP_EVENT_ENC_CHANGE: {
+ rc = ble_gap_conn_find(event->enc_change.conn_handle, &desc);
+ if(rc != 0) {
+ return BLE_ATT_ERR_INVALID_HANDLE;
+ }
+ // Compatibility only - Do not use, should be removed the in future
+ if(NimBLEDevice::m_securityCallbacks != nullptr) {
+ NimBLEDevice::m_securityCallbacks->onAuthenticationComplete(&desc);
+ /////////////////////////////////////////////
+ } else {
+ server->m_pServerCallbacks->onAuthenticationComplete(&desc);
+ }
+
+ return 0;
+ } // BLE_GAP_EVENT_ENC_CHANGE
+
+ case BLE_GAP_EVENT_PASSKEY_ACTION: {
+ struct ble_sm_io pkey = {0,0};
+
+ if (event->passkey.params.action == BLE_SM_IOACT_DISP) {
+ pkey.action = event->passkey.params.action;
+ // backward compatibility
+ pkey.passkey = NimBLEDevice::getSecurityPasskey(); // This is the passkey to be entered on peer
+ // if the (static)passkey is the default, check the callback for custom value
+ // both values default to the same.
+ if(pkey.passkey == 123456) {
+ pkey.passkey = server->m_pServerCallbacks->onPassKeyRequest();
+ }
+ rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
+ NIMBLE_LOGD(LOG_TAG, "BLE_SM_IOACT_DISP; ble_sm_inject_io result: %d", rc);
+
+ } else if (event->passkey.params.action == BLE_SM_IOACT_NUMCMP) {
+ NIMBLE_LOGD(LOG_TAG, "Passkey on device's display: %" PRIu32, event->passkey.params.numcmp);
+ pkey.action = event->passkey.params.action;
+ // Compatibility only - Do not use, should be removed the in future
+ if(NimBLEDevice::m_securityCallbacks != nullptr) {
+ pkey.numcmp_accept = NimBLEDevice::m_securityCallbacks->onConfirmPIN(event->passkey.params.numcmp);
+ /////////////////////////////////////////////
+ } else {
+ pkey.numcmp_accept = server->m_pServerCallbacks->onConfirmPIN(event->passkey.params.numcmp);
+ }
+
+ rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
+ NIMBLE_LOGD(LOG_TAG, "BLE_SM_IOACT_NUMCMP; ble_sm_inject_io result: %d", rc);
+
+ //TODO: Handle out of band pairing
+ } else if (event->passkey.params.action == BLE_SM_IOACT_OOB) {
+ static uint8_t tem_oob[16] = {0};
+ pkey.action = event->passkey.params.action;
+ for (int i = 0; i < 16; i++) {
+ pkey.oob[i] = tem_oob[i];
+ }
+ rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
+ NIMBLE_LOGD(LOG_TAG, "BLE_SM_IOACT_OOB; ble_sm_inject_io result: %d", rc);
+ //////////////////////////////////
+ } else if (event->passkey.params.action == BLE_SM_IOACT_INPUT) {
+ NIMBLE_LOGD(LOG_TAG, "Enter the passkey");
+ pkey.action = event->passkey.params.action;
+
+ // Compatibility only - Do not use, should be removed the in future
+ if(NimBLEDevice::m_securityCallbacks != nullptr) {
+ pkey.passkey = NimBLEDevice::m_securityCallbacks->onPassKeyRequest();
+ /////////////////////////////////////////////
+ } else {
+ pkey.passkey = server->m_pServerCallbacks->onPassKeyRequest();
+ }
+
+ rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
+ NIMBLE_LOGD(LOG_TAG, "BLE_SM_IOACT_INPUT; ble_sm_inject_io result: %d", rc);
+
+ } else if (event->passkey.params.action == BLE_SM_IOACT_NONE) {
+ NIMBLE_LOGD(LOG_TAG, "No passkey action required");
+ }
+
+ NIMBLE_LOGD(LOG_TAG, "<< handleGATTServerEvent");
+ return 0;
+ } // BLE_GAP_EVENT_PASSKEY_ACTION
+
+ default:
+ break;
+ }
+
+ NIMBLE_LOGD(LOG_TAG, "<< handleGATTServerEvent");
+ return 0;
+} // handleGapEvent
+
+
+/**
+ * @brief Set the server callbacks.
+ *
+ * As a %BLE server operates, it will generate server level events such as a new client connecting or a previous client
+ * disconnecting. This function can be called to register a callback handler that will be invoked when these
+ * events are detected.
+ *
+ * @param [in] pCallbacks The callbacks to be invoked.
+ * @param [in] deleteCallbacks if true callback class will be deleted when server is destructed.
+ */
+void NimBLEServer::setCallbacks(NimBLEServerCallbacks* pCallbacks, bool deleteCallbacks) {
+ if (pCallbacks != nullptr){
+ m_pServerCallbacks = pCallbacks;
+ m_deleteCallbacks = deleteCallbacks;
+ } else {
+ m_pServerCallbacks = &defaultCallbacks;
+ }
+} // setCallbacks
+
+
+/**
+ * @brief Remove a service from the server.
+ *
+ * @details Immediately removes access to the service by clients, sends a service changed indication,
+ * and removes the service (if applicable) from the advertisments.
+ * The service is not deleted unless the deleteSvc parameter is true, otherwise the service remains
+ * available and can be re-added in the future. If desired a removed but not deleted service can
+ * be deleted later by calling this method with deleteSvc set to true.
+ *
+ * @note The service will not be removed from the database until all open connections are closed
+ * as it requires resetting the GATT server. In the interim the service will have it's visibility disabled.
+ *
+ * @note Advertising will need to be restarted by the user after calling this as we must stop
+ * advertising in order to remove the service.
+ *
+ * @param [in] service The service object to remove.
+ * @param [in] deleteSvc true if the service should be deleted.
+ */
+void NimBLEServer::removeService(NimBLEService* service, bool deleteSvc) {
+ // Check if the service was already removed and if so check if this
+ // is being called to delete the object and do so if requested.
+ // Otherwise, ignore the call and return.
+ if(service->m_removed > 0) {
+ if(deleteSvc) {
+ for(auto it = m_svcVec.begin(); it != m_svcVec.end(); ++it) {
+ if ((*it) == service) {
+ delete *it;
+ m_svcVec.erase(it);
+ break;
+ }
+ }
+ }
+
+ return;
+ }
+
+ int rc = ble_gatts_svc_set_visibility(service->getHandle(), 0);
+ if(rc !=0) {
+ return;
+ }
+
+ service->m_removed = deleteSvc ? NIMBLE_ATT_REMOVE_DELETE : NIMBLE_ATT_REMOVE_HIDE;
+ serviceChanged();
+ NimBLEDevice::getAdvertising()->removeServiceUUID(service->getUUID());
+}
+
+
+/**
+ * @brief Adds a service which was either already created but removed from availability,\n
+ * or created and later added to services list.
+ * @param [in] service The service object to add.
+ * @note If it is desired to advertise the service it must be added by
+ * calling NimBLEAdvertising::addServiceUUID.
+ */
+void NimBLEServer::addService(NimBLEService* service) {
+ // Check that a service with the supplied UUID does not already exist.
+ if(getServiceByUUID(service->getUUID()) != nullptr) {
+ NIMBLE_LOGW(LOG_TAG, "Warning creating a duplicate service UUID: %s",
+ std::string(service->getUUID()).c_str());
+ }
+
+ // If adding a service that was not removed add it and return.
+ // Else reset GATT and send service changed notification.
+ if(service->m_removed == 0) {
+ m_svcVec.push_back(service);
+ return;
+ }
+
+ service->m_removed = 0;
+ serviceChanged();
+}
+
+
+/**
+ * @brief Resets the GATT server, used when services are added/removed after initialization.
+ */
+void NimBLEServer::resetGATT() {
+ if(getConnectedCount() > 0) {
+ return;
+ }
+
+ NimBLEDevice::stopAdvertising();
+ ble_gatts_reset();
+ ble_svc_gap_init();
+ ble_svc_gatt_init();
+
+ for(auto it = m_svcVec.begin(); it != m_svcVec.end(); ) {
+ if ((*it)->m_removed > 0) {
+ if ((*it)->m_removed == NIMBLE_ATT_REMOVE_DELETE) {
+ delete *it;
+ it = m_svcVec.erase(it);
+ } else {
+ ++it;
+ }
+ continue;
+ }
+
+ (*it)->start();
+ ++it;
+ }
+
+ m_svcChanged = false;
+ m_gattsStarted = false;
+}
+
+
+/**
+ * @brief Start advertising.
+ *
+ * Start the server advertising its existence. This is a convenience function and is equivalent to
+ * retrieving the advertising object and invoking start upon it.
+ */
+void NimBLEServer::startAdvertising() {
+ NimBLEDevice::startAdvertising();
+} // startAdvertising
+
+
+/**
+ * @brief Stop advertising.
+ */
+void NimBLEServer::stopAdvertising() {
+ NimBLEDevice::stopAdvertising();
+} // stopAdvertising
+
+
+/**
+ * @brief Get the MTU of the client.
+ * @returns The client MTU or 0 if not found/connected.
+ */
+uint16_t NimBLEServer::getPeerMTU(uint16_t conn_id) {
+ return ble_att_mtu(conn_id);
+} //getPeerMTU
+
+
+/**
+ * @brief Request an Update the connection parameters:
+ * * Can only be used after a connection has been established.
+ * @param [in] conn_handle The connection handle of the peer to send the request to.
+ * @param [in] minInterval The minimum connection interval in 1.25ms units.
+ * @param [in] maxInterval The maximum connection interval in 1.25ms units.
+ * @param [in] latency The number of packets allowed to skip (extends max interval).
+ * @param [in] timeout The timeout time in 10ms units before disconnecting.
+ */
+void NimBLEServer::updateConnParams(uint16_t conn_handle,
+ uint16_t minInterval, uint16_t maxInterval,
+ uint16_t latency, uint16_t timeout)
+{
+ ble_gap_upd_params params;
+
+ params.latency = latency;
+ params.itvl_max = maxInterval; // max_int = 0x20*1.25ms = 40ms
+ params.itvl_min = minInterval; // min_int = 0x10*1.25ms = 20ms
+ params.supervision_timeout = timeout; // timeout = 400*10ms = 4000ms
+ params.min_ce_len = BLE_GAP_INITIAL_CONN_MIN_CE_LEN; // Minimum length of connection event in 0.625ms units
+ params.max_ce_len = BLE_GAP_INITIAL_CONN_MAX_CE_LEN; // Maximum length of connection event in 0.625ms units
+
+ int rc = ble_gap_update_params(conn_handle, ¶ms);
+ if(rc != 0) {
+ NIMBLE_LOGE(LOG_TAG, "Update params error: %d, %s", rc, NimBLEUtils::returnCodeToString(rc));
+ }
+} // updateConnParams
+
+
+/**
+ * @brief Request an update of the data packet length.
+ * * Can only be used after a connection has been established.
+ * @details Sends a data length update request to the peer.
+ * The Data Length Extension (DLE) allows to increase the Data Channel Payload from 27 bytes to up to 251 bytes.
+ * The peer needs to support the Bluetooth 4.2 specifications, to be capable of DLE.
+ * @param [in] conn_handle The connection handle of the peer to send the request to.
+ * @param [in] tx_octets The preferred number of payload octets to use (Range 0x001B-0x00FB).
+ */
+void NimBLEServer::setDataLen(uint16_t conn_handle, uint16_t tx_octets) {
+#if defined(CONFIG_NIMBLE_CPP_IDF) && !defined(ESP_IDF_VERSION) || \
+ (ESP_IDF_VERSION_MAJOR * 100 + ESP_IDF_VERSION_MINOR * 10 + ESP_IDF_VERSION_PATCH) < 432
+ return;
+#else
+ uint16_t tx_time = (tx_octets + 14) * 8;
+
+ int rc = ble_gap_set_data_len(conn_handle, tx_octets, tx_time);
+ if(rc != 0) {
+ NIMBLE_LOGE(LOG_TAG, "Set data length error: %d, %s", rc, NimBLEUtils::returnCodeToString(rc));
+ }
+#endif
+} // setDataLen
+
+
+bool NimBLEServer::setIndicateWait(uint16_t conn_handle) {
+ for(auto i = 0; i < CONFIG_BT_NIMBLE_MAX_CONNECTIONS; i++) {
+ if(m_indWait[i] == conn_handle) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+void NimBLEServer::clearIndicateWait(uint16_t conn_handle) {
+ for(auto i = 0; i < CONFIG_BT_NIMBLE_MAX_CONNECTIONS; i++) {
+ if(m_indWait[i] == conn_handle) {
+ m_indWait[i] = BLE_HS_CONN_HANDLE_NONE;
+ return;
+ }
+ }
+}
+
+
+/** Default callback handlers */
+
+void NimBLEServerCallbacks::onConnect(NimBLEServer* pServer) {
+ NIMBLE_LOGD("NimBLEServerCallbacks", "onConnect(): Default");
+} // onConnect
+
+
+void NimBLEServerCallbacks::onConnect(NimBLEServer* pServer, ble_gap_conn_desc* desc) {
+ NIMBLE_LOGD("NimBLEServerCallbacks", "onConnect(): Default");
+} // onConnect
+
+
+void NimBLEServerCallbacks::onDisconnect(NimBLEServer* pServer) {
+ NIMBLE_LOGD("NimBLEServerCallbacks", "onDisconnect(): Default");
+} // onDisconnect
+
+void NimBLEServerCallbacks::onDisconnect(NimBLEServer* pServer, ble_gap_conn_desc* desc) {
+ NIMBLE_LOGD("NimBLEServerCallbacks", "onDisconnect(): Default");
+} // onDisconnect
+
+void NimBLEServerCallbacks::onMTUChange(uint16_t MTU, ble_gap_conn_desc* desc) {
+ NIMBLE_LOGD("NimBLEServerCallbacks", "onMTUChange(): Default");
+} // onMTUChange
+
+uint32_t NimBLEServerCallbacks::onPassKeyRequest(){
+ NIMBLE_LOGD("NimBLEServerCallbacks", "onPassKeyRequest: default: 123456");
+ return 123456;
+}
+/*
+void NimBLEServerCallbacks::onPassKeyNotify(uint32_t pass_key){
+ NIMBLE_LOGD("NimBLEServerCallbacks", "onPassKeyNotify: default: %d", pass_key);
+}
+
+bool NimBLEServerCallbacks::onSecurityRequest(){
+ NIMBLE_LOGD("NimBLEServerCallbacks", "onSecurityRequest: default: true");
+ return true;
+}
+*/
+void NimBLEServerCallbacks::onAuthenticationComplete(ble_gap_conn_desc*){
+ NIMBLE_LOGD("NimBLEServerCallbacks", "onAuthenticationComplete: default");
+}
+bool NimBLEServerCallbacks::onConfirmPIN(uint32_t pin){
+ NIMBLE_LOGD("NimBLEServerCallbacks", "onConfirmPIN: default: true");
+ return true;
+}
+
+#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/NimBLEServer.h b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEServer.h
new file mode 100644
index 0000000..605445a
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEServer.h
@@ -0,0 +1,172 @@
+/*
+ * NimBLEServer.h
+ *
+ * Created: on March 2, 2020
+ * Author H2zero
+ *
+ * Originally:
+ *
+ * BLEServer.h
+ *
+ * Created on: Apr 16, 2017
+ * Author: kolban
+ */
+
+#ifndef MAIN_NIMBLESERVER_H_
+#define MAIN_NIMBLESERVER_H_
+
+#include "nimconfig.h"
+#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
+
+#define NIMBLE_ATT_REMOVE_HIDE 1
+#define NIMBLE_ATT_REMOVE_DELETE 2
+
+#define onMtuChanged onMTUChange
+
+#include "NimBLEUtils.h"
+#include "NimBLEAddress.h"
+#include "NimBLEAdvertising.h"
+#include "NimBLEService.h"
+#include "NimBLESecurity.h"
+#include "NimBLEConnInfo.h"
+
+
+class NimBLEService;
+class NimBLECharacteristic;
+class NimBLEServerCallbacks;
+
+
+/**
+ * @brief The model of a %BLE server.
+ */
+class NimBLEServer {
+public:
+ size_t getConnectedCount();
+ NimBLEService* createService(const char* uuid);
+ NimBLEService* createService(const NimBLEUUID &uuid);
+ void removeService(NimBLEService* service, bool deleteSvc = false);
+ void addService(NimBLEService* service);
+ NimBLEAdvertising* getAdvertising();
+ void setCallbacks(NimBLEServerCallbacks* pCallbacks,
+ bool deleteCallbacks = true);
+ void startAdvertising();
+ void stopAdvertising();
+ void start();
+ 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,
+ uint16_t minInterval, uint16_t maxInterval,
+ uint16_t latency, uint16_t timeout);
+ void setDataLen(uint16_t conn_handle, uint16_t tx_octets);
+ uint16_t getPeerMTU(uint16_t conn_id);
+ std::vector getPeerDevices();
+ NimBLEConnInfo getPeerInfo(size_t index);
+ NimBLEConnInfo getPeerInfo(const NimBLEAddress& address);
+ NimBLEConnInfo getPeerIDInfo(uint16_t id);
+ void advertiseOnDisconnect(bool);
+
+private:
+ NimBLEServer();
+ ~NimBLEServer();
+ friend class NimBLECharacteristic;
+ friend class NimBLEService;
+ friend class NimBLEDevice;
+ friend class NimBLEAdvertising;
+
+ bool m_gattsStarted;
+ bool m_advertiseOnDisconnect;
+ bool m_svcChanged;
+ NimBLEServerCallbacks* m_pServerCallbacks;
+ bool m_deleteCallbacks;
+ uint16_t m_indWait[CONFIG_BT_NIMBLE_MAX_CONNECTIONS];
+ std::vector m_connectedPeersVec;
+
+// uint16_t m_svcChgChrHdl; // Future use
+
+ std::vector m_svcVec;
+ std::vector m_notifyChrVec;
+
+ static int handleGapEvent(struct ble_gap_event *event, void *arg);
+ void serviceChanged();
+ void resetGATT();
+ bool setIndicateWait(uint16_t conn_handle);
+ void clearIndicateWait(uint16_t conn_handle);
+}; // NimBLEServer
+
+
+/**
+ * @brief Callbacks associated with the operation of a %BLE server.
+ */
+class NimBLEServerCallbacks {
+public:
+ virtual ~NimBLEServerCallbacks() {};
+
+ /**
+ * @brief Handle a client connection.
+ * This is called when a client connects.
+ * @param [in] pServer A pointer to the %BLE server that received the client connection.
+ */
+ virtual void onConnect(NimBLEServer* pServer);
+
+ /**
+ * @brief Handle a client connection.
+ * This is called when a client connects.
+ * @param [in] pServer A pointer to the %BLE server that received the client connection.
+ * @param [in] desc A pointer to the connection description structure containig information
+ * about the connection parameters.
+ */
+ virtual void onConnect(NimBLEServer* pServer, ble_gap_conn_desc* desc);
+
+ /**
+ * @brief Handle a client disconnection.
+ * This is called when a client disconnects.
+ * @param [in] pServer A reference to the %BLE server that received the existing client disconnection.
+ */
+ virtual void onDisconnect(NimBLEServer* pServer);
+
+ /**
+ * @brief Handle a client disconnection.
+ * This is called when a client discconnects.
+ * @param [in] pServer A pointer to the %BLE server that received the client disconnection.
+ * @param [in] desc A pointer to the connection description structure containig information
+ * about the connection.
+ */
+ virtual void onDisconnect(NimBLEServer* pServer, ble_gap_conn_desc* desc);
+
+ /**
+ * @brief Called when the connection MTU changes.
+ * @param [in] MTU The new MTU value.
+ * @param [in] desc A pointer to the connection description structure containig information
+ * about the connection.
+ */
+ virtual void onMTUChange(uint16_t MTU, ble_gap_conn_desc* desc);
+
+ /**
+ * @brief Called when a client requests a passkey for pairing.
+ * @return The passkey to be sent to the client.
+ */
+ virtual uint32_t onPassKeyRequest();
+
+ //virtual void onPassKeyNotify(uint32_t pass_key);
+ //virtual bool onSecurityRequest();
+
+ /**
+ * @brief Called when the pairing procedure is complete.
+ * @param [in] desc A pointer to the struct containing the connection information.\n
+ * This can be used to check the status of the connection encryption/pairing.
+ */
+ virtual void onAuthenticationComplete(ble_gap_conn_desc* desc);
+
+ /**
+ * @brief Called when using numeric comparision for pairing.
+ * @param [in] pin The pin to compare with the client.
+ * @return True to accept the pin.
+ */
+ virtual bool onConfirmPIN(uint32_t pin);
+}; // NimBLEServerCallbacks
+
+#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
+#endif /* MAIN_NIMBLESERVER_H_ */
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/NimBLEService.cpp b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEService.cpp
new file mode 100644
index 0000000..f8cd0f6
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEService.cpp
@@ -0,0 +1,433 @@
+/*
+ * NimBLEService.cpp
+ *
+ * Created: on March 2, 2020
+ * Author H2zero
+ *
+ * Originally:
+ *
+ * BLEService.cpp
+ *
+ * Created on: Mar 25, 2017
+ * Author: kolban
+ */
+
+// A service is identified by a UUID. A service is also the container for one or more characteristics.
+
+#include "nimconfig.h"
+#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
+
+#include "NimBLEDevice.h"
+#include "NimBLEService.h"
+#include "NimBLEUtils.h"
+#include "NimBLELog.h"
+
+#include
+
+static const char* LOG_TAG = "NimBLEService"; // Tag for logging.
+
+#define NULL_HANDLE (0xffff)
+
+
+/**
+ * @brief Construct an instance of the NimBLEService
+ * @param [in] uuid The UUID of the service.
+ */
+NimBLEService::NimBLEService(const char* uuid)
+: NimBLEService(NimBLEUUID(uuid)) {
+}
+
+
+/**
+ * @brief Construct an instance of the BLEService
+ * @param [in] uuid The UUID of the service.
+ */
+NimBLEService::NimBLEService(const NimBLEUUID &uuid) {
+ m_uuid = uuid;
+ m_handle = NULL_HANDLE;
+ m_pSvcDef = nullptr;
+ m_removed = 0;
+
+} // NimBLEService
+
+
+NimBLEService::~NimBLEService() {
+ if(m_pSvcDef != nullptr) {
+ if(m_pSvcDef->characteristics != nullptr) {
+ for(int i=0; m_pSvcDef->characteristics[i].uuid != NULL; ++i) {
+ if(m_pSvcDef->characteristics[i].descriptors) {
+ delete(m_pSvcDef->characteristics[i].descriptors);
+ }
+ }
+ delete(m_pSvcDef->characteristics);
+ }
+
+ delete(m_pSvcDef);
+ }
+
+ for(auto &it : m_chrVec) {
+ delete it;
+ }
+}
+
+/**
+ * @brief Dump details of this BLE GATT service.
+ * @return N/A.
+ */
+void NimBLEService::dump() {
+ NIMBLE_LOGD(LOG_TAG, "Service: uuid:%s, handle: 0x%2x",
+ m_uuid.toString().c_str(),
+ m_handle);
+
+ std::string res;
+ int count = 0;
+ char hex[5];
+ for (auto &it: m_chrVec) {
+ if (count > 0) {res += "\n";}
+ snprintf(hex, sizeof(hex), "%04x", it->getHandle());
+ count++;
+ res += "handle: 0x";
+ res += hex;
+ res += ", uuid: " + std::string(it->getUUID());
+ }
+ NIMBLE_LOGD(LOG_TAG, "Characteristics:\n%s", res.c_str());
+} // dump
+
+
+/**
+ * @brief Get the UUID of the service.
+ * @return the UUID of the service.
+ */
+NimBLEUUID NimBLEService::getUUID() {
+ return m_uuid;
+} // getUUID
+
+
+/**
+ * @brief Builds the database of characteristics/descriptors for the service
+ * and registers it with the NimBLE stack.
+ * @return bool success/failure .
+ */
+bool NimBLEService::start() {
+ NIMBLE_LOGD(LOG_TAG, ">> start(): Starting service: %s", toString().c_str());
+
+ // Rebuild the service definition if the server attributes have changed.
+ if(getServer()->m_svcChanged && m_pSvcDef != nullptr) {
+ if(m_pSvcDef[0].characteristics) {
+ if(m_pSvcDef[0].characteristics[0].descriptors) {
+ delete(m_pSvcDef[0].characteristics[0].descriptors);
+ }
+ delete(m_pSvcDef[0].characteristics);
+ }
+ delete(m_pSvcDef);
+ m_pSvcDef = nullptr;
+ }
+
+ if(m_pSvcDef == nullptr) {
+ // Nimble requires an array of services to be sent to the api
+ // Since we are adding 1 at a time we create an array of 2 and set the type
+ // of the second service to 0 to indicate the end of the array.
+ ble_gatt_svc_def* svc = new ble_gatt_svc_def[2];
+ ble_gatt_chr_def* pChr_a = nullptr;
+ ble_gatt_dsc_def* pDsc_a = nullptr;
+
+ svc[0].type = BLE_GATT_SVC_TYPE_PRIMARY;
+ svc[0].uuid = &m_uuid.getNative()->u;
+ svc[0].includes = NULL;
+
+ int removedCount = 0;
+ for(auto it = m_chrVec.begin(); it != m_chrVec.end(); ) {
+ if ((*it)->m_removed > 0) {
+ if ((*it)->m_removed == NIMBLE_ATT_REMOVE_DELETE) {
+ delete *it;
+ it = m_chrVec.erase(it);
+ } else {
+ ++removedCount;
+ ++it;
+ }
+ continue;
+ }
+
+ ++it;
+ }
+
+ size_t numChrs = m_chrVec.size() - removedCount;
+ NIMBLE_LOGD(LOG_TAG,"Adding %d characteristics for service %s", numChrs, toString().c_str());
+
+ if(!numChrs){
+ svc[0].characteristics = NULL;
+ }else{
+ // Nimble requires the last characteristic to have it's uuid = 0 to indicate the end
+ // of the characteristics for the service. We create 1 extra and set it to null
+ // for this purpose.
+ pChr_a = new ble_gatt_chr_def[numChrs + 1];
+ uint8_t i = 0;
+ for(auto chr_it = m_chrVec.begin(); chr_it != m_chrVec.end(); ++chr_it) {
+ if((*chr_it)->m_removed > 0) {
+ continue;
+ }
+
+ removedCount = 0;
+ for(auto it = (*chr_it)->m_dscVec.begin(); it != (*chr_it)->m_dscVec.end(); ) {
+ if ((*it)->m_removed > 0) {
+ if ((*it)->m_removed == NIMBLE_ATT_REMOVE_DELETE) {
+ delete *it;
+ it = (*chr_it)->m_dscVec.erase(it);
+ } else {
+ ++removedCount;
+ ++it;
+ }
+ continue;
+ }
+
+ ++it;
+ }
+
+ size_t numDscs = (*chr_it)->m_dscVec.size() - removedCount;
+
+ if(!numDscs){
+ pChr_a[i].descriptors = NULL;
+ } else {
+ // Must have last descriptor uuid = 0 so we have to create 1 extra
+ pDsc_a = new ble_gatt_dsc_def[numDscs+1];
+ uint8_t d = 0;
+ for(auto dsc_it = (*chr_it)->m_dscVec.begin(); dsc_it != (*chr_it)->m_dscVec.end(); ++dsc_it ) {
+ if((*dsc_it)->m_removed > 0) {
+ continue;
+ }
+ pDsc_a[d].uuid = &(*dsc_it)->m_uuid.getNative()->u;
+ pDsc_a[d].att_flags = (*dsc_it)->m_properties;
+ pDsc_a[d].min_key_size = 0;
+ pDsc_a[d].access_cb = NimBLEDescriptor::handleGapEvent;
+ pDsc_a[d].arg = (*dsc_it);
+ ++d;
+ }
+
+ pDsc_a[numDscs].uuid = NULL;
+ pChr_a[i].descriptors = pDsc_a;
+ }
+
+ pChr_a[i].uuid = &(*chr_it)->m_uuid.getNative()->u;
+ pChr_a[i].access_cb = NimBLECharacteristic::handleGapEvent;
+ pChr_a[i].arg = (*chr_it);
+ pChr_a[i].flags = (*chr_it)->m_properties;
+ pChr_a[i].min_key_size = 0;
+ pChr_a[i].val_handle = &(*chr_it)->m_handle;
+ ++i;
+ }
+
+ pChr_a[numChrs].uuid = NULL;
+ svc[0].characteristics = pChr_a;
+ }
+
+ // end of services must indicate to api with type = 0
+ svc[1].type = 0;
+ m_pSvcDef = svc;
+ }
+
+ int rc = ble_gatts_count_cfg((const ble_gatt_svc_def*)m_pSvcDef);
+ if (rc != 0) {
+ NIMBLE_LOGE(LOG_TAG, "ble_gatts_count_cfg failed, rc= %d, %s", rc, NimBLEUtils::returnCodeToString(rc));
+ return false;
+ }
+
+ rc = ble_gatts_add_svcs((const ble_gatt_svc_def*)m_pSvcDef);
+ if (rc != 0) {
+ NIMBLE_LOGE(LOG_TAG, "ble_gatts_add_svcs, rc= %d, %s", rc, NimBLEUtils::returnCodeToString(rc));
+ return false;
+
+ }
+
+ NIMBLE_LOGD(LOG_TAG, "<< start()");
+ return true;
+} // start
+
+
+/**
+ * @brief Get the handle associated with this service.
+ * @return The handle associated with this service.
+ */
+uint16_t NimBLEService::getHandle() {
+ return m_handle;
+} // getHandle
+
+
+/**
+ * @brief Create a new BLE Characteristic associated with this service.
+ * @param [in] uuid - The UUID of the characteristic.
+ * @param [in] properties - The properties of the characteristic.
+ * @return The new BLE characteristic.
+ */
+NimBLECharacteristic* NimBLEService::createCharacteristic(const char* uuid, uint32_t properties) {
+ return createCharacteristic(NimBLEUUID(uuid), properties);
+}
+
+
+/**
+ * @brief Create a new BLE Characteristic associated with this service.
+ * @param [in] uuid - The UUID of the characteristic.
+ * @param [in] properties - The properties of the characteristic.
+ * @return The new BLE characteristic.
+ */
+NimBLECharacteristic* NimBLEService::createCharacteristic(const NimBLEUUID &uuid, uint32_t properties) {
+ NimBLECharacteristic* pCharacteristic = new NimBLECharacteristic(uuid, properties, this);
+
+ if (getCharacteristic(uuid) != nullptr) {
+ NIMBLE_LOGD(LOG_TAG, "<< Adding a duplicate characteristic with UUID: %s",
+ std::string(uuid).c_str());
+ }
+
+ addCharacteristic(pCharacteristic);
+ return pCharacteristic;
+} // createCharacteristic
+
+
+/**
+ * @brief Add a characteristic to the service.
+ * @param[in] pCharacteristic A pointer to the characteristic instance to add to the service.
+ */
+void NimBLEService::addCharacteristic(NimBLECharacteristic* pCharacteristic) {
+ bool foundRemoved = false;
+
+ if(pCharacteristic->m_removed > 0) {
+ for(auto& it : m_chrVec) {
+ if(it == pCharacteristic) {
+ foundRemoved = true;
+ pCharacteristic->m_removed = 0;
+ }
+ }
+ }
+
+ if(!foundRemoved) {
+ m_chrVec.push_back(pCharacteristic);
+ }
+
+ pCharacteristic->setService(this);
+ getServer()->serviceChanged();
+} // addCharacteristic
+
+
+/**
+ * @brief Remove a characteristic from the service.
+ * @param[in] pCharacteristic A pointer to the characteristic instance to remove from the service.
+ * @param[in] deleteChr If true it will delete the characteristic instance and free it's resources.
+ */
+void NimBLEService::removeCharacteristic(NimBLECharacteristic* pCharacteristic, bool deleteChr) {
+ // Check if the characteristic was already removed and if so, check if this
+ // is being called to delete the object and do so if requested.
+ // Otherwise, ignore the call and return.
+ if(pCharacteristic->m_removed > 0) {
+ if(deleteChr) {
+ for(auto it = m_chrVec.begin(); it != m_chrVec.end(); ++it) {
+ if ((*it) == pCharacteristic) {
+ m_chrVec.erase(it);
+ delete *it;
+ break;
+ }
+ }
+ }
+
+ return;
+ }
+
+ pCharacteristic->m_removed = deleteChr ? NIMBLE_ATT_REMOVE_DELETE : NIMBLE_ATT_REMOVE_HIDE;
+ getServer()->serviceChanged();
+} // removeCharacteristic
+
+
+/**
+ * @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, 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, uint16_t instanceId) {
+ uint16_t position = 0;
+ for (auto &it : m_chrVec) {
+ if (it->getUUID() == uuid) {
+ 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.
+ * A service is defined by:
+ * * Its UUID
+ * * Its handle
+ * @return A string representation of this service.
+ */
+std::string NimBLEService::toString() {
+ std::string res = "UUID: " + getUUID().toString();
+ char hex[5];
+ snprintf(hex, sizeof(hex), "%04x", getHandle());
+ res += ", handle: 0x";
+ res += hex;
+ return res;
+} // toString
+
+
+/**
+ * @brief Get the BLE server associated with this service.
+ * @return The BLEServer associated with this service.
+ */
+NimBLEServer* NimBLEService::getServer() {
+ return NimBLEDevice::getServer();
+}// getServer
+
+#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/NimBLEService.h b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEService.h
new file mode 100644
index 0000000..fbdd2e1
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEService.h
@@ -0,0 +1,85 @@
+/*
+ * NimBLEService.h
+ *
+ * Created: on March 2, 2020
+ * Author H2zero
+ *
+ * Originally:
+ *
+ * BLEService.h
+ *
+ * Created on: Mar 25, 2017
+ * Author: kolban
+ */
+
+#ifndef MAIN_NIMBLESERVICE_H_
+#define MAIN_NIMBLESERVICE_H_
+
+#include "nimconfig.h"
+#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
+
+#include "NimBLEServer.h"
+#include "NimBLECharacteristic.h"
+#include "NimBLEUUID.h"
+
+
+class NimBLEServer;
+class NimBLECharacteristic;
+
+
+/**
+ * @brief The model of a %BLE service.
+ *
+ */
+class NimBLEService {
+public:
+
+ NimBLEService(const char* uuid);
+ NimBLEService(const NimBLEUUID &uuid);
+ ~NimBLEService();
+
+ 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 |
+ NIMBLE_PROPERTY::WRITE);
+
+ NimBLECharacteristic* createCharacteristic(const NimBLEUUID &uuid,
+ uint32_t properties =
+ NIMBLE_PROPERTY::READ |
+ NIMBLE_PROPERTY::WRITE);
+
+ void addCharacteristic(NimBLECharacteristic* pCharacteristic);
+ void removeCharacteristic(NimBLECharacteristic* pCharacteristic, bool deleteChr = false);
+ 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:
+
+ friend class NimBLEServer;
+ friend class NimBLEDevice;
+
+ uint16_t m_handle;
+ NimBLEUUID m_uuid;
+ ble_gatt_svc_def* m_pSvcDef;
+ uint8_t m_removed;
+ std::vector m_chrVec;
+
+}; // NimBLEService
+
+#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
+#endif /* MAIN_NIMBLESERVICE_H_ */
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/NimBLEUUID.cpp b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEUUID.cpp
new file mode 100644
index 0000000..255f771
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEUUID.cpp
@@ -0,0 +1,360 @@
+/*
+ * NimBLEUUID.cpp
+ *
+ * Created: on Jan 24 2020
+ * Author H2zero
+ *
+ * Originally:
+ *
+ * BLEUUID.cpp
+ *
+ * Created on: Jun 21, 2017
+ * Author: kolban
+ */
+
+#include "nimconfig.h"
+#if defined(CONFIG_BT_ENABLED)
+
+#include "NimBLEUtils.h"
+#include "NimBLEUUID.h"
+#include "NimBLELog.h"
+
+#include
+
+static const char* LOG_TAG = "NimBLEUUID";
+
+
+/**
+ * @brief Create a UUID from a string.
+ *
+ * Create a UUID from a string. There will be two possible stories here. Either the string represents
+ * a binary data field or the string represents a hex encoding of a UUID.
+ * For the hex encoding, here is an example:
+ *
+ * ```
+ * "beb5483e-36e1-4688-b7f5-ea07361b26a8"
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ * 12345678-90ab-cdef-1234-567890abcdef
+ * ```
+ *
+ * This has a length of 36 characters. We need to parse this into 16 bytes.
+ *
+ * @param [in] value The string to build a UUID from.
+ */
+ NimBLEUUID::NimBLEUUID(const std::string &value) {
+ m_valueSet = true;
+ if (value.length() == 4) {
+ m_uuid.u.type = BLE_UUID_TYPE_16;
+ m_uuid.u16.value = strtoul(value.c_str(), NULL, 16);
+ }
+ else if (value.length() == 8) {
+ m_uuid.u.type = BLE_UUID_TYPE_32;
+ m_uuid.u32.value = strtoul(value.c_str(), NULL, 16);
+ }
+ else if (value.length() == 16) {
+ *this = NimBLEUUID((uint8_t*)value.data(), 16, true);
+ }
+ else if (value.length() == 36) {
+ // If the length of the string is 36 bytes then we will assume it is a long hex string in
+ // UUID format.
+ char * position = const_cast(value.c_str());
+ uint32_t first = strtoul(position, &position, 16);
+ uint16_t second = strtoul(position + 1, &position, 16);
+ uint16_t third = strtoul(position + 1, &position, 16);
+ uint16_t fourth = strtoul(position + 1, &position, 16);
+ uint64_t fifth = strtoull(position + 1, NULL, 16);
+ *this = NimBLEUUID(first, second, third, (uint64_t(fourth) << 48) + fifth);
+ }
+ else {
+ m_valueSet = false;
+ }
+} // NimBLEUUID(std::string)
+
+
+/**
+ * @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) {
+ 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 + size, uuidValue);
+ } else {
+ memcpy(uuidValue, pData, size);
+ }
+ m_valueSet = true;
+} // NimBLEUUID
+
+
+/**
+ * @brief Create a UUID from the 16bit value.
+ * @param [in] uuid The 16bit short form UUID.
+ */
+NimBLEUUID::NimBLEUUID(uint16_t uuid) {
+ m_uuid.u.type = BLE_UUID_TYPE_16;
+ m_uuid.u16.value = uuid;
+ m_valueSet = true;
+} // NimBLEUUID
+
+
+/**
+ * @brief Create a UUID from the 32bit value.
+ * @param [in] uuid The 32bit short form UUID.
+ */
+NimBLEUUID::NimBLEUUID(uint32_t uuid) {
+ m_uuid.u.type = BLE_UUID_TYPE_32;
+ m_uuid.u32.value = uuid;
+ m_valueSet = true;
+} // NimBLEUUID
+
+
+/**
+ * @brief Create a UUID from the native UUID.
+ * @param [in] uuid The native UUID.
+ */
+NimBLEUUID::NimBLEUUID(const ble_uuid128_t* uuid) {
+ m_uuid.u.type = BLE_UUID_TYPE_128;
+ memcpy(m_uuid.u128.value, uuid->value, 16);
+ m_valueSet = true;
+} // NimBLEUUID
+
+
+/**
+ * @brief Create a UUID from the 128bit value using hex parts instead of string,
+ * instead of NimBLEUUID("ebe0ccb0-7a0a-4b0c-8a1a-6ff2997da3a6"), it becomes
+ * NimBLEUUID(0xebe0ccb0, 0x7a0a, 0x4b0c, 0x8a1a6ff2997da3a6)
+ *
+ * @param [in] first The first 32bit of the UUID.
+ * @param [in] second The next 16bit of the UUID.
+ * @param [in] third The next 16bit of the UUID.
+ * @param [in] fourth The last 64bit of the UUID, combining the last 2 parts of the string equivalent
+ */
+NimBLEUUID::NimBLEUUID(uint32_t first, uint16_t second, uint16_t third, uint64_t fourth) {
+ m_uuid.u.type = BLE_UUID_TYPE_128;
+ memcpy(m_uuid.u128.value + 12, &first, 4);
+ memcpy(m_uuid.u128.value + 10, &second, 2);
+ memcpy(m_uuid.u128.value + 8, &third, 2);
+ memcpy(m_uuid.u128.value, &fourth, 8);
+ m_valueSet = true;
+}
+
+
+/**
+ * @brief Creates an empty UUID.
+ */
+NimBLEUUID::NimBLEUUID() {
+ m_valueSet = false;
+} // NimBLEUUID
+
+
+/**
+ * @brief Get the number of bits in this uuid.
+ * @return The number of bits in the UUID. One of 16, 32 or 128.
+ */
+uint8_t NimBLEUUID::bitSize() const {
+ if (!m_valueSet) return 0;
+ return m_uuid.u.type;
+} // bitSize
+
+
+/**
+ * @brief Compare a UUID against this UUID.
+ *
+ * @param [in] uuid The UUID to compare against.
+ * @return True if the UUIDs are equal and false otherwise.
+ */
+bool NimBLEUUID::equals(const NimBLEUUID &uuid) const {
+ return *this == uuid;
+}
+
+
+/**
+ * Create a NimBLEUUID from a string of the form:
+ * 0xNNNN
+ * 0xNNNNNNNN
+ * 0x
+ * NNNN
+ * NNNNNNNN
+ *
+ *
+ * @param [in] uuid The string to create the UUID from.
+ */
+NimBLEUUID NimBLEUUID::fromString(const std::string &uuid) {
+ uint8_t start = 0;
+ if (strstr(uuid.c_str(), "0x") != nullptr) { // If the string starts with 0x, skip those characters.
+ start = 2;
+ }
+ uint8_t len = uuid.length() - start; // Calculate the length of the string we are going to use.
+
+ if(len == 4) {
+ uint16_t x = strtoul(uuid.substr(start, len).c_str(), NULL, 16);
+ return NimBLEUUID(x);
+ } else if (len == 8) {
+ uint32_t x = strtoul(uuid.substr(start, len).c_str(), NULL, 16);
+ return NimBLEUUID(x);
+ } else if (len == 36) {
+ return NimBLEUUID(uuid);
+ }
+ return NimBLEUUID();
+} // fromString
+
+
+/**
+ * @brief Get the native UUID value.
+ * @return The native UUID value or nullptr if not set.
+ */
+const ble_uuid_any_t* NimBLEUUID::getNative() const {
+ if (m_valueSet == false) {
+ NIMBLE_LOGD(LOG_TAG,"<< Return of un-initialized UUID!");
+ return nullptr;
+ }
+ return &m_uuid;
+} // getNative
+
+
+/**
+ * @brief Convert a UUID to its 128 bit representation.
+ * @details A UUID can be internally represented as 16bit, 32bit or the full 128bit.
+ * This method will convert 16 or 32bit representations to the full 128bit.
+ * @return The NimBLEUUID converted to 128bit.
+ */
+const NimBLEUUID &NimBLEUUID::to128() {
+ // If we either don't have a value or are already a 128 bit UUID, nothing further to do.
+ if (!m_valueSet || m_uuid.u.type == BLE_UUID_TYPE_128) {
+ return *this;
+ }
+
+ // If we are 16 bit or 32 bit, then set the other bytes of the UUID.
+ if (m_uuid.u.type == BLE_UUID_TYPE_16) {
+ *this = NimBLEUUID(m_uuid.u16.value, 0x0000, 0x1000, 0x800000805f9b34fb);
+ }
+ else if (m_uuid.u.type == BLE_UUID_TYPE_32) {
+ *this = NimBLEUUID(m_uuid.u32.value, 0x0000, 0x1000, 0x800000805f9b34fb);
+ }
+
+ return *this;
+} // to128
+
+
+/**
+ * @brief Convert 128 bit UUID to its 16 bit representation.
+ * @details A UUID can be internally represented as 16bit, 32bit or the full 128bit.
+ * This method will convert a 128bit uuid to 16bit if it contains the ble base uuid.
+ * @return The NimBLEUUID converted to 16bit if successful, otherwise the original uuid.
+ */
+const NimBLEUUID& NimBLEUUID::to16() {
+ if (!m_valueSet || m_uuid.u.type == BLE_UUID_TYPE_16) {
+ return *this;
+ }
+
+ if (m_uuid.u.type == BLE_UUID_TYPE_128) {
+ uint8_t base128[] = {0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00,
+ 0x00, 0x80, 0x00, 0x10, 0x00, 0x00};
+ if (memcmp(m_uuid.u128.value, base128, sizeof(base128)) == 0 ) {
+ *this = NimBLEUUID(*(uint16_t*)(m_uuid.u128.value + 12));
+ }
+ }
+
+ return *this;
+}
+
+
+/**
+ * @brief Get a string representation of the UUID.
+ * @details
+ * The format of a string is:
+ * 01234567 8901 2345 6789 012345678901
+ * 0000180d-0000-1000-8000-00805f9b34fb
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ *
+ * @return A string representation of the UUID.
+ * @deprecated Use std::string() operator instead.
+ */
+std::string NimBLEUUID::toString() const {
+ return std::string(*this);
+} // toString
+
+
+/**
+ * @brief Convienience operator to check if this UUID is equal to another.
+ */
+bool NimBLEUUID::operator ==(const NimBLEUUID & rhs) const {
+ if(m_valueSet && rhs.m_valueSet) {
+ if(m_uuid.u.type != rhs.m_uuid.u.type) {
+ uint8_t uuidBase[16] = {
+ 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+
+ if(m_uuid.u.type == BLE_UUID_TYPE_128){
+ if(rhs.m_uuid.u.type == BLE_UUID_TYPE_16){
+ memcpy(uuidBase+12, &rhs.m_uuid.u16.value, 2);
+ } else if (rhs.m_uuid.u.type == BLE_UUID_TYPE_32){
+ memcpy(uuidBase+12, &rhs.m_uuid.u32.value, 4);
+ }
+ return memcmp(m_uuid.u128.value,uuidBase,16) == 0;
+
+ } else if(rhs.m_uuid.u.type == BLE_UUID_TYPE_128) {
+ if(m_uuid.u.type == BLE_UUID_TYPE_16){
+ memcpy(uuidBase+12, &m_uuid.u16.value, 2);
+ } else if (m_uuid.u.type == BLE_UUID_TYPE_32){
+ memcpy(uuidBase+12, &m_uuid.u32.value, 4);
+ }
+ return memcmp(rhs.m_uuid.u128.value,uuidBase,16) == 0;
+
+ } else {
+ return false;
+ }
+ }
+
+ return ble_uuid_cmp(&m_uuid.u, &rhs.m_uuid.u) == 0;
+ }
+
+ return m_valueSet == rhs.m_valueSet;
+}
+
+
+/**
+ * @brief Convienience operator to check if this UUID is not equal to another.
+ */
+bool NimBLEUUID::operator !=(const NimBLEUUID & rhs) const {
+ return !this->operator==(rhs);
+}
+
+
+/**
+ * @brief Convienience operator to convert this UUID to string representation.
+ * @details This allows passing NimBLEUUID to functions
+ * that accept std::string and/or or it's methods as a parameter.
+ */
+NimBLEUUID::operator std::string() const {
+ if (!m_valueSet) return std::string(); // If we have no value, nothing to format.
+
+ char buf[BLE_UUID_STR_LEN];
+
+ return ble_uuid_to_str(&m_uuid.u, buf);
+}
+
+
+#endif /* CONFIG_BT_ENABLED */
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/NimBLEUUID.h b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEUUID.h
new file mode 100644
index 0000000..2c24971
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEUUID.h
@@ -0,0 +1,64 @@
+/*
+ * NimBLEUUID.h
+ *
+ * Created: on Jan 24 2020
+ * Author H2zero
+ *
+ * Originally:
+ *
+ * BLEUUID.h
+ *
+ * Created on: Jun 21, 2017
+ * Author: kolban
+ */
+
+#ifndef COMPONENTS_NIMBLEUUID_H_
+#define COMPONENTS_NIMBLEUUID_H_
+
+#include "nimconfig.h"
+#if defined(CONFIG_BT_ENABLED)
+
+#if defined(CONFIG_NIMBLE_CPP_IDF)
+#include "host/ble_uuid.h"
+#else
+#include "nimble/nimble/host/include/host/ble_uuid.h"
+#endif
+
+/**** FIX COMPILATION ****/
+#undef min
+#undef max
+/**************************/
+
+#include
+
+/**
+ * @brief A model of a %BLE UUID.
+ */
+class NimBLEUUID {
+public:
+ NimBLEUUID(const std::string &uuid);
+ NimBLEUUID(uint16_t uuid);
+ NimBLEUUID(uint32_t uuid);
+ NimBLEUUID(const ble_uuid128_t* uuid);
+ NimBLEUUID(const uint8_t* pData, size_t size, bool msbFirst);
+ NimBLEUUID(uint32_t first, uint16_t second, uint16_t third, uint64_t fourth);
+ NimBLEUUID();
+
+ uint8_t bitSize() const;
+ bool equals(const NimBLEUUID &uuid) const;
+ const ble_uuid_any_t* getNative() const;
+ const NimBLEUUID & to128();
+ const NimBLEUUID& to16();
+ std::string toString() const;
+ static NimBLEUUID fromString(const std::string &uuid);
+
+ bool operator ==(const NimBLEUUID & rhs) const;
+ bool operator !=(const NimBLEUUID & rhs) const;
+ operator std::string() const;
+
+private:
+ ble_uuid_any_t m_uuid;
+ bool m_valueSet = false;
+}; // NimBLEUUID
+#endif /* CONFIG_BT_ENABLED */
+#endif /* COMPONENTS_NIMBLEUUID_H_ */
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/NimBLEUtils.cpp b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEUtils.cpp
new file mode 100644
index 0000000..c6bd823
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEUtils.cpp
@@ -0,0 +1,518 @@
+/*
+ * NimBLEUtils.cpp
+ *
+ * Created: on Jan 25 2020
+ * Author H2zero
+ *
+ */
+
+#include "nimconfig.h"
+#if defined(CONFIG_BT_ENABLED)
+
+#include "NimBLEUtils.h"
+#include "NimBLELog.h"
+
+#include
+
+static const char* LOG_TAG = "NimBLEUtils";
+
+
+/**
+ * @brief A function for checking validity of connection parameters.
+ * @param [in] params A pointer to the structure containing the parameters to check.
+ * @return valid == 0 or error code.
+ */
+int NimBLEUtils::checkConnParams(ble_gap_conn_params* params) {
+ /* Check connection interval min */
+ if ((params->itvl_min < BLE_HCI_CONN_ITVL_MIN) ||
+ (params->itvl_min > BLE_HCI_CONN_ITVL_MAX)) {
+ return BLE_ERR_INV_HCI_CMD_PARMS;
+ }
+ /* Check connection interval max */
+ if ((params->itvl_max < BLE_HCI_CONN_ITVL_MIN) ||
+ (params->itvl_max > BLE_HCI_CONN_ITVL_MAX) ||
+ (params->itvl_max < params->itvl_min)) {
+ return BLE_ERR_INV_HCI_CMD_PARMS;
+ }
+
+ /* Check connection latency */
+ if (params->latency > BLE_HCI_CONN_LATENCY_MAX) {
+ return BLE_ERR_INV_HCI_CMD_PARMS;
+ }
+
+ /* Check supervision timeout */
+ if ((params->supervision_timeout < BLE_HCI_CONN_SPVN_TIMEOUT_MIN) ||
+ (params->supervision_timeout > BLE_HCI_CONN_SPVN_TIMEOUT_MAX)) {
+ return BLE_ERR_INV_HCI_CMD_PARMS;
+ }
+
+ /* Check connection event length */
+ if (params->min_ce_len > params->max_ce_len) {
+ return BLE_ERR_INV_HCI_CMD_PARMS;
+ }
+
+ return 0;
+}
+
+
+/**
+ * @brief Converts a return code from the NimBLE stack to a text string.
+ * @param [in] rc The return code to convert.
+ * @return A string representation of the return code.
+ */
+const char* NimBLEUtils::returnCodeToString(int rc) {
+#if defined(CONFIG_NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT)
+ switch(rc) {
+ case 0:
+ return "SUCCESS";
+ case BLE_HS_EAGAIN:
+ return "Temporary failure; try again.";
+ case BLE_HS_EALREADY:
+ return "Operation already in progress or completed.";
+ case BLE_HS_EINVAL:
+ return "One or more arguments are invalid.";
+ case BLE_HS_EMSGSIZE:
+ return "The provided buffer is too small.";
+ case BLE_HS_ENOENT:
+ return "No entry matching the specified criteria.";
+ case BLE_HS_ENOMEM:
+ return "Operation failed due to resource exhaustion.";
+ case BLE_HS_ENOTCONN:
+ return "No open connection with the specified handle.";
+ case BLE_HS_ENOTSUP:
+ return "Operation disabled at compile time.";
+ case BLE_HS_EAPP:
+ return "Application callback behaved unexpectedly.";
+ case BLE_HS_EBADDATA:
+ return "Command from peer is invalid.";
+ case BLE_HS_EOS:
+ return "Mynewt OS error.";
+ case BLE_HS_ECONTROLLER:
+ return "Event from controller is invalid.";
+ case BLE_HS_ETIMEOUT:
+ return "Operation timed out.";
+ case BLE_HS_EDONE:
+ return "Operation completed successfully.";
+ case BLE_HS_EBUSY:
+ return "Operation cannot be performed until procedure completes.";
+ case BLE_HS_EREJECT:
+ return "Peer rejected a connection parameter update request.";
+ case BLE_HS_EUNKNOWN:
+ return "Unexpected failure; catch all.";
+ case BLE_HS_EROLE:
+ return "Operation requires different role (e.g., central vs. peripheral).";
+ case BLE_HS_ETIMEOUT_HCI:
+ return "HCI request timed out; controller unresponsive.";
+ case BLE_HS_ENOMEM_EVT:
+ return "Controller failed to send event due to memory exhaustion (combined host-controller only).";
+ case BLE_HS_ENOADDR:
+ return "Operation requires an identity address but none configured.";
+ case BLE_HS_ENOTSYNCED:
+ return "Attempt to use the host before it is synced with controller.";
+ case BLE_HS_EAUTHEN:
+ return "Insufficient authentication.";
+ case BLE_HS_EAUTHOR:
+ return "Insufficient authorization.";
+ case BLE_HS_EENCRYPT:
+ return "Insufficient encryption level.";
+ case BLE_HS_EENCRYPT_KEY_SZ:
+ return "Insufficient key size.";
+ case BLE_HS_ESTORE_CAP:
+ return "Storage at capacity.";
+ case BLE_HS_ESTORE_FAIL:
+ return "Storage IO error.";
+ case (0x0100+BLE_ATT_ERR_INVALID_HANDLE ):
+ return "The attribute handle given was not valid on this server.";
+ case (0x0100+BLE_ATT_ERR_READ_NOT_PERMITTED ):
+ return "The attribute cannot be read.";
+ case (0x0100+BLE_ATT_ERR_WRITE_NOT_PERMITTED ):
+ return "The attribute cannot be written.";
+ case (0x0100+BLE_ATT_ERR_INVALID_PDU ):
+ return "The attribute PDU was invalid.";
+ case (0x0100+BLE_ATT_ERR_INSUFFICIENT_AUTHEN ):
+ return "The attribute requires authentication before it can be read or written.";
+ case (0x0100+BLE_ATT_ERR_REQ_NOT_SUPPORTED ):
+ return "Attribute server does not support the request received from the client.";
+ case (0x0100+BLE_ATT_ERR_INVALID_OFFSET ):
+ return "Offset specified was past the end of the attribute.";
+ case (0x0100+BLE_ATT_ERR_INSUFFICIENT_AUTHOR ):
+ return "The attribute requires authorization before it can be read or written.";
+ case (0x0100+BLE_ATT_ERR_PREPARE_QUEUE_FULL ):
+ return "Too many prepare writes have been queued.";
+ case (0x0100+BLE_ATT_ERR_ATTR_NOT_FOUND ):
+ return "No attribute found within the given attribute handle range.";
+ case (0x0100+BLE_ATT_ERR_ATTR_NOT_LONG ):
+ return "The attribute cannot be read or written using the Read Blob Request.";
+ case (0x0100+BLE_ATT_ERR_INSUFFICIENT_KEY_SZ ):
+ return "The Encryption Key Size used for encrypting this link is insufficient.";
+ case (0x0100+BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN ):
+ return "The attribute value length is invalid for the operation.";
+ case (0x0100+BLE_ATT_ERR_UNLIKELY ):
+ return "The attribute request has encountered an error that was unlikely, could not be completed as requested.";
+ case (0x0100+BLE_ATT_ERR_INSUFFICIENT_ENC ):
+ return "The attribute requires encryption before it can be read or written.";
+ case (0x0100+BLE_ATT_ERR_UNSUPPORTED_GROUP ):
+ return "The attribute type is not a supported grouping attribute as defined by a higher layer specification.";
+ case (0x0100+BLE_ATT_ERR_INSUFFICIENT_RES ):
+ return "Insufficient Resources to complete the request.";
+ case (0x0200+BLE_ERR_UNKNOWN_HCI_CMD ):
+ return "Unknown HCI Command";
+ case (0x0200+BLE_ERR_UNK_CONN_ID ):
+ return "Unknown Connection Identifier";
+ case (0x0200+BLE_ERR_HW_FAIL ):
+ return "Hardware Failure";
+ case (0x0200+BLE_ERR_PAGE_TMO ):
+ return "Page Timeout";
+ case (0x0200+BLE_ERR_AUTH_FAIL ):
+ return "Authentication Failure";
+ case (0x0200+BLE_ERR_PINKEY_MISSING ):
+ return "PIN or Key Missing";
+ case (0x0200+BLE_ERR_MEM_CAPACITY ):
+ return "Memory Capacity Exceeded";
+ case (0x0200+BLE_ERR_CONN_SPVN_TMO ):
+ return "Connection Timeout";
+ case (0x0200+BLE_ERR_CONN_LIMIT ):
+ return "Connection Limit Exceeded";
+ case (0x0200+BLE_ERR_SYNCH_CONN_LIMIT ):
+ return "Synchronous Connection Limit To A Device Exceeded";
+ case (0x0200+BLE_ERR_ACL_CONN_EXISTS ):
+ return "ACL Connection Already Exists";
+ case (0x0200+BLE_ERR_CMD_DISALLOWED ):
+ return "Command Disallowed";
+ case (0x0200+BLE_ERR_CONN_REJ_RESOURCES ):
+ return "Connection Rejected due to Limited Resources";
+ case (0x0200+BLE_ERR_CONN_REJ_SECURITY ):
+ return "Connection Rejected Due To Security Reasons";
+ case (0x0200+BLE_ERR_CONN_REJ_BD_ADDR ):
+ return "Connection Rejected due to Unacceptable BD_ADDR";
+ case (0x0200+BLE_ERR_CONN_ACCEPT_TMO ):
+ return "Connection Accept Timeout Exceeded";
+ case (0x0200+BLE_ERR_UNSUPPORTED ):
+ return "Unsupported Feature or Parameter Value";
+ case (0x0200+BLE_ERR_INV_HCI_CMD_PARMS ):
+ return "Invalid HCI Command Parameters";
+ case (0x0200+BLE_ERR_REM_USER_CONN_TERM ):
+ return "Remote User Terminated Connection";
+ case (0x0200+BLE_ERR_RD_CONN_TERM_RESRCS ):
+ return "Remote Device Terminated Connection due to Low Resources";
+ case (0x0200+BLE_ERR_RD_CONN_TERM_PWROFF ):
+ return "Remote Device Terminated Connection due to Power Off";
+ case (0x0200+BLE_ERR_CONN_TERM_LOCAL ):
+ return "Connection Terminated By Local Host";
+ case (0x0200+BLE_ERR_REPEATED_ATTEMPTS ):
+ return "Repeated Attempts";
+ case (0x0200+BLE_ERR_NO_PAIRING ):
+ return "Pairing Not Allowed";
+ case (0x0200+BLE_ERR_UNK_LMP ):
+ return "Unknown LMP PDU";
+ case (0x0200+BLE_ERR_UNSUPP_REM_FEATURE ):
+ return "Unsupported Remote Feature / Unsupported LMP Feature";
+ case (0x0200+BLE_ERR_SCO_OFFSET ):
+ return "SCO Offset Rejected";
+ case (0x0200+BLE_ERR_SCO_ITVL ):
+ return "SCO Interval Rejected";
+ case (0x0200+BLE_ERR_SCO_AIR_MODE ):
+ return "SCO Air Mode Rejected";
+ case (0x0200+BLE_ERR_INV_LMP_LL_PARM ):
+ return "Invalid LMP Parameters / Invalid LL Parameters";
+ case (0x0200+BLE_ERR_UNSPECIFIED ):
+ return "Unspecified Error";
+ case (0x0200+BLE_ERR_UNSUPP_LMP_LL_PARM ):
+ return "Unsupported LMP Parameter Value / Unsupported LL Parameter Value";
+ case (0x0200+BLE_ERR_NO_ROLE_CHANGE ):
+ return "Role Change Not Allowed";
+ case (0x0200+BLE_ERR_LMP_LL_RSP_TMO ):
+ return "LMP Response Timeout / LL Response Timeout";
+ case (0x0200+BLE_ERR_LMP_COLLISION ):
+ return "LMP Error Transaction Collision";
+ case (0x0200+BLE_ERR_LMP_PDU ):
+ return "LMP PDU Not Allowed";
+ case (0x0200+BLE_ERR_ENCRYPTION_MODE ):
+ return "Encryption Mode Not Acceptable";
+ case (0x0200+BLE_ERR_LINK_KEY_CHANGE ):
+ return "Link Key cannot be Changed";
+ case (0x0200+BLE_ERR_UNSUPP_QOS ):
+ return "Requested QoS Not Supported";
+ case (0x0200+BLE_ERR_INSTANT_PASSED ):
+ return "Instant Passed";
+ case (0x0200+BLE_ERR_UNIT_KEY_PAIRING ):
+ return "Pairing With Unit Key Not Supported";
+ case (0x0200+BLE_ERR_DIFF_TRANS_COLL ):
+ return "Different Transaction Collision";
+ case (0x0200+BLE_ERR_QOS_PARM ):
+ return "QoS Unacceptable Parameter";
+ case (0x0200+BLE_ERR_QOS_REJECTED ):
+ return "QoS Rejected";
+ case (0x0200+BLE_ERR_CHAN_CLASS ):
+ return "Channel Classification Not Supported";
+ case (0x0200+BLE_ERR_INSUFFICIENT_SEC ):
+ return "Insufficient Security";
+ case (0x0200+BLE_ERR_PARM_OUT_OF_RANGE ):
+ return "Parameter Out Of Mandatory Range";
+ case (0x0200+BLE_ERR_PENDING_ROLE_SW ):
+ return "Role Switch Pending";
+ case (0x0200+BLE_ERR_RESERVED_SLOT ):
+ return "Reserved Slot Violation";
+ case (0x0200+BLE_ERR_ROLE_SW_FAIL ):
+ return "Role Switch Failed";
+ case (0x0200+BLE_ERR_INQ_RSP_TOO_BIG ):
+ return "Extended Inquiry Response Too Large";
+ case (0x0200+BLE_ERR_SEC_SIMPLE_PAIR ):
+ return "Secure Simple Pairing Not Supported By Host";
+ case (0x0200+BLE_ERR_HOST_BUSY_PAIR ):
+ return "Host Busy - Pairing";
+ case (0x0200+BLE_ERR_CONN_REJ_CHANNEL ):
+ return "Connection Rejected, No Suitable Channel Found";
+ case (0x0200+BLE_ERR_CTLR_BUSY ):
+ return "Controller Busy";
+ case (0x0200+BLE_ERR_CONN_PARMS ):
+ return "Unacceptable Connection Parameters";
+ case (0x0200+BLE_ERR_DIR_ADV_TMO ):
+ return "Directed Advertising Timeout";
+ case (0x0200+BLE_ERR_CONN_TERM_MIC ):
+ return "Connection Terminated due to MIC Failure";
+ case (0x0200+BLE_ERR_CONN_ESTABLISHMENT ):
+ return "Connection Failed to be Established";
+ case (0x0200+BLE_ERR_MAC_CONN_FAIL ):
+ return "MAC Connection Failed";
+ case (0x0200+BLE_ERR_COARSE_CLK_ADJ ):
+ return "Coarse Clock Adjustment Rejected";
+ case (0x0300+BLE_L2CAP_SIG_ERR_CMD_NOT_UNDERSTOOD ):
+ return "Invalid or unsupported incoming L2CAP sig command.";
+ case (0x0300+BLE_L2CAP_SIG_ERR_MTU_EXCEEDED ):
+ return "Incoming packet too large.";
+ case (0x0300+BLE_L2CAP_SIG_ERR_INVALID_CID ):
+ return "No channel with specified ID.";
+ case (0x0400+BLE_SM_ERR_PASSKEY ):
+ return "The user input of passkey failed, for example, the user cancelled the operation.";
+ case (0x0400+BLE_SM_ERR_OOB ):
+ return "The OOB data is not available.";
+ case (0x0400+BLE_SM_ERR_AUTHREQ ):
+ return "The pairing procedure cannot be performed as authentication requirements cannot be met due to IO capabilities of one or both devices.";
+ case (0x0400+BLE_SM_ERR_CONFIRM_MISMATCH ):
+ return "The confirm value does not match the calculated compare value.";
+ case (0x0400+BLE_SM_ERR_PAIR_NOT_SUPP ):
+ return "Pairing is not supported by the device.";
+ case (0x0400+BLE_SM_ERR_ENC_KEY_SZ ):
+ return "The resultant encryption key size is insufficient for the security requirements of this device.";
+ case (0x0400+BLE_SM_ERR_CMD_NOT_SUPP ):
+ return "The SMP command received is not supported on this device.";
+ case (0x0400+BLE_SM_ERR_UNSPECIFIED ):
+ return "Pairing failed due to an unspecified reason.";
+ case (0x0400+BLE_SM_ERR_REPEATED ):
+ return "Pairing or authentication procedure disallowed, too little time has elapsed since last pairing request or security request.";
+ case (0x0400+BLE_SM_ERR_INVAL ):
+ return "Command length is invalid or that a parameter is outside of the specified range.";
+ case (0x0400+BLE_SM_ERR_DHKEY ):
+ return "DHKey Check value received doesn't match the one calculated by the local device.";
+ case (0x0400+BLE_SM_ERR_NUMCMP ):
+ return "Confirm values in the numeric comparison protocol do not match.";
+ case (0x0400+BLE_SM_ERR_ALREADY ):
+ return "Pairing over the LE transport failed - Pairing Request sent over the BR/EDR transport in process.";
+ case (0x0400+BLE_SM_ERR_CROSS_TRANS ):
+ return "BR/EDR Link Key generated on the BR/EDR transport cannot be used to derive and distribute keys for the LE transport.";
+ case (0x0500+BLE_SM_ERR_PASSKEY ):
+ return "The user input of passkey failed or the user cancelled the operation.";
+ case (0x0500+BLE_SM_ERR_OOB ):
+ return "The OOB data is not available.";
+ case (0x0500+BLE_SM_ERR_AUTHREQ ):
+ return "The pairing procedure cannot be performed as authentication requirements cannot be met due to IO capabilities of one or both devices.";
+ case (0x0500+BLE_SM_ERR_CONFIRM_MISMATCH ):
+ return "The confirm value does not match the calculated compare value.";
+ case (0x0500+BLE_SM_ERR_PAIR_NOT_SUPP ):
+ return "Pairing is not supported by the device.";
+ case (0x0500+BLE_SM_ERR_ENC_KEY_SZ ):
+ return "The resultant encryption key size is insufficient for the security requirements of this device.";
+ case (0x0500+BLE_SM_ERR_CMD_NOT_SUPP ):
+ return "The SMP command received is not supported on this device.";
+ case (0x0500+BLE_SM_ERR_UNSPECIFIED ):
+ return "Pairing failed due to an unspecified reason.";
+ case (0x0500+BLE_SM_ERR_REPEATED ):
+ return "Pairing or authentication procedure is disallowed because too little time has elapsed since last pairing request or security request.";
+ case (0x0500+BLE_SM_ERR_INVAL ):
+ return "Command length is invalid or a parameter is outside of the specified range.";
+ case (0x0500+BLE_SM_ERR_DHKEY ):
+ return "Indicates to the remote device that the DHKey Check value received doesn’t match the one calculated by the local device.";
+ case (0x0500+BLE_SM_ERR_NUMCMP ):
+ return "Confirm values in the numeric comparison protocol do not match.";
+ case (0x0500+BLE_SM_ERR_ALREADY ):
+ return "Pairing over the LE transport failed - Pairing Request sent over the BR/EDR transport in process.";
+ case (0x0500+BLE_SM_ERR_CROSS_TRANS ):
+ return "BR/EDR Link Key generated on the BR/EDR transport cannot be used to derive and distribute keys for the LE transport.";
+ default:
+ return "Unknown";
+ }
+#else // #if defined(CONFIG_NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT)
+ (void)rc;
+ return "";
+#endif // #if defined(CONFIG_NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT)
+}
+
+
+/**
+ * @brief Convert the advertising type flag to a string.
+ * @param advType The type to convert.
+ * @return A string representation of the advertising flags.
+ */
+const char* NimBLEUtils::advTypeToString(uint8_t advType) {
+#if defined(CONFIG_NIMBLE_CPP_ENABLE_ADVERTISMENT_TYPE_TEXT)
+ switch(advType) {
+ case BLE_HCI_ADV_TYPE_ADV_IND : //0
+ return "Undirected - Connectable / Scannable";
+ case BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD: //1
+ return "Directed High Duty - Connectable";
+ case BLE_HCI_ADV_TYPE_ADV_SCAN_IND: //2
+ return "Non-Connectable - Scan Response Available";
+ case BLE_HCI_ADV_TYPE_ADV_NONCONN_IND: //3
+ return "Non-Connectable - No Scan Response";
+ case BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_LD: //4
+ return "Directed Low Duty - Connectable";
+ default:
+ return "Unknown flag";
+ }
+#else // #if defined(CONFIG_NIMBLE_CPP_ENABLE_ADVERTISMENT_TYPE_TEXT)
+ (void)advType;
+ return "";
+#endif // #if defined(CONFIG_NIMBLE_CPP_ENABLE_ADVERTISMENT_TYPE_TEXT)
+} // adFlagsToString
+
+
+/**
+ * @brief Create a hex representation of data.
+ *
+ * @param [in] target Where to write the hex string. If this is null, we malloc storage.
+ * @param [in] source The start of the binary data.
+ * @param [in] length The length of the data to convert.
+ * @return A pointer to the formatted buffer.
+ */
+char* NimBLEUtils::buildHexData(uint8_t* target, const uint8_t* source, uint8_t length) {
+ // Guard against too much data.
+ if (length > 100) length = 100;
+
+ if (target == nullptr) {
+ target = (uint8_t*) malloc(length * 2 + 1);
+ if (target == nullptr) {
+ NIMBLE_LOGE(LOG_TAG, "buildHexData: malloc failed");
+ return nullptr;
+ }
+ }
+ char* startOfData = (char*) target;
+
+ for (int i = 0; i < length; i++) {
+ sprintf((char*) target, "%.2x", (char) *source);
+ source++;
+ target += 2;
+ }
+
+ // Handle the special case where there was no data.
+ if (length == 0) {
+ *startOfData = 0;
+ }
+
+ return startOfData;
+} // buildHexData
+
+
+/**
+ * @brief Utility function to log the gap event info.
+ * @param [in] event A pointer to the gap event structure.
+ * @param [in] arg Unused.
+ */
+void NimBLEUtils::dumpGapEvent(ble_gap_event *event, void *arg){
+ (void)arg;
+#if defined(CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT)
+ NIMBLE_LOGD(LOG_TAG, "Received a GAP event: %s", gapEventToString(event->type));
+#else
+ (void)event;
+#endif
+}
+
+
+/**
+ * @brief Convert a GAP event type to a string representation.
+ * @param [in] eventType The type of event.
+ * @return A string representation of the event type.
+ */
+const char* NimBLEUtils::gapEventToString(uint8_t eventType) {
+#if defined(CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT)
+ switch (eventType) {
+ case BLE_GAP_EVENT_CONNECT : //0
+ return "BLE_GAP_EVENT_CONNECT ";
+
+ case BLE_GAP_EVENT_DISCONNECT: //1
+ return "BLE_GAP_EVENT_DISCONNECT";
+
+ case BLE_GAP_EVENT_CONN_UPDATE: //3
+ return "BLE_GAP_EVENT_CONN_UPDATE";
+
+ case BLE_GAP_EVENT_CONN_UPDATE_REQ: //4
+ return "BLE_GAP_EVENT_CONN_UPDATE_REQ";
+
+ case BLE_GAP_EVENT_L2CAP_UPDATE_REQ: //5
+ return "BLE_GAP_EVENT_L2CAP_UPDATE_REQ";
+
+ case BLE_GAP_EVENT_TERM_FAILURE: //6
+ return "BLE_GAP_EVENT_TERM_FAILURE";
+
+ case BLE_GAP_EVENT_DISC: //7
+ return "BLE_GAP_EVENT_DISC";
+
+ case BLE_GAP_EVENT_DISC_COMPLETE: //8
+ return "BLE_GAP_EVENT_DISC_COMPLETE";
+
+ case BLE_GAP_EVENT_ADV_COMPLETE: //9
+ return "BLE_GAP_EVENT_ADV_COMPLETE";
+
+ case BLE_GAP_EVENT_ENC_CHANGE: //10
+ return "BLE_GAP_EVENT_ENC_CHANGE";
+
+ case BLE_GAP_EVENT_PASSKEY_ACTION : //11
+ return "BLE_GAP_EVENT_PASSKEY_ACTION";
+
+ case BLE_GAP_EVENT_NOTIFY_RX: //12
+ return "BLE_GAP_EVENT_NOTIFY_RX";
+
+ case BLE_GAP_EVENT_NOTIFY_TX : //13
+ return "BLE_GAP_EVENT_NOTIFY_TX";
+
+ case BLE_GAP_EVENT_SUBSCRIBE : //14
+ return "BLE_GAP_EVENT_SUBSCRIBE";
+
+ case BLE_GAP_EVENT_MTU: //15
+ return "BLE_GAP_EVENT_MTU";
+
+ case BLE_GAP_EVENT_IDENTITY_RESOLVED: //16
+ return "BLE_GAP_EVENT_IDENTITY_RESOLVED";
+
+ case BLE_GAP_EVENT_REPEAT_PAIRING: //17
+ return "BLE_GAP_EVENT_REPEAT_PAIRING";
+
+ case BLE_GAP_EVENT_PHY_UPDATE_COMPLETE: //18
+ return "BLE_GAP_EVENT_PHY_UPDATE_COMPLETE";
+
+ case BLE_GAP_EVENT_EXT_DISC: //19
+ return "BLE_GAP_EVENT_EXT_DISC";
+#ifdef BLE_GAP_EVENT_PERIODIC_SYNC // IDF 4.0 does not support these
+ case BLE_GAP_EVENT_PERIODIC_SYNC: //20
+ return "BLE_GAP_EVENT_PERIODIC_SYNC";
+
+ case BLE_GAP_EVENT_PERIODIC_REPORT: //21
+ return "BLE_GAP_EVENT_PERIODIC_REPORT";
+
+ case BLE_GAP_EVENT_PERIODIC_SYNC_LOST: //22
+ return "BLE_GAP_EVENT_PERIODIC_SYNC_LOST";
+
+ case BLE_GAP_EVENT_SCAN_REQ_RCVD: //23
+ return "BLE_GAP_EVENT_SCAN_REQ_RCVD";
+#endif
+ default:
+ NIMBLE_LOGD(LOG_TAG, "gapEventToString: Unknown event type %d 0x%.2x", eventType, eventType);
+ return "Unknown event type";
+ }
+#else // #if defined(CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT)
+ (void)eventType;
+ return "";
+#endif // #if defined(CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT)
+} // gapEventToString
+
+#endif //CONFIG_BT_ENABLED
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/NimBLEUtils.h b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEUtils.h
new file mode 100644
index 0000000..2fe4b3c
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/NimBLEUtils.h
@@ -0,0 +1,51 @@
+/*
+ * NimBLEUtils.h
+ *
+ * Created: on Jan 25 2020
+ * Author H2zero
+ *
+ */
+
+#ifndef COMPONENTS_NIMBLEUTILS_H_
+#define COMPONENTS_NIMBLEUTILS_H_
+
+#include "nimconfig.h"
+#if defined(CONFIG_BT_ENABLED)
+
+#if defined(CONFIG_NIMBLE_CPP_IDF)
+#include "host/ble_gap.h"
+#else
+#include "nimble/nimble/host/include/host/ble_gap.h"
+#endif
+
+/**** FIX COMPILATION ****/
+#undef min
+#undef max
+/**************************/
+
+#include
+
+typedef struct {
+ void *pATT;
+ TaskHandle_t task;
+ int rc;
+ std::string *buf;
+} ble_task_data_t;
+
+
+/**
+ * @brief A BLE Utility class with methods for debugging and general purpose use.
+ */
+class NimBLEUtils {
+public:
+ static void dumpGapEvent(ble_gap_event *event, void *arg);
+ static const char* gapEventToString(uint8_t eventType);
+ static char* buildHexData(uint8_t* target, const uint8_t* source, uint8_t length);
+ static const char* advTypeToString(uint8_t advType);
+ static const char* returnCodeToString(int rc);
+ static int checkConnParams(ble_gap_conn_params* params);
+};
+
+
+#endif // CONFIG_BT_ENABLED
+#endif // COMPONENTS_NIMBLEUTILS_H_
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/nimconfig.h b/src/components/esp-nimble-cpp-1.3.3/src/nimconfig.h
new file mode 100644
index 0000000..ea1840a
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/nimconfig.h
@@ -0,0 +1,117 @@
+/** @file
+ *
+ * IGNORE THIS FILE IF USING ESP-IDF, USE MENUCONFIG TO SET NIMBLE OPTIONS.
+ *
+ * The config options here are for doxygen documentation only.
+ */
+
+#pragma once
+
+#include "sdkconfig.h"
+#include "nimconfig_rename.h"
+
+#if defined(CONFIG_BT_ENABLED)
+
+// Allows cpp wrapper to select the correct include paths when using esp-idf
+#define CONFIG_NIMBLE_CPP_IDF
+
+/* Cannot use client without scan */
+#if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL) && !defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
+#define CONFIG_BT_NIMBLE_ROLE_OBSERVER
+#endif
+
+/* Cannot use server without advertise */
+#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) && !defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
+#define CONFIG_BT_NIMBLE_ROLE_BROADCASTER
+#endif
+
+#endif /* CONFIG_BT_ENABLED */
+
+#ifdef _DOXYGEN_
+
+/** @brief Un-comment to change the number of simultaneous connections (esp controller max is 9) */
+#define CONFIG_BT_NIMBLE_MAX_CONNECTIONS 3
+
+/** @brief Un-comment to change the default MTU size */
+#define CONFIG_BT_NIMBLE_ATT_PREFERRED_MTU 255
+
+/** @brief Un-comment to change default device name */
+#define CONFIG_BT_NIMBLE_SVC_GAP_DEVICE_NAME "nimble"
+
+/** @brief Un-comment to set the debug log messages level from the NimBLE host stack.\n
+ * Values: 0 = DEBUG, 1 = INFO, 2 = WARNING, 3 = ERROR, 4 = CRITICAL, 5+ = NONE\n
+ * Uses approx. 32kB of flash memory.
+ */
+#define CONFIG_BT_NIMBLE_LOG_LEVEL 5
+
+/** @brief Un-comment to set the debug log messages level from the NimBLE CPP Wrapper.\n
+ * Values: 0 = NONE, 1 = ERROR, 2 = WARNING, 3 = INFO, 4+ = DEBUG\n
+ * Uses approx. 32kB of flash memory.
+ */
+#define CONFIG_NIMBLE_CPP_LOG_LEVEL 0
+
+/** @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
+
+/** @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
+
+/** @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 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
+
+#endif // _DOXYGEN_
diff --git a/src/components/esp-nimble-cpp-1.3.3/src/nimconfig_rename.h b/src/components/esp-nimble-cpp-1.3.3/src/nimconfig_rename.h
new file mode 100644
index 0000000..c45aa8b
--- /dev/null
+++ b/src/components/esp-nimble-cpp-1.3.3/src/nimconfig_rename.h
@@ -0,0 +1,61 @@
+/*
+ * 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_BT_CTRL_SCAN_DUPL_TYPE) && !defined(CONFIG_BTDM_SCAN_DUPL_TYPE)
+#define CONFIG_BTDM_SCAN_DUPL_TYPE CONFIG_BT_CTRL_SCAN_DUPL_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_BT_CTRL_SCAN_DUPL_CACHE_SIZE) && !defined(CONFIG_BTDM_SCAN_DUPL_CACHE_SIZE)
+#define CONFIG_BTDM_SCAN_DUPL_CACHE_SIZE CONFIG_BT_CTRL_SCAN_DUPL_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
diff --git a/src/main/CMakeLists.txt b/src/main/CMakeLists.txt
new file mode 100644
index 0000000..bd7253a
--- /dev/null
+++ b/src/main/CMakeLists.txt
@@ -0,0 +1,8 @@
+# Edit following two lines to set component requirements (see docs)
+set(COMPONENT_REQUIRES )
+set(COMPONENT_PRIV_REQUIRES )
+
+set(COMPONENT_SRCS "main.cpp")
+set(COMPONENT_ADD_INCLUDEDIRS "")
+
+register_component()
diff --git a/src/main/Kconfig.projbuild b/src/main/Kconfig.projbuild
new file mode 100644
index 0000000..7e23439
--- /dev/null
+++ b/src/main/Kconfig.projbuild
@@ -0,0 +1,14 @@
+# put here your custom config value
+menu "Example Configuration"
+config ESP_WIFI_SSID
+ string "WiFi SSID"
+ default "myssid"
+ help
+ SSID (network name) for the example to connect to.
+
+config ESP_WIFI_PASSWORD
+ string "WiFi Password"
+ default "mypassword"
+ help
+ WiFi password (WPA or WPA2) for the example to use.
+endmenu
diff --git a/src/main/component.mk b/src/main/component.mk
new file mode 100644
index 0000000..61f8990
--- /dev/null
+++ b/src/main/component.mk
@@ -0,0 +1,8 @@
+#
+# Main component makefile.
+#
+# This Makefile can be left empty. By default, it will take the sources in the
+# src/ directory, compile them and link them into lib(subdirectory_name).a
+# in the build directory. This behaviour is entirely configurable,
+# please read the ESP-IDF documents if you need to do this.
+#
diff --git a/src/main/main.cpp b/src/main/main.cpp
new file mode 100644
index 0000000..3201d57
--- /dev/null
+++ b/src/main/main.cpp
@@ -0,0 +1,64 @@
+#include
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "NimBLEDevice.h"
+#include "GPIO_drv.hpp"
+#include "SPI_drv.hpp"
+
+extern "C" {void app_main(void);}
+
+static NimBLEServer* pServer;
+GPIO_drv latch;
+SPI_drv spi;
+std::uint8_t chislo = 0xFF;
+
+// FreeRTOS Task
+void writeToShift(void *pvParameters)
+{
+ (void) pvParameters;
+
+ latch.setLvl(Lvl::reset);
+ spi.transfer(&chislo, 1);
+ latch.setLvl(Lvl::set);
+}
+
+// BLE Callbacks
+class ServerCallbacks: public NimBLEServerCallbacks {
+ void onConnect(NimBLEServer* pServer) {
+ printf("Client connected\n");
+
+ TaskHandle_t xHandle = NULL;
+ xTaskCreate( writeToShift, "SPISHIFT", 128, NULL, 1, &xHandle );
+ if( xHandle != NULL )
+ vTaskDelete(xHandle);
+
+ NimBLEDevice::startAdvertising();
+ };
+
+ void onDisconnect(NimBLEServer* pServer) {
+ printf("Client disconnected - start advertising\n");
+
+ TaskHandle_t xHandle = NULL;
+ xTaskCreate( writeToShift, "SPISHIFT", 128, NULL, 1, &xHandle );
+ if( xHandle != NULL )
+ vTaskDelete(xHandle);
+
+ NimBLEDevice::startAdvertising();
+ };
+};
+
+void app_main(void)
+{
+ // Init Ports
+ latch.init(GPIO_NUM_2, GPIO_MODE_OUTPUT);
+ spi.init(SPI_HOST, 1000000, GPIO_NUM_5);
+
+ //Init Bluetooth
+ NimBLEDevice::init("NimBLE");
+
+ pServer = NimBLEDevice::createServer();
+ pServer->setCallbacks(new ServerCallbacks());
+
+ NimBLEAdvertising* pAdvertising = NimBLEDevice::getAdvertising();
+ pAdvertising->start();
+}