Upload code
This commit is contained in:
parent
39b5588332
commit
5226521aa9
3
src/.gitignore
vendored
Normal file
3
src/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
build/
|
||||||
|
sdkconfig
|
||||||
|
sdkconfig.old
|
6
src/CMakeLists.txt
Normal file
6
src/CMakeLists.txt
Normal file
@ -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)
|
9
src/Makefile
Normal file
9
src/Makefile
Normal file
@ -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
|
||||||
|
|
16
src/components/GPIO_drv/.cproject
Normal file
16
src/components/GPIO_drv/.cproject
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
|
||||||
|
<storageModule moduleId="org.eclipse.cdt.core.settings">
|
||||||
|
<cconfiguration id="org.eclipse.cdt.core.default.config.818362570">
|
||||||
|
<storageModule buildSystemId="org.eclipse.cdt.core.defaultConfigDataProvider" id="org.eclipse.cdt.core.default.config.818362570" moduleId="org.eclipse.cdt.core.settings" name="Configuration">
|
||||||
|
<externalSettings/>
|
||||||
|
<extensions/>
|
||||||
|
</storageModule>
|
||||||
|
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
|
||||||
|
</cconfiguration>
|
||||||
|
</storageModule>
|
||||||
|
<storageModule moduleId="org.eclipse.cdt.core.pathentry">
|
||||||
|
<pathentry excluding="**/CMakeFiles/**" kind="out" path="build"/>
|
||||||
|
</storageModule>
|
||||||
|
<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
|
||||||
|
</cproject>
|
20
src/components/GPIO_drv/.project
Normal file
20
src/components/GPIO_drv/.project
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<projectDescription>
|
||||||
|
<name>GPIO_drv</name>
|
||||||
|
<comment></comment>
|
||||||
|
<projects>
|
||||||
|
</projects>
|
||||||
|
<buildSpec>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.cdt.core.cBuilder</name>
|
||||||
|
<triggers>clean,full,incremental,</triggers>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
</buildSpec>
|
||||||
|
<natures>
|
||||||
|
<nature>org.eclipse.cdt.core.cnature</nature>
|
||||||
|
<nature>org.eclipse.cdt.core.ccnature</nature>
|
||||||
|
<nature>org.eclipse.cdt.cmake.core.cmakeNature</nature>
|
||||||
|
</natures>
|
||||||
|
</projectDescription>
|
3
src/components/GPIO_drv/CMakeLists.txt
Normal file
3
src/components/GPIO_drv/CMakeLists.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
idf_component_register(SRCS "GPIO_drv.cpp"
|
||||||
|
INCLUDE_DIRS "."
|
||||||
|
)
|
48
src/components/GPIO_drv/GPIO_drv.cpp
Normal file
48
src/components/GPIO_drv/GPIO_drv.cpp
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#include "GPIO_drv.hpp"
|
||||||
|
#include <algorithm>
|
||||||
|
#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<std::uint32_t>(lvl));
|
||||||
|
}
|
||||||
|
|
||||||
|
Lvl GPIO_drv::getLvl()
|
||||||
|
{
|
||||||
|
return static_cast<Lvl>(gpio_get_level(button));
|
||||||
|
}
|
32
src/components/GPIO_drv/GPIO_drv.hpp
Normal file
32
src/components/GPIO_drv/GPIO_drv.hpp
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <cstdint>
|
||||||
|
#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;
|
||||||
|
};
|
||||||
|
|
16
src/components/SPI_drv/.cproject
Normal file
16
src/components/SPI_drv/.cproject
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
|
||||||
|
<storageModule moduleId="org.eclipse.cdt.core.settings">
|
||||||
|
<cconfiguration id="org.eclipse.cdt.core.default.config.818362570">
|
||||||
|
<storageModule buildSystemId="org.eclipse.cdt.core.defaultConfigDataProvider" id="org.eclipse.cdt.core.default.config.818362570" moduleId="org.eclipse.cdt.core.settings" name="Configuration">
|
||||||
|
<externalSettings/>
|
||||||
|
<extensions/>
|
||||||
|
</storageModule>
|
||||||
|
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
|
||||||
|
</cconfiguration>
|
||||||
|
</storageModule>
|
||||||
|
<storageModule moduleId="org.eclipse.cdt.core.pathentry">
|
||||||
|
<pathentry excluding="**/CMakeFiles/**" kind="out" path="build"/>
|
||||||
|
</storageModule>
|
||||||
|
<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
|
||||||
|
</cproject>
|
20
src/components/SPI_drv/.project
Normal file
20
src/components/SPI_drv/.project
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<projectDescription>
|
||||||
|
<name>SPI_drv</name>
|
||||||
|
<comment></comment>
|
||||||
|
<projects>
|
||||||
|
</projects>
|
||||||
|
<buildSpec>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.cdt.core.cBuilder</name>
|
||||||
|
<triggers>clean,full,incremental,</triggers>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
</buildSpec>
|
||||||
|
<natures>
|
||||||
|
<nature>org.eclipse.cdt.core.cnature</nature>
|
||||||
|
<nature>org.eclipse.cdt.core.ccnature</nature>
|
||||||
|
<nature>org.eclipse.cdt.cmake.core.cmakeNature</nature>
|
||||||
|
</natures>
|
||||||
|
</projectDescription>
|
4
src/components/SPI_drv/CMakeLists.txt
Normal file
4
src/components/SPI_drv/CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
idf_component_register(SRCS "SPI_drv.cpp"
|
||||||
|
INCLUDE_DIRS "."
|
||||||
|
REQUIRES log
|
||||||
|
)
|
147
src/components/SPI_drv/SPI_drv.cpp
Normal file
147
src/components/SPI_drv/SPI_drv.cpp
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
#include "SPI_drv.hpp"
|
||||||
|
#include <esp_log.h>
|
||||||
|
#include <cstring>
|
||||||
|
//#include <algorithm>
|
||||||
|
|
||||||
|
//#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
|
19
src/components/SPI_drv/SPI_drv.hpp
Normal file
19
src/components/SPI_drv/SPI_drv.hpp
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <cstdint>
|
||||||
|
#include <driver/spi_master.h>
|
||||||
|
#include <driver/gpio.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
251
src/components/esp-nimble-cpp-1.3.3/CHANGELOG.md
Normal file
251
src/components/esp-nimble-cpp-1.3.3/CHANGELOG.md
Normal file
@ -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.
|
58
src/components/esp-nimble-cpp-1.3.3/CMakeLists.txt
Normal file
58
src/components/esp-nimble-cpp-1.3.3/CMakeLists.txt
Normal file
@ -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}
|
||||||
|
)
|
||||||
|
|
56
src/components/esp-nimble-cpp-1.3.3/CMakeLists.txt_idf3
Normal file
56
src/components/esp-nimble-cpp-1.3.3/CMakeLists.txt_idf3
Normal file
@ -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()
|
53
src/components/esp-nimble-cpp-1.3.3/Kconfig
Normal file
53
src/components/esp-nimble-cpp-1.3.3/Kconfig
Normal file
@ -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
|
203
src/components/esp-nimble-cpp-1.3.3/LICENSE
Normal file
203
src/components/esp-nimble-cpp-1.3.3/LICENSE
Normal file
@ -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.
|
70
src/components/esp-nimble-cpp-1.3.3/README.md
Normal file
70
src/components/esp-nimble-cpp-1.3.3/README.md
Normal file
@ -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)
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
# 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*
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
# 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.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
# 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`.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
### 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`.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
# 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/)
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
<br>
|
||||||
|
|
||||||
|
# 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.
|
||||||
|
<br/>
|
||||||
|
|
2
src/components/esp-nimble-cpp-1.3.3/component.mk
Normal file
2
src/components/esp-nimble-cpp-1.3.3/component.mk
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
COMPONENT_ADD_INCLUDEDIRS := src
|
||||||
|
COMPONENT_SRCDIRS := src
|
124
src/components/esp-nimble-cpp-1.3.3/docs/Command_line_config.md
Normal file
124
src/components/esp-nimble-cpp-1.3.3/docs/Command_line_config.md
Normal file
@ -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
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
`CONFIG_BT_NIMBLE_ATT_PREFERRED_MTU`
|
||||||
|
|
||||||
|
Sets the default MTU size.
|
||||||
|
- Default value is 255
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
`CONFIG_BT_NIMBLE_SVC_GAP_DEVICE_NAME`
|
||||||
|
|
||||||
|
Set the default device name
|
||||||
|
- Default value is "nimble"
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
`CONFIG_BT_NIMBLE_DEBUG`
|
||||||
|
|
||||||
|
If defined, enables debug log messages from the NimBLE host
|
||||||
|
- Uses approx. 32kB of flash memory.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
`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
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
`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.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
`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.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
`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.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
`CONFIG_BT_NIMBLE_SVC_GAP_APPEARANCE`
|
||||||
|
|
||||||
|
Set the default appearance.
|
||||||
|
- Default value is 0x00
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
`CONFIG_BT_NIMBLE_ROLE_CENTRAL_DISABLED`
|
||||||
|
|
||||||
|
If defined, NimBLE Client functions will not be included.
|
||||||
|
- Reduces flash size by approx. 7kB.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
`CONFIG_BT_NIMBLE_ROLE_OBSERVER_DISABLED`
|
||||||
|
|
||||||
|
If defined, NimBLE Scan functions will not be included.
|
||||||
|
- Reduces flash size by approx. 26kB.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
`CONFIG_BT_NIMBLE_ROLE_PERIPHERAL_DISABLED`
|
||||||
|
|
||||||
|
If defined NimBLE Server functions will not be included.
|
||||||
|
- Reduces flash size by approx. 16kB.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
`CONFIG_BT_NIMBLE_ROLE_BROADCASTER_DISABLED`
|
||||||
|
|
||||||
|
If defined, NimBLE Advertising functions will not be included.
|
||||||
|
- Reduces flash size by approx. 5kB.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
`CONFIG_BT_NIMBLE_MAX_BONDS`
|
||||||
|
|
||||||
|
Sets the number of devices allowed to store/bond with
|
||||||
|
- Default value is 3
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
`CONFIG_BT_NIMBLE_MAX_CCCDS`
|
||||||
|
|
||||||
|
Sets the maximum number of CCCD subscriptions to store
|
||||||
|
- Default value is 8
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
`CONFIG_BT_NIMBLE_RPA_TIMEOUT`
|
||||||
|
|
||||||
|
Sets the random address refresh time in seconds.
|
||||||
|
- Default value is 900
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
`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
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
`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
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
`CONFIG_BT_NIMBLE_PINNED_TO_CORE`
|
||||||
|
|
||||||
|
Sets the core the NimBLE host stack will run on
|
||||||
|
- Options: 0 or 1
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
`CONFIG_BT_NIMBLE_TASK_STACK_SIZE`
|
||||||
|
|
||||||
|
Set the task stack size for the NimBLE core.
|
||||||
|
- Default is 4096
|
||||||
|
<br/>
|
||||||
|
|
2669
src/components/esp-nimble-cpp-1.3.3/docs/Doxyfile
Normal file
2669
src/components/esp-nimble-cpp-1.3.3/docs/Doxyfile
Normal file
File diff suppressed because it is too large
Load Diff
@ -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)
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<a name="server"></a>
|
||||||
|
# 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<myStruct>(×tamp); // timestamp optional
|
||||||
|
```
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
**Advertising will automatically start when a client disconnects.**
|
||||||
|
|
||||||
|
A new method `NimBLEServer::advertiseOnDisconnect(bool)` has been implemented to control this, true(default) = enabled.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
`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`.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<a name="advertising"></a>
|
||||||
|
# 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.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<a name="client"></a>
|
||||||
|
# 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<myStruct>(×tamp); // timestamp optional
|
||||||
|
```
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
`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.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
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(&<ClassName>::<memberFunctionCallbackName>, this, _1, _2, _3, _4);
|
||||||
|
<remoteCharacteristicInstance>->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.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
`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()`.
|
||||||
|
|
||||||
|
<a name="general"></a>
|
||||||
|
# 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.
|
||||||
|
<br/>
|
||||||
|
|
399
src/components/esp-nimble-cpp-1.3.3/docs/Migration_guide.md
Normal file
399
src/components/esp-nimble-cpp-1.3.3/docs/Migration_guide.md
Normal file
@ -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)
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<a name="general-information"></a>
|
||||||
|
## 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.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
### 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.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
### 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.
|
||||||
|
<br/>
|
||||||
|
`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.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<a name="server-api"></a>
|
||||||
|
## 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.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<a name="services"></a>
|
||||||
|
### 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.
|
||||||
|
|
||||||
|
<a name="characteristics"></a>
|
||||||
|
### 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
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
#### 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
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
**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
|
||||||
|
);
|
||||||
|
```
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
`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.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
> 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<my_struct_t>();
|
||||||
|
```
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<a name="descriptors"></a>
|
||||||
|
### 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.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
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");
|
||||||
|
```
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<a name="server-security"></a>
|
||||||
|
### 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.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<a name="advertising-api"></a>
|
||||||
|
## 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`).
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
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.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
> 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.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<a name="client-api"></a>
|
||||||
|
## 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.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
> `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`.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
**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.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<a name="remote-services"></a>
|
||||||
|
### Remote Services
|
||||||
|
`BLERemoteService` (`NimBLERemoteService`) Methods remain mostly unchanged with the exceptions of:
|
||||||
|
|
||||||
|
> BLERemoteService::getCharacteristicsByHandle
|
||||||
|
|
||||||
|
This method has been removed.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
> `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`.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<a name="remote-characteristics"></a>
|
||||||
|
### 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.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
> `BLERemoteCharacteristic::registerForNotify` (`NimBLERemoteCharacteristic::registerForNotify`)
|
||||||
|
|
||||||
|
Is now **deprecated**.
|
||||||
|
> `NimBLERemoteCharacteristic::subscribe`
|
||||||
|
> `NimBLERemoteCharacteristic::unsubscribe`
|
||||||
|
|
||||||
|
Are the new methods added to replace it.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
> `BLERemoteCharacteristic::readUInt8` (`NimBLERemoteCharacteristic::readUInt8`)
|
||||||
|
> `BLERemoteCharacteristic::readUInt16` (`NimBLERemoteCharacteristic::readUInt16`)
|
||||||
|
> `BLERemoteCharacteristic::readUInt32` (`NimBLERemoteCharacteristic::readUInt32`)
|
||||||
|
> `BLERemoteCharacteristic::readFloat` (`NimBLERemoteCharacteristic::readFloat`)
|
||||||
|
|
||||||
|
Are **deprecated** a template: NimBLERemoteCharacteristic::readValue<type\>(time_t\*, bool) has been added to replace them.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
> `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<my_struct_t>();
|
||||||
|
```
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
> `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`.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<a name="client-security"></a>
|
||||||
|
### 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.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<a name="security-api"></a>
|
||||||
|
## 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.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
> `uint32_t onPassKeyRequest()`
|
||||||
|
|
||||||
|
For server callback; return the passkey expected from the client.
|
||||||
|
For client callback; return the passkey to send to the server.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
> `void onAuthenticationComplete(ble_gap_conn_desc\* desc)`
|
||||||
|
|
||||||
|
Authentication complete, success or failed information is in `desc`.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
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.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
> `NimBLEDevice::setSecurityIOCap(uint8_t iocap)`
|
||||||
|
|
||||||
|
Sets the Input/Output capabilities of this device.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
> `NimBLEDevice::setSecurityInitKey(uint8_t init_key)`
|
||||||
|
|
||||||
|
If we are the initiator of the security procedure this sets the keys we will distribute.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
> `NimBLEDevice::setSecurityRespKey(uint8_t resp_key)`
|
||||||
|
|
||||||
|
Sets the keys we are willing to accept from the peer during pairing.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<a name="arduino-configuration"></a>
|
||||||
|
## 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*
|
||||||
|
<br/>
|
339
src/components/esp-nimble-cpp-1.3.3/docs/New_user_guide.md
Normal file
339
src/components/esp-nimble-cpp-1.3.3/docs/New_user_guide.md
Normal file
@ -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)
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<a name="creating-a-server"></a>
|
||||||
|
## 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.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
**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");`
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
**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.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<a name="creating-a-client"></a>
|
||||||
|
## 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);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
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.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
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.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
**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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
For more advanced features and options please see the client examples in the examples folder.
|
||||||
|
<br/>
|
||||||
|
|
41
src/components/esp-nimble-cpp-1.3.3/docs/Usage_tips.md
Normal file
41
src/components/esp-nimble-cpp-1.3.3/docs/Usage_tips.md
Normal file
@ -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.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
## 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.
|
85
src/components/esp-nimble-cpp-1.3.3/docs/index.md
Normal file
85
src/components/esp-nimble-cpp-1.3.3/docs/index.md
Normal file
@ -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*
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
# 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.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
# 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.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
# 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`.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
### 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`.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
# 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.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
### 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).
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
### 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).
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
# 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.
|
||||||
|
<br/>
|
||||||
|
|
@ -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)
|
@ -0,0 +1,3 @@
|
|||||||
|
PROJECT_NAME := NimBLE_Client
|
||||||
|
|
||||||
|
include $(IDF_PATH)/make/project.mk
|
@ -0,0 +1,4 @@
|
|||||||
|
set(COMPONENT_SRCS "main.cpp")
|
||||||
|
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||||
|
|
||||||
|
register_component()
|
@ -0,0 +1,4 @@
|
|||||||
|
#
|
||||||
|
# "main" pseudo-component makefile.
|
||||||
|
#
|
||||||
|
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
@ -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 <NimBLEDevice.h>
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
@ -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)
|
@ -0,0 +1,3 @@
|
|||||||
|
PROJECT_NAME := NimBLE_Server
|
||||||
|
|
||||||
|
include $(IDF_PATH)/make/project.mk
|
@ -0,0 +1,4 @@
|
|||||||
|
set(COMPONENT_SRCS "main.cpp")
|
||||||
|
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||||
|
|
||||||
|
register_component()
|
@ -0,0 +1,4 @@
|
|||||||
|
#
|
||||||
|
# "main" pseudo-component makefile.
|
||||||
|
#
|
||||||
|
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
@ -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 <stdio.h>
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
@ -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)
|
@ -0,0 +1,3 @@
|
|||||||
|
PROJECT_NAME := BLE_client
|
||||||
|
|
||||||
|
include $(IDF_PATH)/make/project.mk
|
@ -0,0 +1,4 @@
|
|||||||
|
set(COMPONENT_SRCS "main.cpp")
|
||||||
|
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||||
|
|
||||||
|
register_component()
|
@ -0,0 +1,4 @@
|
|||||||
|
#
|
||||||
|
# "main" pseudo-component makefile.
|
||||||
|
#
|
||||||
|
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
@ -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.
|
||||||
|
|
@ -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)
|
@ -0,0 +1,3 @@
|
|||||||
|
PROJECT_NAME := BLE_notify
|
||||||
|
|
||||||
|
include $(IDF_PATH)/make/project.mk
|
@ -0,0 +1,4 @@
|
|||||||
|
set(COMPONENT_SRCS "main.cpp")
|
||||||
|
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||||
|
|
||||||
|
register_component()
|
@ -0,0 +1,4 @@
|
|||||||
|
#
|
||||||
|
# "main" pseudo-component makefile.
|
||||||
|
#
|
||||||
|
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
@ -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 <BLEDevice.h>
|
||||||
|
#include <BLEServer.h>
|
||||||
|
#include <BLEUtils.h>
|
||||||
|
#include <BLE2902.h>
|
||||||
|
***********************/
|
||||||
|
#include <NimBLEDevice.h>
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
@ -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)
|
@ -0,0 +1,3 @@
|
|||||||
|
PROJECT_NAME := BLE_scan
|
||||||
|
|
||||||
|
include $(IDF_PATH)/make/project.mk
|
@ -0,0 +1,4 @@
|
|||||||
|
set(COMPONENT_SRCS "main.cpp")
|
||||||
|
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||||
|
|
||||||
|
register_component()
|
@ -0,0 +1,4 @@
|
|||||||
|
#
|
||||||
|
# "main" pseudo-component makefile.
|
||||||
|
#
|
||||||
|
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
@ -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 <BLEDevice.h>
|
||||||
|
#include <BLEUtils.h>
|
||||||
|
#include <BLEScan.h>
|
||||||
|
#include <BLEAdvertisedDevice.h>
|
||||||
|
***********************/
|
||||||
|
|
||||||
|
#include <NimBLEDevice.h>
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
@ -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)
|
@ -0,0 +1,3 @@
|
|||||||
|
PROJECT_NAME := BLE_server
|
||||||
|
|
||||||
|
include $(IDF_PATH)/make/project.mk
|
@ -0,0 +1,4 @@
|
|||||||
|
set(COMPONENT_SRCS "main.cpp")
|
||||||
|
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||||
|
|
||||||
|
register_component()
|
@ -0,0 +1,4 @@
|
|||||||
|
#
|
||||||
|
# "main" pseudo-component makefile.
|
||||||
|
#
|
||||||
|
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
@ -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 <BLEDevice.h>
|
||||||
|
#include <BLEUtils.h>
|
||||||
|
#include <BLEServer.h>
|
||||||
|
***********************/
|
||||||
|
|
||||||
|
#include <NimBLEDevice.h>
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
@ -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)
|
@ -0,0 +1,3 @@
|
|||||||
|
PROJECT_NAME := BLE_uart
|
||||||
|
|
||||||
|
include $(IDF_PATH)/make/project.mk
|
@ -0,0 +1,4 @@
|
|||||||
|
set(COMPONENT_SRCS "main.cpp")
|
||||||
|
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||||
|
|
||||||
|
register_component()
|
@ -0,0 +1,4 @@
|
|||||||
|
#
|
||||||
|
# "main" pseudo-component makefile.
|
||||||
|
#
|
||||||
|
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
@ -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 <BLEDevice.h>
|
||||||
|
#include <BLEServer.h>
|
||||||
|
#include <BLEUtils.h>
|
||||||
|
#include <BLE2902.h>
|
||||||
|
***********************/
|
||||||
|
#include <NimBLEDevice.h>
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
402
src/components/esp-nimble-cpp-1.3.3/src/HIDKeyboardTypes.h
Normal file
402
src/components/esp-nimble-cpp-1.3.3/src/HIDKeyboardTypes.h
Normal file
@ -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
|
91
src/components/esp-nimble-cpp-1.3.3/src/HIDTypes.h
Normal file
91
src/components/esp-nimble-cpp-1.3.3/src/HIDTypes.h
Normal file
@ -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 <stdint.h>
|
||||||
|
|
||||||
|
/* */
|
||||||
|
#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
|
86
src/components/esp-nimble-cpp-1.3.3/src/NimBLE2904.cpp
Normal file
86
src/components/esp-nimble-cpp-1.3.3/src/NimBLE2904.cpp
Normal file
@ -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 */
|
83
src/components/esp-nimble-cpp-1.3.3/src/NimBLE2904.h
Normal file
83
src/components/esp-nimble-cpp-1.3.3/src/NimBLE2904.h
Normal file
@ -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_ */
|
197
src/components/esp-nimble-cpp-1.3.3/src/NimBLEAddress.cpp
Normal file
197
src/components/esp-nimble-cpp-1.3.3/src/NimBLEAddress.cpp
Normal file
@ -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 <algorithm>
|
||||||
|
|
||||||
|
#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
|
62
src/components/esp-nimble-cpp-1.3.3/src/NimBLEAddress.h
Normal file
62
src/components/esp-nimble-cpp-1.3.3/src/NimBLEAddress.h
Normal file
@ -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 <string>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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_ */
|
@ -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 */
|
||||||
|
|
177
src/components/esp-nimble-cpp-1.3.3/src/NimBLEAdvertisedDevice.h
Normal file
177
src/components/esp-nimble-cpp-1.3.3/src/NimBLEAdvertisedDevice.h
Normal file
@ -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 <map>
|
||||||
|
#include <vector>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
|
||||||
|
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 <type\>.
|
||||||
|
* @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 <tt>sizeof(<type\>)</tt>.
|
||||||
|
* @return The data converted to <type\> or NULL if skipSizeCheck is false and the data is
|
||||||
|
* less than <tt>sizeof(<type\>)</tt>.
|
||||||
|
* @details <b>Use:</b> <tt>getManufacturerData<type>(skipSizeCheck);</tt>
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
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 <tt><type\></tt>.
|
||||||
|
* @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 <tt>sizeof(<type\>)</tt>.
|
||||||
|
* @return The data converted to <type\> or NULL if skipSizeCheck is false and the data is
|
||||||
|
* less than <tt>sizeof(<type\>)</tt>.
|
||||||
|
* @details <b>Use:</b> <tt>getServiceData<type>(skipSizeCheck);</tt>
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
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 <tt><type\></tt>.
|
||||||
|
* @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 <tt>sizeof(<type\>)</tt>.
|
||||||
|
* @return The data converted to <type\> or NULL if skipSizeCheck is false and the data is
|
||||||
|
* less than <tt>sizeof(<type\>)</tt>.
|
||||||
|
* @details <b>Use:</b> <tt>getServiceData<type>(skipSizeCheck);</tt>
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
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<uint8_t> 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_ */
|
1029
src/components/esp-nimble-cpp-1.3.3/src/NimBLEAdvertising.cpp
Normal file
1029
src/components/esp-nimble-cpp-1.3.3/src/NimBLEAdvertising.cpp
Normal file
File diff suppressed because it is too large
Load Diff
138
src/components/esp-nimble-cpp-1.3.3/src/NimBLEAdvertising.h
Normal file
138
src/components/esp-nimble-cpp-1.3.3/src/NimBLEAdvertising.h
Normal file
@ -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 <vector>
|
||||||
|
|
||||||
|
/* 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<NimBLEUUID> &v_uuid);
|
||||||
|
void setCompleteServices32(const std::vector<NimBLEUUID> &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<NimBLEUUID> &v_uuid);
|
||||||
|
void setPartialServices32(const std::vector<NimBLEUUID> &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<NimBLEUUID> &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<NimBLEUUID> 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<uint8_t> m_svcData16;
|
||||||
|
std::vector<uint8_t> m_svcData32;
|
||||||
|
std::vector<uint8_t> m_svcData128;
|
||||||
|
std::vector<uint8_t> m_name;
|
||||||
|
std::vector<uint8_t> m_mfgData;
|
||||||
|
std::vector<uint8_t> m_uri;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER */
|
||||||
|
#endif /* MAIN_BLEADVERTISING_H_ */
|
157
src/components/esp-nimble-cpp-1.3.3/src/NimBLEBeacon.cpp
Normal file
157
src/components/esp-nimble-cpp-1.3.3/src/NimBLEBeacon.cpp
Normal file
@ -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 <string.h>
|
||||||
|
#include <algorithm>
|
||||||
|
#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
|
51
src/components/esp-nimble-cpp-1.3.3/src/NimBLEBeacon.h
Normal file
51
src/components/esp-nimble-cpp-1.3.3/src/NimBLEBeacon.h
Normal file
@ -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_ */
|
649
src/components/esp-nimble-cpp-1.3.3/src/NimBLECharacteristic.cpp
Normal file
649
src/components/esp-nimble-cpp-1.3.3/src/NimBLECharacteristic.cpp
Normal file
@ -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 */
|
202
src/components/esp-nimble-cpp-1.3.3/src/NimBLECharacteristic.h
Normal file
202
src/components/esp-nimble-cpp-1.3.3/src/NimBLECharacteristic.h
Normal file
@ -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 <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
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 <type\>.
|
||||||
|
* @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 <tt>sizeof(<type\>)</tt>.
|
||||||
|
* @return The data converted to <type\> or NULL if skipSizeCheck is false and the data is
|
||||||
|
* less than <tt>sizeof(<type\>)</tt>.
|
||||||
|
* @details <b>Use:</b> <tt>getValue<type>(×tamp, skipSizeCheck);</tt>
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
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 <type\>val.
|
||||||
|
* @param [in] s The value to set.
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
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<NimBLEDescriptor*> m_dscVec;
|
||||||
|
time_t m_timestamp;
|
||||||
|
uint8_t m_removed;
|
||||||
|
|
||||||
|
std::vector<std::pair<uint16_t, uint16_t>> 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_*/
|
1251
src/components/esp-nimble-cpp-1.3.3/src/NimBLEClient.cpp
Normal file
1251
src/components/esp-nimble-cpp-1.3.3/src/NimBLEClient.cpp
Normal file
File diff suppressed because it is too large
Load Diff
162
src/components/esp-nimble-cpp-1.3.3/src/NimBLEClient.h
Normal file
162
src/components/esp-nimble-cpp-1.3.3/src/NimBLEClient.h
Normal file
@ -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 <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
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<NimBLERemoteService*>* getServices(bool refresh = false);
|
||||||
|
std::vector<NimBLERemoteService*>::iterator begin();
|
||||||
|
std::vector<NimBLERemoteService*>::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<NimBLERemoteService*> 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_ */
|
55
src/components/esp-nimble-cpp-1.3.3/src/NimBLEConnInfo.h
Normal file
55
src/components/esp-nimble-cpp-1.3.3/src/NimBLEConnInfo.h
Normal file
@ -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
|
297
src/components/esp-nimble-cpp-1.3.3/src/NimBLEDescriptor.cpp
Normal file
297
src/components/esp-nimble-cpp-1.3.3/src/NimBLEDescriptor.cpp
Normal file
@ -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 <string>
|
||||||
|
|
||||||
|
#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 */
|
114
src/components/esp-nimble-cpp-1.3.3/src/NimBLEDescriptor.h
Normal file
114
src/components/esp-nimble-cpp-1.3.3/src/NimBLEDescriptor.h
Normal file
@ -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 <string>
|
||||||
|
|
||||||
|
|
||||||
|
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 <type\>val.
|
||||||
|
* @param [in] s The value to set.
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
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_ */
|
1159
src/components/esp-nimble-cpp-1.3.3/src/NimBLEDevice.cpp
Normal file
1159
src/components/esp-nimble-cpp-1.3.3/src/NimBLEDevice.cpp
Normal file
File diff suppressed because it is too large
Load Diff
218
src/components/esp-nimble-cpp-1.3.3/src/NimBLEDevice.h
Normal file
218
src/components/esp-nimble-cpp-1.3.3/src/NimBLEDevice.h
Normal file
@ -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 <map>
|
||||||
|
#include <string>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
#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<NimBLEClient*>* 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 <NimBLEClient*> m_cList;
|
||||||
|
#endif
|
||||||
|
static std::list <NimBLEAddress> 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<NimBLEAddress> m_whiteList;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // CONFIG_BT_ENABLED
|
||||||
|
#endif // MAIN_NIMBLEDEVICE_H_
|
227
src/components/esp-nimble-cpp-1.3.3/src/NimBLEEddystoneTLM.cpp
Normal file
227
src/components/esp-nimble-cpp-1.3.3/src/NimBLEEddystoneTLM.cpp
Normal file
@ -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 <stdio.h>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#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
|
61
src/components/esp-nimble-cpp-1.3.3/src/NimBLEEddystoneTLM.h
Normal file
61
src/components/esp-nimble-cpp-1.3.3/src/NimBLEEddystoneTLM.h
Normal file
@ -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 <string>
|
||||||
|
|
||||||
|
#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_ */
|
204
src/components/esp-nimble-cpp-1.3.3/src/NimBLEEddystoneURL.cpp
Normal file
204
src/components/esp-nimble-cpp-1.3.3/src/NimBLEEddystoneURL.cpp
Normal file
@ -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 <cstring>
|
||||||
|
|
||||||
|
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
|
52
src/components/esp-nimble-cpp-1.3.3/src/NimBLEEddystoneURL.h
Normal file
52
src/components/esp-nimble-cpp-1.3.3/src/NimBLEEddystoneURL.h
Normal file
@ -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 <string>
|
||||||
|
|
||||||
|
#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_ */
|
248
src/components/esp-nimble-cpp-1.3.3/src/NimBLEHIDDevice.cpp
Normal file
248
src/components/esp-nimble-cpp-1.3.3/src/NimBLEHIDDevice.cpp
Normal file
@ -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 */
|
86
src/components/esp-nimble-cpp-1.3.3/src/NimBLEHIDDevice.h
Normal file
86
src/components/esp-nimble-cpp-1.3.3/src/NimBLEHIDDevice.h
Normal file
@ -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_ */
|
80
src/components/esp-nimble-cpp-1.3.3/src/NimBLELog.h
Normal file
80
src/components/esp-nimble-cpp-1.3.3/src/NimBLELog.h
Normal file
@ -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_ */
|
@ -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 <climits>
|
||||||
|
|
||||||
|
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<ble_uuid128_t*>(&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<NimBLERemoteDescriptor*>* 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<NimBLERemoteDescriptor*>::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<NimBLERemoteDescriptor*>::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>().
|
||||||
|
*/
|
||||||
|
uint16_t NimBLERemoteCharacteristic::readUInt16() {
|
||||||
|
return readValue<uint16_t>();
|
||||||
|
} // readUInt16
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read an unsigned 32 bit value.
|
||||||
|
* @return the unsigned 32 bit value.
|
||||||
|
* @deprecated Use readValue<uint32_t>().
|
||||||
|
*/
|
||||||
|
uint32_t NimBLERemoteCharacteristic::readUInt32() {
|
||||||
|
return readValue<uint32_t>();
|
||||||
|
} // readUInt32
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read a byte value
|
||||||
|
* @return The value as a byte
|
||||||
|
* @deprecated Use readValue<uint8_t>().
|
||||||
|
*/
|
||||||
|
uint8_t NimBLERemoteCharacteristic::readUInt8() {
|
||||||
|
return readValue<uint8_t>();
|
||||||
|
} // readUInt8
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read a float value.
|
||||||
|
* @return the float value.
|
||||||
|
*/
|
||||||
|
float NimBLERemoteCharacteristic::readFloat() {
|
||||||
|
return readValue<float>();
|
||||||
|
} // 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 */
|
@ -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 <vector>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
class NimBLERemoteService;
|
||||||
|
class NimBLERemoteDescriptor;
|
||||||
|
|
||||||
|
|
||||||
|
typedef std::function<void (NimBLERemoteCharacteristic* pBLERemoteCharacteristic,
|
||||||
|
uint8_t* pData, size_t length, bool isNotify)> 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<NimBLERemoteDescriptor*>::iterator begin();
|
||||||
|
std::vector<NimBLERemoteDescriptor*>::iterator end();
|
||||||
|
NimBLERemoteDescriptor* getDescriptor(const NimBLEUUID &uuid);
|
||||||
|
std::vector<NimBLERemoteDescriptor*>* 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 <type\>.
|
||||||
|
* @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 <tt>sizeof(<type\>)</tt>.
|
||||||
|
* @return The data converted to <type\> or NULL if skipSizeCheck is false and the data is
|
||||||
|
* less than <tt>sizeof(<type\>)</tt>.
|
||||||
|
* @details <b>Use:</b> <tt>readValue<type>(×tamp, skipSizeCheck);</tt>
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
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<uint8_t>()")));
|
||||||
|
uint16_t readUInt16() __attribute__ ((deprecated("Use template readValue<uint16_t>()")));
|
||||||
|
uint32_t readUInt32() __attribute__ ((deprecated("Use template readValue<uint32_t>()")));
|
||||||
|
float readFloat() __attribute__ ((deprecated("Use template readValue<float>()")));
|
||||||
|
std::string getValue(time_t *timestamp = nullptr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A template to convert the remote characteristic data to <type\>.
|
||||||
|
* @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 <tt>sizeof(<type\>)</tt>.
|
||||||
|
* @return The data converted to <type\> or NULL if skipSizeCheck is false and the data is
|
||||||
|
* less than <tt>sizeof(<type\>)</tt>.
|
||||||
|
* @details <b>Use:</b> <tt>getValue<type>(×tamp, skipSizeCheck);</tt>
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
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 <type\>val.
|
||||||
|
* @param [in] s The value to write.
|
||||||
|
* @param [in] response True == request write response.
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
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<NimBLERemoteDescriptor*> m_descriptorVector;
|
||||||
|
}; // NimBLERemoteCharacteristic
|
||||||
|
|
||||||
|
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|
||||||
|
#endif /* COMPONENTS_NIMBLEREMOTECHARACTERISTIC_H_ */
|
@ -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 <climits>
|
||||||
|
|
||||||
|
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<ble_uuid128_t*>(&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>().
|
||||||
|
*/
|
||||||
|
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>().
|
||||||
|
*/
|
||||||
|
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>().
|
||||||
|
*/
|
||||||
|
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 */
|
@ -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 <type\>.
|
||||||
|
* @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 <tt>sizeof(<type\>)</tt>.
|
||||||
|
* @return The data converted to <type\> or NULL if skipSizeCheck is false and the data is
|
||||||
|
* less than <tt>sizeof(<type\>)</tt>.
|
||||||
|
* @details <b>Use:</b> <tt>readValue<type>(skipSizeCheck);</tt>
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
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<uint8_t>()")));
|
||||||
|
uint16_t readUInt16() __attribute__ ((deprecated("Use template readValue<uint16_t>()")));
|
||||||
|
uint32_t readUInt32() __attribute__ ((deprecated("Use template readValue<uint32_t>()")));
|
||||||
|
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 <type\>val.
|
||||||
|
* @param [in] s The value to write.
|
||||||
|
* @param [in] response True == request write response.
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
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_ */
|
411
src/components/esp-nimble-cpp-1.3.3/src/NimBLERemoteService.cpp
Normal file
411
src/components/esp-nimble-cpp-1.3.3/src/NimBLERemoteService.cpp
Normal file
@ -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 <climits>
|
||||||
|
|
||||||
|
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<ble_uuid128_t*>(&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<NimBLERemoteCharacteristic*>::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<NimBLERemoteCharacteristic*>::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<NimBLERemoteCharacteristic*>* 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 */
|
@ -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 <vector>
|
||||||
|
|
||||||
|
class NimBLEClient;
|
||||||
|
class NimBLERemoteCharacteristic;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A model of a remote %BLE service.
|
||||||
|
*/
|
||||||
|
class NimBLERemoteService {
|
||||||
|
public:
|
||||||
|
virtual ~NimBLERemoteService();
|
||||||
|
|
||||||
|
// Public methods
|
||||||
|
std::vector<NimBLERemoteCharacteristic*>::iterator begin();
|
||||||
|
std::vector<NimBLERemoteCharacteristic*>::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<NimBLERemoteCharacteristic*>* 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<NimBLERemoteCharacteristic*> 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_ */
|
541
src/components/esp-nimble-cpp-1.3.3/src/NimBLEScan.cpp
Normal file
541
src/components/esp-nimble-cpp-1.3.3/src/NimBLEScan.cpp
Normal file
@ -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 <string>
|
||||||
|
#include <climits>
|
||||||
|
|
||||||
|
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<getCount(); i++) {
|
||||||
|
NIMBLE_LOGI(LOG_TAG, "- %s", getDevice(i).toString().c_str());
|
||||||
|
}
|
||||||
|
} // dump
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the count of devices found in the last scan.
|
||||||
|
* @return The number of devices found in the last scan.
|
||||||
|
*/
|
||||||
|
int NimBLEScanResults::getCount() {
|
||||||
|
return m_advertisedDevicesVector.size();
|
||||||
|
} // getCount
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the specified device at the given index.
|
||||||
|
* The index should be between 0 and getCount()-1.
|
||||||
|
* @param [in] i The index of the device.
|
||||||
|
* @return The device at the specified index.
|
||||||
|
*/
|
||||||
|
NimBLEAdvertisedDevice NimBLEScanResults::getDevice(uint32_t i) {
|
||||||
|
return *m_advertisedDevicesVector[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get iterator to the beginning of the vector of advertised device pointers.
|
||||||
|
* @return An iterator to the beginning of the vector of advertised device pointers.
|
||||||
|
*/
|
||||||
|
std::vector<NimBLEAdvertisedDevice*>::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<NimBLEAdvertisedDevice*>::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 */
|
103
src/components/esp-nimble-cpp-1.3.3/src/NimBLEScan.h
Normal file
103
src/components/esp-nimble-cpp-1.3.3/src/NimBLEScan.h
Normal file
@ -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 <vector>
|
||||||
|
|
||||||
|
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<NimBLEAdvertisedDevice*>::iterator begin();
|
||||||
|
std::vector<NimBLEAdvertisedDevice*>::iterator end();
|
||||||
|
NimBLEAdvertisedDevice *getDevice(const NimBLEAddress &address);
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend NimBLEScan;
|
||||||
|
std::vector<NimBLEAdvertisedDevice*> 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_ */
|
158
src/components/esp-nimble-cpp-1.3.3/src/NimBLESecurity.cpp
Normal file
158
src/components/esp-nimble-cpp-1.3.3/src/NimBLESecurity.cpp
Normal file
@ -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
|
131
src/components/esp-nimble-cpp-1.3.3/src/NimBLESecurity.h
Normal file
131
src/components/esp-nimble-cpp-1.3.3/src/NimBLESecurity.h
Normal file
@ -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 <stdint.h>
|
||||||
|
|
||||||
|
#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.
|
||||||
|
* <b>Deprecated - provided for backward compatibility only.</b>
|
||||||
|
* @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.
|
||||||
|
* <b>Deprecated - provided for backward compatibility only.</b>
|
||||||
|
* @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_
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user