mirror of
https://github.com/h2zero/esp-nimble-cpp.git
synced 2024-11-23 13:40:55 +01:00
Merge branch 'master' into mesh
This commit is contained in:
commit
356459d352
68 changed files with 3814 additions and 837 deletions
27
.travis.yml
27
.travis.yml
|
@ -1,27 +0,0 @@
|
||||||
sudo: false
|
|
||||||
|
|
||||||
before_install:
|
|
||||||
- cd ${TMPDIR-/tmp}
|
|
||||||
- wget -q http://doxygen.nl/files/doxygen-1.9.0.src.tar.gz
|
|
||||||
- tar -xzvf doxygen-1.9.0.src.tar.gz
|
|
||||||
- mkdir doxygen_build
|
|
||||||
- cd doxygen_build
|
|
||||||
- cmake ../doxygen-1.9.0/
|
|
||||||
- make
|
|
||||||
- export PATH="${TMPDIR-/tmp}/doxygen_build/bin:$PATH"
|
|
||||||
- cd ${TRAVIS_BUILD_DIR}
|
|
||||||
|
|
||||||
branches:
|
|
||||||
only:
|
|
||||||
- master
|
|
||||||
|
|
||||||
script:
|
|
||||||
- doxygen ./docs/Doxyfile
|
|
||||||
|
|
||||||
deploy:
|
|
||||||
provider: pages
|
|
||||||
skip_cleanup: true
|
|
||||||
local_dir: docs/html
|
|
||||||
github_token: $GH_REPO_TOKEN
|
|
||||||
on:
|
|
||||||
branch: master
|
|
32
CHANGELOG.md
32
CHANGELOG.md
|
@ -2,6 +2,38 @@
|
||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
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
|
## [1.3.1] - 2021-08-04
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
|
@ -39,6 +39,7 @@ idf_component_register(
|
||||||
"src/NimBLEDevice.cpp"
|
"src/NimBLEDevice.cpp"
|
||||||
"src/NimBLEEddystoneTLM.cpp"
|
"src/NimBLEEddystoneTLM.cpp"
|
||||||
"src/NimBLEEddystoneURL.cpp"
|
"src/NimBLEEddystoneURL.cpp"
|
||||||
|
"src/NimBLEExtAdvertising.cpp"
|
||||||
"src/NimBLEHIDDevice.cpp"
|
"src/NimBLEHIDDevice.cpp"
|
||||||
"src/NimBLERemoteCharacteristic.cpp"
|
"src/NimBLERemoteCharacteristic.cpp"
|
||||||
"src/NimBLERemoteDescriptor.cpp"
|
"src/NimBLERemoteDescriptor.cpp"
|
||||||
|
|
45
Kconfig
45
Kconfig
|
@ -1,5 +1,31 @@
|
||||||
menu "ESP-NimBLE-CPP configuration"
|
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
|
config NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT
|
||||||
bool "Show NimBLE return codes as text in debug log."
|
bool "Show NimBLE return codes as text in debug log."
|
||||||
default "n"
|
default "n"
|
||||||
|
@ -24,4 +50,23 @@ config NIMBLE_CPP_ENABLE_ADVERTISMENT_TYPE_TEXT
|
||||||
while scanning as text messages in the debug log.
|
while scanning as text messages in the debug log.
|
||||||
This will use approximately 250 bytes of flash memory.
|
This will use approximately 250 bytes of flash memory.
|
||||||
|
|
||||||
|
config NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
|
||||||
|
bool "Enable timestamps to be stored with attribute values."
|
||||||
|
default "n"
|
||||||
|
help
|
||||||
|
Enabling this option will store the timestamp when an attribute value is updated.
|
||||||
|
This allows for checking the last update time using getTimeStamp()
|
||||||
|
or getValue(time_t*). If disabled, the timestamp returned from these functions will be 0.
|
||||||
|
Disabling timestamps will reduce the memory used for each value.
|
||||||
|
|
||||||
|
config NIMBLE_CPP_ATT_VALUE_INIT_LENGTH
|
||||||
|
int "Initial attribute value size (bytes) for empty values."
|
||||||
|
range 1 512
|
||||||
|
default 20
|
||||||
|
help
|
||||||
|
Sets the default allocation size (bytes) for each attribute if not specified
|
||||||
|
when the constructor is called. This is also the size used when a remote
|
||||||
|
characteristic or descriptor is constructed before a value is read/notifed.
|
||||||
|
Increasing this will reduce reallocations but increase memory footprint.
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
29
docs/Bluetooth 5 features.md
Normal file
29
docs/Bluetooth 5 features.md
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
# Bluetooth 5.x features
|
||||||
|
|
||||||
|
## About extended advertising
|
||||||
|
Extended advertising allows for much more capability and flexibility.
|
||||||
|
|
||||||
|
* Allows for 251 bytes of advertisement data and up to 1650 bytes when chained (configuration dependant) vs 31.
|
||||||
|
|
||||||
|
* New PHY's (physical layers) that allow for faster data rate (2M PHY) or long range/slower data rates (CODED PHY) as well as the original 1M PHY.
|
||||||
|
|
||||||
|
* New periodic advertising, allowing the scanning device to sync with the advertisements of a beacon. This allows for the scanning device to sleep or perform other tasks before the next expected advertisement is sent, preserving cpu cycles and power (To be implemented).
|
||||||
|
<br>
|
||||||
|
|
||||||
|
## Enabling extended advertising
|
||||||
|
Extended advertising is supported when enabled with the config option `CONFIG_BT_NIMBLE_EXT_ADV` set to a value of 1. This is done in menuconfig under `Component config > Bluetooth > NimBLE options >
|
||||||
|
Enable extended advertising`.
|
||||||
|
|
||||||
|
When enabled the following will occur:
|
||||||
|
* `NimBLEScan::start` method will scan on both the 1M PHY and the coded PHY standards automatically.
|
||||||
|
|
||||||
|
* `NimBLEClient::connect` will use the primary PHY the device is listening on, unless specified (see below).
|
||||||
|
|
||||||
|
* `NimBLEClient::setConnectPhy` becomes available to specify the PHY's to connect with (default is all).
|
||||||
|
|
||||||
|
* `NimBLEAdvertising` is no longer available for use and is replaced by `NimBLEExtAdvertising`. `NimBLEDevice::getAdvertising` will now return an instance of `NimBLEExtAdvertising`.
|
||||||
|
|
||||||
|
* `NimBLEAdvertisementData` is no longer available for use and is replaced by `NimBLEExtAdvertisement`. This new class is where everything about the advertisement is configured, including the advertisement intervals and advertisement ended callback.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,24 @@ Sets the number of simultaneous connections (esp controller max is 9)
|
||||||
- Default value is 3
|
- Default value is 3
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
|
`CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED`
|
||||||
|
|
||||||
|
Enable/disable storing the timestamp when an attribute value is updated
|
||||||
|
This allows for checking the last update time using getTimeStamp() or getValue(time_t*)
|
||||||
|
If disabled, the timestamp returned from these functions will be 0.
|
||||||
|
Disabling timestamps will reduce the memory used for each value.
|
||||||
|
1 = Enabled, 0 = Disabled; Default = Disabled
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
`CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH`
|
||||||
|
|
||||||
|
Set the default allocation size (bytes) for each attribute.
|
||||||
|
If not specified when the constructor is called. This is also the size used when a remote
|
||||||
|
characteristic or descriptor is constructed before a value is read/notifed.
|
||||||
|
Increasing this will reduce reallocations but increase memory footprint.
|
||||||
|
Default value is 20. Range: 1 : 512 (BLE_ATT_ATTR_MAX_LEN)
|
||||||
|
<br/>
|
||||||
|
|
||||||
`CONFIG_BT_NIMBLE_ATT_PREFERRED_MTU`
|
`CONFIG_BT_NIMBLE_ATT_PREFERRED_MTU`
|
||||||
|
|
||||||
Sets the default MTU size.
|
Sets the default MTU size.
|
||||||
|
@ -24,6 +42,13 @@ If defined, enables debug log messages from the NimBLE host
|
||||||
- Uses approx. 32kB of flash memory.
|
- Uses approx. 32kB of flash memory.
|
||||||
<br/>
|
<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`
|
`CONFIG_NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT`
|
||||||
|
|
||||||
If defined, NimBLE host return codes will be printed as text in debug log messages.
|
If defined, NimBLE host return codes will be printed as text in debug log messages.
|
||||||
|
|
225
docs/Doxyfile
225
docs/Doxyfile
|
@ -1,4 +1,4 @@
|
||||||
# Doxyfile 1.8.18
|
# Doxyfile 1.9.1
|
||||||
|
|
||||||
# This file describes the settings to be used by the documentation system
|
# This file describes the settings to be used by the documentation system
|
||||||
# doxygen (www.doxygen.org) for a project.
|
# doxygen (www.doxygen.org) for a project.
|
||||||
|
@ -32,13 +32,13 @@ DOXYFILE_ENCODING = UTF-8
|
||||||
# title of most generated pages and in a few other places.
|
# title of most generated pages and in a few other places.
|
||||||
# The default value is: My Project.
|
# The default value is: My Project.
|
||||||
|
|
||||||
PROJECT_NAME = "esp-nimble-cpp / NimBLE-Arduino"
|
PROJECT_NAME = esp-nimble-cpp
|
||||||
|
|
||||||
# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
|
# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
|
||||||
# could be handy for archiving the generated documentation or if some version
|
# could be handy for archiving the generated documentation or if some version
|
||||||
# control system is used.
|
# control system is used.
|
||||||
|
|
||||||
PROJECT_NUMBER = 1.3.1
|
PROJECT_NUMBER = 1.3.2
|
||||||
|
|
||||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||||
# for a project that appears at the top of each page and should give viewer a
|
# for a project that appears at the top of each page and should give viewer a
|
||||||
|
@ -58,7 +58,7 @@ PROJECT_LOGO =
|
||||||
# entered, it will be relative to the location where doxygen was started. If
|
# entered, it will be relative to the location where doxygen was started. If
|
||||||
# left blank the current directory will be used.
|
# left blank the current directory will be used.
|
||||||
|
|
||||||
OUTPUT_DIRECTORY = docs
|
OUTPUT_DIRECTORY = .
|
||||||
|
|
||||||
# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
|
# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
|
||||||
# directories (in 2 levels) under the output directory of each output format and
|
# directories (in 2 levels) under the output directory of each output format and
|
||||||
|
@ -227,6 +227,14 @@ QT_AUTOBRIEF = NO
|
||||||
|
|
||||||
MULTILINE_CPP_IS_BRIEF = NO
|
MULTILINE_CPP_IS_BRIEF = NO
|
||||||
|
|
||||||
|
# By default Python docstrings are displayed as preformatted text and doxygen's
|
||||||
|
# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the
|
||||||
|
# doxygen's special commands can be used and the contents of the docstring
|
||||||
|
# documentation blocks is shown as doxygen documentation.
|
||||||
|
# The default value is: YES.
|
||||||
|
|
||||||
|
PYTHON_DOCSTRING = YES
|
||||||
|
|
||||||
# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
|
# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
|
||||||
# documentation from any documented member that it re-implements.
|
# documentation from any documented member that it re-implements.
|
||||||
# The default value is: YES.
|
# The default value is: YES.
|
||||||
|
@ -315,7 +323,10 @@ OPTIMIZE_OUTPUT_SLICE = NO
|
||||||
# Note: For files without extension you can use no_extension as a placeholder.
|
# Note: For files without extension you can use no_extension as a placeholder.
|
||||||
#
|
#
|
||||||
# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
|
# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
|
||||||
# the files are not read by doxygen.
|
# the files are not read by doxygen. When specifying no_extension you should add
|
||||||
|
# * to the FILE_PATTERNS.
|
||||||
|
#
|
||||||
|
# Note see also the list of default file extension mappings.
|
||||||
|
|
||||||
EXTENSION_MAPPING =
|
EXTENSION_MAPPING =
|
||||||
|
|
||||||
|
@ -449,6 +460,19 @@ TYPEDEF_HIDES_STRUCT = NO
|
||||||
|
|
||||||
LOOKUP_CACHE_SIZE = 0
|
LOOKUP_CACHE_SIZE = 0
|
||||||
|
|
||||||
|
# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use
|
||||||
|
# during processing. When set to 0 doxygen will based this on the number of
|
||||||
|
# cores available in the system. You can set it explicitly to a value larger
|
||||||
|
# than 0 to get more control over the balance between CPU load and processing
|
||||||
|
# speed. At this moment only the input processing can be done using multiple
|
||||||
|
# threads. Since this is still an experimental feature the default is set to 1,
|
||||||
|
# which efficively disables parallel processing. Please report any issues you
|
||||||
|
# encounter. Generating dot graphs in parallel is controlled by the
|
||||||
|
# DOT_NUM_THREADS setting.
|
||||||
|
# Minimum value: 0, maximum value: 32, default value: 1.
|
||||||
|
|
||||||
|
NUM_PROC_THREADS = 1
|
||||||
|
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
# Build related configuration options
|
# Build related configuration options
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
|
@ -512,6 +536,13 @@ EXTRACT_LOCAL_METHODS = NO
|
||||||
|
|
||||||
EXTRACT_ANON_NSPACES = NO
|
EXTRACT_ANON_NSPACES = NO
|
||||||
|
|
||||||
|
# If this flag is set to YES, the name of an unnamed parameter in a declaration
|
||||||
|
# will be determined by the corresponding definition. By default unnamed
|
||||||
|
# parameters remain unnamed in the output.
|
||||||
|
# The default value is: YES.
|
||||||
|
|
||||||
|
RESOLVE_UNNAMED_PARAMS = YES
|
||||||
|
|
||||||
# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
|
# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
|
||||||
# undocumented members inside documented classes or files. If set to NO these
|
# undocumented members inside documented classes or files. If set to NO these
|
||||||
# members will be included in the various overviews, but no documentation
|
# members will be included in the various overviews, but no documentation
|
||||||
|
@ -549,11 +580,18 @@ HIDE_IN_BODY_DOCS = YES
|
||||||
|
|
||||||
INTERNAL_DOCS = NO
|
INTERNAL_DOCS = NO
|
||||||
|
|
||||||
# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
|
# With the correct setting of option CASE_SENSE_NAMES doxygen will better be
|
||||||
# names in lower-case letters. If set to YES, upper-case letters are also
|
# able to match the capabilities of the underlying filesystem. In case the
|
||||||
# allowed. This is useful if you have classes or files whose names only differ
|
# filesystem is case sensitive (i.e. it supports files in the same directory
|
||||||
# in case and if your file system supports case sensitive file names. Windows
|
# whose names only differ in casing), the option must be set to YES to properly
|
||||||
# (including Cygwin) ands Mac users are advised to set this option to NO.
|
# deal with such files in case they appear in the input. For filesystems that
|
||||||
|
# are not case sensitive the option should be be set to NO to properly deal with
|
||||||
|
# output files written for symbols that only differ in casing, such as for two
|
||||||
|
# classes, one named CLASS and the other named Class, and to also support
|
||||||
|
# references to files without having to specify the exact matching casing. On
|
||||||
|
# Windows (including Cygwin) and MacOS, users should typically set this option
|
||||||
|
# to NO, whereas on Linux or other Unix flavors it should typically be set to
|
||||||
|
# YES.
|
||||||
# The default value is: system dependent.
|
# The default value is: system dependent.
|
||||||
|
|
||||||
CASE_SENSE_NAMES = NO
|
CASE_SENSE_NAMES = NO
|
||||||
|
@ -792,7 +830,10 @@ WARN_IF_DOC_ERROR = YES
|
||||||
WARN_NO_PARAMDOC = NO
|
WARN_NO_PARAMDOC = NO
|
||||||
|
|
||||||
# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
|
# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
|
||||||
# a warning is encountered.
|
# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
|
||||||
|
# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but
|
||||||
|
# at the end of the doxygen process doxygen will return with a non-zero status.
|
||||||
|
# Possible values are: NO, YES and FAIL_ON_WARNINGS.
|
||||||
# The default value is: NO.
|
# The default value is: NO.
|
||||||
|
|
||||||
WARN_AS_ERROR = NO
|
WARN_AS_ERROR = NO
|
||||||
|
@ -823,13 +864,15 @@ WARN_LOGFILE =
|
||||||
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
|
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
|
||||||
# Note: If this tag is empty the current directory is searched.
|
# Note: If this tag is empty the current directory is searched.
|
||||||
|
|
||||||
INPUT = .
|
INPUT = ../CHANGELOG.md \
|
||||||
|
. \
|
||||||
|
../src
|
||||||
|
|
||||||
# This tag can be used to specify the character encoding of the source files
|
# This tag can be used to specify the character encoding of the source files
|
||||||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
|
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
|
||||||
# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
|
# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
|
||||||
# documentation (see: https://www.gnu.org/software/libiconv/) for the list of
|
# documentation (see:
|
||||||
# possible encodings.
|
# https://www.gnu.org/software/libiconv/) for the list of possible encodings.
|
||||||
# The default value is: UTF-8.
|
# The default value is: UTF-8.
|
||||||
|
|
||||||
INPUT_ENCODING = UTF-8
|
INPUT_ENCODING = UTF-8
|
||||||
|
@ -842,13 +885,15 @@ INPUT_ENCODING = UTF-8
|
||||||
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
|
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
|
||||||
# read by doxygen.
|
# read by doxygen.
|
||||||
#
|
#
|
||||||
|
# Note the list of default checked file patterns might differ from the list of
|
||||||
|
# default file extension mappings.
|
||||||
|
#
|
||||||
# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
|
# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
|
||||||
# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
|
# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
|
||||||
# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
|
# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
|
||||||
# *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C comment),
|
# *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C comment),
|
||||||
# *.doc (to be provided as doxygen C comment), *.txt (to be provided as doxygen
|
# *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, *.vhdl,
|
||||||
# C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd,
|
# *.ucf, *.qsf and *.ice.
|
||||||
# *.vhdl, *.ucf, *.qsf and *.ice.
|
|
||||||
|
|
||||||
FILE_PATTERNS = *.c \
|
FILE_PATTERNS = *.c \
|
||||||
*.cc \
|
*.cc \
|
||||||
|
@ -911,11 +956,7 @@ RECURSIVE = YES
|
||||||
# Note that relative paths are relative to the directory from which doxygen is
|
# Note that relative paths are relative to the directory from which doxygen is
|
||||||
# run.
|
# run.
|
||||||
|
|
||||||
EXCLUDE = ./README.md \
|
EXCLUDE = ../src/nimconfig_rename.h
|
||||||
./src/FreeRTOS.h \
|
|
||||||
./src/FreeRTOS.cpp \
|
|
||||||
./examples \
|
|
||||||
./CMakelists.txt
|
|
||||||
|
|
||||||
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
|
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
|
||||||
# directories that are symbolic links (a Unix file system feature) are excluded
|
# directories that are symbolic links (a Unix file system feature) are excluded
|
||||||
|
@ -1112,6 +1153,44 @@ USE_HTAGS = NO
|
||||||
|
|
||||||
VERBATIM_HEADERS = YES
|
VERBATIM_HEADERS = YES
|
||||||
|
|
||||||
|
# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
|
||||||
|
# clang parser (see:
|
||||||
|
# http://clang.llvm.org/) for more accurate parsing at the cost of reduced
|
||||||
|
# performance. This can be particularly helpful with template rich C++ code for
|
||||||
|
# which doxygen's built-in parser lacks the necessary type information.
|
||||||
|
# Note: The availability of this option depends on whether or not doxygen was
|
||||||
|
# generated with the -Duse_libclang=ON option for CMake.
|
||||||
|
# The default value is: NO.
|
||||||
|
|
||||||
|
CLANG_ASSISTED_PARSING = NO
|
||||||
|
|
||||||
|
# If clang assisted parsing is enabled and the CLANG_ADD_INC_PATHS tag is set to
|
||||||
|
# YES then doxygen will add the directory of each input to the include path.
|
||||||
|
# The default value is: YES.
|
||||||
|
|
||||||
|
CLANG_ADD_INC_PATHS = YES
|
||||||
|
|
||||||
|
# If clang assisted parsing is enabled you can provide the compiler with command
|
||||||
|
# line options that you would normally use when invoking the compiler. Note that
|
||||||
|
# the include paths will already be set by doxygen for the files and directories
|
||||||
|
# specified with INPUT and INCLUDE_PATH.
|
||||||
|
# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
|
||||||
|
|
||||||
|
CLANG_OPTIONS =
|
||||||
|
|
||||||
|
# If clang assisted parsing is enabled you can provide the clang parser with the
|
||||||
|
# path to the directory containing a file called compile_commands.json. This
|
||||||
|
# file is the compilation database (see:
|
||||||
|
# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the
|
||||||
|
# options used when the source files were built. This is equivalent to
|
||||||
|
# specifying the -p option to a clang tool, such as clang-check. These options
|
||||||
|
# will then be passed to the parser. Any options specified with CLANG_OPTIONS
|
||||||
|
# will be added as well.
|
||||||
|
# Note: The availability of this option depends on whether or not doxygen was
|
||||||
|
# generated with the -Duse_libclang=ON option for CMake.
|
||||||
|
|
||||||
|
CLANG_DATABASE_PATH =
|
||||||
|
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
# Configuration options related to the alphabetical class index
|
# Configuration options related to the alphabetical class index
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
|
@ -1123,13 +1202,6 @@ VERBATIM_HEADERS = YES
|
||||||
|
|
||||||
ALPHABETICAL_INDEX = YES
|
ALPHABETICAL_INDEX = YES
|
||||||
|
|
||||||
# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
|
|
||||||
# which the alphabetical index list will be split.
|
|
||||||
# Minimum value: 1, maximum value: 20, default value: 5.
|
|
||||||
# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
|
|
||||||
|
|
||||||
COLS_IN_ALPHA_INDEX = 5
|
|
||||||
|
|
||||||
# In case all classes in a project start with a common prefix, all classes will
|
# In case all classes in a project start with a common prefix, all classes will
|
||||||
# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
|
# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
|
||||||
# can be used to specify a prefix (or a list of prefixes) that should be ignored
|
# can be used to specify a prefix (or a list of prefixes) that should be ignored
|
||||||
|
@ -1300,10 +1372,11 @@ HTML_INDEX_NUM_ENTRIES = 100
|
||||||
|
|
||||||
# If the GENERATE_DOCSET tag is set to YES, additional index files will be
|
# If the GENERATE_DOCSET tag is set to YES, additional index files will be
|
||||||
# generated that can be used as input for Apple's Xcode 3 integrated development
|
# generated that can be used as input for Apple's Xcode 3 integrated development
|
||||||
# environment (see: https://developer.apple.com/xcode/), introduced with OSX
|
# environment (see:
|
||||||
# 10.5 (Leopard). To create a documentation set, doxygen will generate a
|
# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To
|
||||||
# Makefile in the HTML output directory. Running make will produce the docset in
|
# create a documentation set, doxygen will generate a Makefile in the HTML
|
||||||
# that directory and running make install will install the docset in
|
# output directory. Running make will produce the docset in that directory and
|
||||||
|
# running make install will install the docset in
|
||||||
# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
|
# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
|
||||||
# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy
|
# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy
|
||||||
# genXcode/_index.html for more information.
|
# genXcode/_index.html for more information.
|
||||||
|
@ -1345,8 +1418,8 @@ DOCSET_PUBLISHER_NAME = Publisher
|
||||||
# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
|
# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
|
||||||
# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
|
# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
|
||||||
# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
|
# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
|
||||||
# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on
|
# (see:
|
||||||
# Windows.
|
# https://www.microsoft.com/en-us/download/details.aspx?id=21138) on Windows.
|
||||||
#
|
#
|
||||||
# The HTML Help Workshop contains a compiler that can convert all HTML output
|
# The HTML Help Workshop contains a compiler that can convert all HTML output
|
||||||
# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
|
# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
|
||||||
|
@ -1376,7 +1449,7 @@ CHM_FILE =
|
||||||
HHC_LOCATION =
|
HHC_LOCATION =
|
||||||
|
|
||||||
# The GENERATE_CHI flag controls if a separate .chi index file is generated
|
# The GENERATE_CHI flag controls if a separate .chi index file is generated
|
||||||
# (YES) or that it should be included in the master .chm file (NO).
|
# (YES) or that it should be included in the main .chm file (NO).
|
||||||
# The default value is: NO.
|
# The default value is: NO.
|
||||||
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
|
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
|
||||||
|
|
||||||
|
@ -1421,7 +1494,8 @@ QCH_FILE =
|
||||||
|
|
||||||
# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
|
# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
|
||||||
# Project output. For more information please see Qt Help Project / Namespace
|
# Project output. For more information please see Qt Help Project / Namespace
|
||||||
# (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
|
# (see:
|
||||||
|
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
|
||||||
# The default value is: org.doxygen.Project.
|
# The default value is: org.doxygen.Project.
|
||||||
# This tag requires that the tag GENERATE_QHP is set to YES.
|
# This tag requires that the tag GENERATE_QHP is set to YES.
|
||||||
|
|
||||||
|
@ -1429,8 +1503,8 @@ QHP_NAMESPACE = org.doxygen.Project
|
||||||
|
|
||||||
# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
|
# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
|
||||||
# Help Project output. For more information please see Qt Help Project / Virtual
|
# Help Project output. For more information please see Qt Help Project / Virtual
|
||||||
# Folders (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-
|
# Folders (see:
|
||||||
# folders).
|
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders).
|
||||||
# The default value is: doc.
|
# The default value is: doc.
|
||||||
# This tag requires that the tag GENERATE_QHP is set to YES.
|
# This tag requires that the tag GENERATE_QHP is set to YES.
|
||||||
|
|
||||||
|
@ -1438,16 +1512,16 @@ QHP_VIRTUAL_FOLDER = doc
|
||||||
|
|
||||||
# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
|
# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
|
||||||
# filter to add. For more information please see Qt Help Project / Custom
|
# filter to add. For more information please see Qt Help Project / Custom
|
||||||
# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-
|
# Filters (see:
|
||||||
# filters).
|
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
|
||||||
# This tag requires that the tag GENERATE_QHP is set to YES.
|
# This tag requires that the tag GENERATE_QHP is set to YES.
|
||||||
|
|
||||||
QHP_CUST_FILTER_NAME =
|
QHP_CUST_FILTER_NAME =
|
||||||
|
|
||||||
# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
|
# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
|
||||||
# custom filter to add. For more information please see Qt Help Project / Custom
|
# custom filter to add. For more information please see Qt Help Project / Custom
|
||||||
# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-
|
# Filters (see:
|
||||||
# filters).
|
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
|
||||||
# This tag requires that the tag GENERATE_QHP is set to YES.
|
# This tag requires that the tag GENERATE_QHP is set to YES.
|
||||||
|
|
||||||
QHP_CUST_FILTER_ATTRS =
|
QHP_CUST_FILTER_ATTRS =
|
||||||
|
@ -1459,9 +1533,9 @@ QHP_CUST_FILTER_ATTRS =
|
||||||
|
|
||||||
QHP_SECT_FILTER_ATTRS =
|
QHP_SECT_FILTER_ATTRS =
|
||||||
|
|
||||||
# The QHG_LOCATION tag can be used to specify the location of Qt's
|
# The QHG_LOCATION tag can be used to specify the location (absolute path
|
||||||
# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
|
# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to
|
||||||
# generated .qhp file.
|
# run qhelpgenerator on the generated .qhp file.
|
||||||
# This tag requires that the tag GENERATE_QHP is set to YES.
|
# This tag requires that the tag GENERATE_QHP is set to YES.
|
||||||
|
|
||||||
QHG_LOCATION =
|
QHG_LOCATION =
|
||||||
|
@ -1542,8 +1616,8 @@ EXT_LINKS_IN_WINDOW = NO
|
||||||
# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see
|
# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see
|
||||||
# https://inkscape.org) to generate formulas as SVG images instead of PNGs for
|
# https://inkscape.org) to generate formulas as SVG images instead of PNGs for
|
||||||
# the HTML output. These images will generally look nicer at scaled resolutions.
|
# the HTML output. These images will generally look nicer at scaled resolutions.
|
||||||
# Possible values are: png The default and svg Looks nicer but requires the
|
# Possible values are: png (the default) and svg (looks nicer but requires the
|
||||||
# pdf2svg tool.
|
# pdf2svg or inkscape tool).
|
||||||
# The default value is: png.
|
# The default value is: png.
|
||||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||||
|
|
||||||
|
@ -1588,7 +1662,7 @@ USE_MATHJAX = NO
|
||||||
|
|
||||||
# When MathJax is enabled you can set the default output format to be used for
|
# When MathJax is enabled you can set the default output format to be used for
|
||||||
# the MathJax output. See the MathJax site (see:
|
# the MathJax output. See the MathJax site (see:
|
||||||
# http://docs.mathjax.org/en/latest/output.html) for more details.
|
# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details.
|
||||||
# Possible values are: HTML-CSS (which is slower, but has the best
|
# Possible values are: HTML-CSS (which is slower, but has the best
|
||||||
# compatibility), NativeMML (i.e. MathML) and SVG.
|
# compatibility), NativeMML (i.e. MathML) and SVG.
|
||||||
# The default value is: HTML-CSS.
|
# The default value is: HTML-CSS.
|
||||||
|
@ -1618,7 +1692,8 @@ MATHJAX_EXTENSIONS =
|
||||||
|
|
||||||
# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
|
# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
|
||||||
# of code that will be used on startup of the MathJax code. See the MathJax site
|
# of code that will be used on startup of the MathJax code. See the MathJax site
|
||||||
# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
|
# (see:
|
||||||
|
# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an
|
||||||
# example see the documentation.
|
# example see the documentation.
|
||||||
# This tag requires that the tag USE_MATHJAX is set to YES.
|
# This tag requires that the tag USE_MATHJAX is set to YES.
|
||||||
|
|
||||||
|
@ -1665,7 +1740,8 @@ SERVER_BASED_SEARCH = NO
|
||||||
#
|
#
|
||||||
# Doxygen ships with an example indexer (doxyindexer) and search engine
|
# Doxygen ships with an example indexer (doxyindexer) and search engine
|
||||||
# (doxysearch.cgi) which are based on the open source search engine library
|
# (doxysearch.cgi) which are based on the open source search engine library
|
||||||
# Xapian (see: https://xapian.org/).
|
# Xapian (see:
|
||||||
|
# https://xapian.org/).
|
||||||
#
|
#
|
||||||
# See the section "External Indexing and Searching" for details.
|
# See the section "External Indexing and Searching" for details.
|
||||||
# The default value is: NO.
|
# The default value is: NO.
|
||||||
|
@ -1678,8 +1754,9 @@ EXTERNAL_SEARCH = NO
|
||||||
#
|
#
|
||||||
# Doxygen ships with an example indexer (doxyindexer) and search engine
|
# Doxygen ships with an example indexer (doxyindexer) and search engine
|
||||||
# (doxysearch.cgi) which are based on the open source search engine library
|
# (doxysearch.cgi) which are based on the open source search engine library
|
||||||
# Xapian (see: https://xapian.org/). See the section "External Indexing and
|
# Xapian (see:
|
||||||
# Searching" for details.
|
# https://xapian.org/). See the section "External Indexing and Searching" for
|
||||||
|
# details.
|
||||||
# This tag requires that the tag SEARCHENGINE is set to YES.
|
# This tag requires that the tag SEARCHENGINE is set to YES.
|
||||||
|
|
||||||
SEARCHENGINE_URL =
|
SEARCHENGINE_URL =
|
||||||
|
@ -1843,9 +1920,11 @@ LATEX_EXTRA_FILES =
|
||||||
|
|
||||||
PDF_HYPERLINKS = YES
|
PDF_HYPERLINKS = YES
|
||||||
|
|
||||||
# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
|
# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as
|
||||||
# the PDF file directly from the LaTeX files. Set this option to YES, to get a
|
# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX
|
||||||
# higher quality PDF documentation.
|
# files. Set this option to YES, to get a higher quality PDF documentation.
|
||||||
|
#
|
||||||
|
# See also section LATEX_CMD_NAME for selecting the engine.
|
||||||
# The default value is: YES.
|
# The default value is: YES.
|
||||||
# This tag requires that the tag GENERATE_LATEX is set to YES.
|
# This tag requires that the tag GENERATE_LATEX is set to YES.
|
||||||
|
|
||||||
|
@ -2084,6 +2163,10 @@ DOCBOOK_PROGRAMLISTING = NO
|
||||||
|
|
||||||
GENERATE_AUTOGEN_DEF = NO
|
GENERATE_AUTOGEN_DEF = NO
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Configuration options related to Sqlite3 output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
# Configuration options related to the Perl module output
|
# Configuration options related to the Perl module output
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
|
@ -2361,10 +2444,32 @@ UML_LOOK = NO
|
||||||
# but if the number exceeds 15, the total amount of fields shown is limited to
|
# but if the number exceeds 15, the total amount of fields shown is limited to
|
||||||
# 10.
|
# 10.
|
||||||
# Minimum value: 0, maximum value: 100, default value: 10.
|
# Minimum value: 0, maximum value: 100, default value: 10.
|
||||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
# This tag requires that the tag UML_LOOK is set to YES.
|
||||||
|
|
||||||
UML_LIMIT_NUM_FIELDS = 10
|
UML_LIMIT_NUM_FIELDS = 10
|
||||||
|
|
||||||
|
# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and
|
||||||
|
# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS
|
||||||
|
# tag is set to YES, doxygen will add type and arguments for attributes and
|
||||||
|
# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen
|
||||||
|
# will not generate fields with class member information in the UML graphs. The
|
||||||
|
# class diagrams will look similar to the default class diagrams but using UML
|
||||||
|
# notation for the relationships.
|
||||||
|
# Possible values are: NO, YES and NONE.
|
||||||
|
# The default value is: NO.
|
||||||
|
# This tag requires that the tag UML_LOOK is set to YES.
|
||||||
|
|
||||||
|
DOT_UML_DETAILS = NO
|
||||||
|
|
||||||
|
# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters
|
||||||
|
# to display on a single line. If the actual line length exceeds this threshold
|
||||||
|
# significantly it will wrapped across multiple lines. Some heuristics are apply
|
||||||
|
# to avoid ugly line breaks.
|
||||||
|
# Minimum value: 0, maximum value: 1000, default value: 17.
|
||||||
|
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||||
|
|
||||||
|
DOT_WRAP_THRESHOLD = 17
|
||||||
|
|
||||||
# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
|
# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
|
||||||
# collaboration graphs will show the relations between templates and their
|
# collaboration graphs will show the relations between templates and their
|
||||||
# instances.
|
# instances.
|
||||||
|
@ -2554,9 +2659,11 @@ DOT_MULTI_TARGETS = NO
|
||||||
|
|
||||||
GENERATE_LEGEND = YES
|
GENERATE_LEGEND = YES
|
||||||
|
|
||||||
# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
|
# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate
|
||||||
# files that are used to generate the various graphs.
|
# files that are used to generate the various graphs.
|
||||||
|
#
|
||||||
|
# Note: This setting is not only used for dot files but also for msc and
|
||||||
|
# plantuml temporary files.
|
||||||
# The default value is: YES.
|
# The default value is: YES.
|
||||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
|
||||||
|
|
||||||
DOT_CLEANUP = YES
|
DOT_CLEANUP = YES
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
# The following lines of boilerplate have to be in your project's
|
||||||
|
# CMakeLists in this exact order for cmake to work correctly
|
||||||
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
|
||||||
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
|
set(SUPPORTED_TARGETS esp32c3 esp32s3)
|
||||||
|
project(NimBLE_extended_client)
|
3
examples/Bluetooth_5/NimBLE_extended_client/Makefile
Normal file
3
examples/Bluetooth_5/NimBLE_extended_client/Makefile
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
PROJECT_NAME := NimBLE_extended_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.)
|
169
examples/Bluetooth_5/NimBLE_extended_client/main/main.cpp
Normal file
169
examples/Bluetooth_5/NimBLE_extended_client/main/main.cpp
Normal file
|
@ -0,0 +1,169 @@
|
||||||
|
|
||||||
|
/** NimBLE Extended Client Demo:
|
||||||
|
*
|
||||||
|
* Demonstrates the Bluetooth 5.x client capabilities.
|
||||||
|
*
|
||||||
|
* Created: on April 2 2022
|
||||||
|
* Author: H2zero
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <NimBLEDevice.h>
|
||||||
|
|
||||||
|
extern "C" void app_main(void);
|
||||||
|
|
||||||
|
void scanEndedCB(NimBLEScanResults results);
|
||||||
|
|
||||||
|
#define SERVICE_UUID "ABCD"
|
||||||
|
#define CHARACTERISTIC_UUID "1234"
|
||||||
|
|
||||||
|
static NimBLEAdvertisedDevice* advDevice;
|
||||||
|
static bool doConnect = false;
|
||||||
|
static uint32_t scanTime = 10; /* 0 = scan forever */
|
||||||
|
|
||||||
|
/* Define the PHY's to use when connecting to peer devices, can be 1, 2, or all 3 (default).*/
|
||||||
|
static uint8_t connectPhys = BLE_GAP_LE_PHY_CODED_MASK | BLE_GAP_LE_PHY_1M_MASK /*| BLE_GAP_LE_PHY_2M_MASK */ ;
|
||||||
|
|
||||||
|
/* Define a class to handle the callbacks for client connection events */
|
||||||
|
class ClientCallbacks : public NimBLEClientCallbacks {
|
||||||
|
void onConnect(NimBLEClient* pClient) {
|
||||||
|
printf("Connected\n");
|
||||||
|
};
|
||||||
|
|
||||||
|
void onDisconnect(NimBLEClient* pClient) {
|
||||||
|
printf("%s Disconnected - Starting scan\n", pClient->getPeerAddress().toString().c_str());
|
||||||
|
NimBLEDevice::getScan()->start(scanTime, scanEndedCB);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Define a class to handle the callbacks when advertisements are received */
|
||||||
|
class AdvertisedDeviceCallbacks: public NimBLEAdvertisedDeviceCallbacks {
|
||||||
|
|
||||||
|
void onResult(NimBLEAdvertisedDevice* advertisedDevice) {
|
||||||
|
printf("Advertised Device found: %s\n", advertisedDevice->toString().c_str());
|
||||||
|
if(advertisedDevice->isAdvertisingService(NimBLEUUID("ABCD")))
|
||||||
|
{
|
||||||
|
printf("Found Our Service\n");
|
||||||
|
/* Ready to connect now */
|
||||||
|
doConnect = true;
|
||||||
|
/* Save the device reference in a global for the client to use*/
|
||||||
|
advDevice = advertisedDevice;
|
||||||
|
/* stop scan before connecting */
|
||||||
|
NimBLEDevice::getScan()->stop();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Callback to process the results of the last scan or restart it */
|
||||||
|
void scanEndedCB(NimBLEScanResults results){
|
||||||
|
printf("Scan Ended\n");
|
||||||
|
if (!doConnect) { /* Don't start the scan while connecting */
|
||||||
|
NimBLEDevice::getScan()->start(scanTime, scanEndedCB);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Handles the provisioning of clients and connects / interfaces with the server */
|
||||||
|
bool connectToServer() {
|
||||||
|
NimBLEClient* pClient = nullptr;
|
||||||
|
|
||||||
|
pClient = NimBLEDevice::createClient();
|
||||||
|
pClient->setClientCallbacks(new ClientCallbacks, false);
|
||||||
|
|
||||||
|
/* Set the PHY's to use for this connection. This is a bitmask that represents the PHY's:
|
||||||
|
* * 0x01 BLE_GAP_LE_PHY_1M_MASK
|
||||||
|
* * 0x02 BLE_GAP_LE_PHY_2M_MASK
|
||||||
|
* * 0x04 BLE_GAP_LE_PHY_CODED_MASK
|
||||||
|
* Combine these with OR ("|"), eg BLE_GAP_LE_PHY_1M_MASK | BLE_GAP_LE_PHY_2M_MASK | BLE_GAP_LE_PHY_CODED_MASK;
|
||||||
|
*/
|
||||||
|
pClient->setConnectPhy(connectPhys);
|
||||||
|
|
||||||
|
/** Set how long we are willing to wait for the connection to complete (seconds), default is 30. */
|
||||||
|
pClient->setConnectTimeout(10);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
pSvc = pClient->getService(SERVICE_UUID);
|
||||||
|
|
||||||
|
if (pSvc) {
|
||||||
|
pChr = pSvc->getCharacteristic(CHARACTERISTIC_UUID);
|
||||||
|
|
||||||
|
if (pChr) {
|
||||||
|
// Read the value of the characteristic.
|
||||||
|
if (pChr->canRead()) {
|
||||||
|
std::string value = pChr->readValue();
|
||||||
|
printf("Characteristic value: %s\n", value.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
printf("ABCD service not found.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
NimBLEDevice::deleteClient(pClient);
|
||||||
|
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) {
|
||||||
|
/* Found a device we want to connect to, do it now */
|
||||||
|
if (connectToServer()) {
|
||||||
|
printf("Success!, scanning for more!\n");
|
||||||
|
} else {
|
||||||
|
printf("Failed to connect, starting scan\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
doConnect = false;
|
||||||
|
NimBLEDevice::getScan()->start(scanTime, scanEndedCB);
|
||||||
|
}
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(10));
|
||||||
|
}
|
||||||
|
|
||||||
|
vTaskDelete(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void app_main (void) {
|
||||||
|
printf("Starting NimBLE Client\n");
|
||||||
|
/* Create a task to handle connecting to peers */
|
||||||
|
xTaskCreate(connectTask, "connectTask", 5000, NULL, 1, NULL);
|
||||||
|
|
||||||
|
/* Initialize NimBLE, no device name specified as we are not advertising */
|
||||||
|
NimBLEDevice::init("");
|
||||||
|
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(97);
|
||||||
|
pScan->setWindow(67);
|
||||||
|
|
||||||
|
/* 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");
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
# The following lines of boilerplate have to be in your project's
|
||||||
|
# CMakeLists in this exact order for cmake to work correctly
|
||||||
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
|
||||||
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
|
set(SUPPORTED_TARGETS esp32c3 esp32s3)
|
||||||
|
project(NimBLE_extended_server)
|
3
examples/Bluetooth_5/NimBLE_extended_server/Makefile
Normal file
3
examples/Bluetooth_5/NimBLE_extended_server/Makefile
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
PROJECT_NAME := NimBLE_extended_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.)
|
139
examples/Bluetooth_5/NimBLE_extended_server/main/main.cpp
Normal file
139
examples/Bluetooth_5/NimBLE_extended_server/main/main.cpp
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
/** NimBLE Extended Server Demo:
|
||||||
|
*
|
||||||
|
* Demonstrates the Bluetooth 5.x extended advertising capabilities.
|
||||||
|
*
|
||||||
|
* This demo will advertise a long data string on the CODED and 1M Phy's and
|
||||||
|
* starts a server allowing connection over either PHY's. It will advertise for
|
||||||
|
* 5 seconds then sleep for 20 seconds, if a client connects it will sleep once
|
||||||
|
* it has disconnected then repeats.
|
||||||
|
*
|
||||||
|
* Created: on April 2 2022
|
||||||
|
* Author: H2zero
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "NimBLEDevice.h"
|
||||||
|
#include "esp_sleep.h"
|
||||||
|
|
||||||
|
extern "C" void app_main(void);
|
||||||
|
|
||||||
|
#define SERVICE_UUID "ABCD"
|
||||||
|
#define CHARACTERISTIC_UUID "1234"
|
||||||
|
|
||||||
|
/* Time in milliseconds to advertise */
|
||||||
|
static uint32_t advTime = 5000;
|
||||||
|
|
||||||
|
/* Time to sleep between advertisements */
|
||||||
|
static uint32_t sleepSeconds = 20;
|
||||||
|
|
||||||
|
/* Primary PHY used for advertising, can be one of BLE_HCI_LE_PHY_1M or BLE_HCI_LE_PHY_CODED */
|
||||||
|
static uint8_t primaryPhy = BLE_HCI_LE_PHY_CODED;
|
||||||
|
|
||||||
|
/* Secondary PHY used for advertising and connecting,
|
||||||
|
* can be one of BLE_HCI_LE_PHY_1M, BLE_HCI_LE_PHY_2M or BLE_HCI_LE_PHY_CODED
|
||||||
|
*/
|
||||||
|
static uint8_t secondaryPhy = BLE_HCI_LE_PHY_1M;
|
||||||
|
|
||||||
|
|
||||||
|
/* Handler class for server events */
|
||||||
|
class ServerCallbacks: public NimBLEServerCallbacks {
|
||||||
|
void onConnect(NimBLEServer* pServer, ble_gap_conn_desc* desc) {
|
||||||
|
printf("Client connected: %s\n", NimBLEAddress(desc->peer_ota_addr).toString().c_str());
|
||||||
|
};
|
||||||
|
|
||||||
|
void onDisconnect(NimBLEServer* pServer) {
|
||||||
|
printf("Client disconnected - sleeping for %u seconds\n", sleepSeconds);
|
||||||
|
esp_deep_sleep_start();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Callback class to handle advertising events */
|
||||||
|
class advertisingCallbacks: public NimBLEExtAdvertisingCallbacks {
|
||||||
|
void onStopped(NimBLEExtAdvertising* pAdv, int reason, uint8_t inst_id) {
|
||||||
|
/* Check the reason advertising stopped, don't sleep if client is connecting */
|
||||||
|
printf("Advertising instance %u stopped\n", inst_id);
|
||||||
|
switch (reason) {
|
||||||
|
case 0:
|
||||||
|
printf("Client connecting\n");
|
||||||
|
return;
|
||||||
|
case BLE_HS_ETIMEOUT:
|
||||||
|
printf("Time expired - sleeping for %u seconds\n", sleepSeconds);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_deep_sleep_start();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void app_main (void) {
|
||||||
|
NimBLEDevice::init("Extended advertiser");
|
||||||
|
|
||||||
|
/* Create the server and add the services/characteristics/descriptors */
|
||||||
|
NimBLEServer *pServer = NimBLEDevice::createServer();
|
||||||
|
pServer->setCallbacks(new ServerCallbacks);
|
||||||
|
|
||||||
|
NimBLEService *pService = pServer->createService(SERVICE_UUID);
|
||||||
|
NimBLECharacteristic *pCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID,
|
||||||
|
NIMBLE_PROPERTY::READ |
|
||||||
|
NIMBLE_PROPERTY::WRITE |
|
||||||
|
NIMBLE_PROPERTY::NOTIFY);
|
||||||
|
|
||||||
|
pCharacteristic->setValue("Hello World");
|
||||||
|
|
||||||
|
/* Start the services */
|
||||||
|
pService->start();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create an extended advertisement with the instance ID 0 and set the PHY's.
|
||||||
|
* Multiple instances can be added as long as the instance ID is incremented.
|
||||||
|
*/
|
||||||
|
NimBLEExtAdvertisement extAdv(primaryPhy, secondaryPhy);
|
||||||
|
|
||||||
|
/* Set the advertisement as connectable */
|
||||||
|
extAdv.setConnectable(true);
|
||||||
|
|
||||||
|
/* As per Bluetooth specification, extended advertising cannot be both scannable and connectable */
|
||||||
|
extAdv.setScannable(false); // The default is false, set here for demonstration.
|
||||||
|
|
||||||
|
/* Extended advertising allows for 251 bytes (minus header bytes ~20) in a single advertisement or up to 1650 if chained */
|
||||||
|
extAdv.setServiceData(NimBLEUUID(SERVICE_UUID), std::string("Extended Advertising Demo.\r\n"
|
||||||
|
"Extended advertising allows for "
|
||||||
|
"251 bytes of data in a single advertisement,\r\n"
|
||||||
|
"or up to 1650 bytes with chaining.\r\n"
|
||||||
|
"This example message is 226 bytes long "
|
||||||
|
"and is using CODED_PHY for long range."));
|
||||||
|
|
||||||
|
extAdv.setCompleteServices16({NimBLEUUID(SERVICE_UUID)});
|
||||||
|
|
||||||
|
/* When extended advertising is enabled `NimBLEDevice::getAdvertising` returns a pointer to `NimBLEExtAdvertising */
|
||||||
|
NimBLEExtAdvertising* pAdvertising = NimBLEDevice::getAdvertising();
|
||||||
|
|
||||||
|
/* Set the callbacks for advertising events */
|
||||||
|
pAdvertising->setCallbacks(new advertisingCallbacks);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NimBLEExtAdvertising::setInstanceData takes the instance ID and
|
||||||
|
* a reference to a `NimBLEExtAdvertisement` object. This sets the data
|
||||||
|
* that will be advertised for this instance ID, returns true if successful.
|
||||||
|
*
|
||||||
|
* Note: It is safe to create the advertisement as a local variable if setInstanceData
|
||||||
|
* is called before exiting the code block as the data will be copied.
|
||||||
|
*/
|
||||||
|
if (pAdvertising->setInstanceData(0, extAdv)) {
|
||||||
|
/*
|
||||||
|
* `NimBLEExtAdvertising::start` takes the advertisement instance ID to start
|
||||||
|
* and a duration in milliseconds or a max number of advertisements to send (or both).
|
||||||
|
*/
|
||||||
|
if (pAdvertising->start(0, advTime)) {
|
||||||
|
printf("Started advertising\n");
|
||||||
|
} else {
|
||||||
|
printf("Failed to start advertising\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printf("Failed to register advertisment data\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_sleep_enable_timer_wakeup(sleepSeconds * 1000000);
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
# The following lines of boilerplate have to be in your project's
|
||||||
|
# CMakeLists in this exact order for cmake to work correctly
|
||||||
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
|
||||||
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
|
set(SUPPORTED_TARGETS esp32c3 esp32s3)
|
||||||
|
project(NimBLE_multi_advertiser)
|
3
examples/Bluetooth_5/NimBLE_multi_advertiser/Makefile
Normal file
3
examples/Bluetooth_5/NimBLE_multi_advertiser/Makefile
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
PROJECT_NAME := NimBLE_multi_advertiser
|
||||||
|
|
||||||
|
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.)
|
170
examples/Bluetooth_5/NimBLE_multi_advertiser/main/main.cpp
Normal file
170
examples/Bluetooth_5/NimBLE_multi_advertiser/main/main.cpp
Normal file
|
@ -0,0 +1,170 @@
|
||||||
|
/** NimBLE Multi Advertiser Demo:
|
||||||
|
*
|
||||||
|
* Demonstrates the Bluetooth 5.x extended advertising capabilities.
|
||||||
|
*
|
||||||
|
* This demo will advertise 2 advertisements, and extended scannable instance
|
||||||
|
* and a connectable legacy instance. They will advertise for 5 seconds then
|
||||||
|
* sleep for 20 seconds. The extended scannable instance will use the scan
|
||||||
|
* request callback to update it's data when a scan response is requested.
|
||||||
|
*
|
||||||
|
* Created: on April 9 2022
|
||||||
|
* Author: H2zero
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "NimBLEDevice.h"
|
||||||
|
#include "esp_sleep.h"
|
||||||
|
|
||||||
|
extern "C" void app_main(void);
|
||||||
|
|
||||||
|
#define SERVICE_UUID "ABCD"
|
||||||
|
#define CHARACTERISTIC_UUID "1234"
|
||||||
|
|
||||||
|
/* Time in milliseconds to advertise */
|
||||||
|
static uint32_t advTime = 5000;
|
||||||
|
|
||||||
|
/* Time to sleep between advertisements */
|
||||||
|
static uint32_t sleepTime = 20;
|
||||||
|
|
||||||
|
/* Primary PHY used for advertising, can be one of BLE_HCI_LE_PHY_1M or BLE_HCI_LE_PHY_CODED */
|
||||||
|
static uint8_t primaryPhy = BLE_HCI_LE_PHY_CODED;
|
||||||
|
|
||||||
|
/* Secondary PHY used for advertising and connecting,
|
||||||
|
* can be one of BLE_HCI_LE_PHY_1M, BLE_HCI_LE_PHY_2M or BLE_HCI_LE_PHY_CODED
|
||||||
|
*/
|
||||||
|
static uint8_t secondaryPhy = BLE_HCI_LE_PHY_1M;
|
||||||
|
|
||||||
|
|
||||||
|
/* Handler class for server events */
|
||||||
|
class ServerCallbacks: public NimBLEServerCallbacks {
|
||||||
|
void onConnect(NimBLEServer* pServer, ble_gap_conn_desc* desc) {
|
||||||
|
printf("Client connected: %s\n", NimBLEAddress(desc->peer_ota_addr).toString().c_str());
|
||||||
|
};
|
||||||
|
|
||||||
|
void onDisconnect(NimBLEServer* pServer) {
|
||||||
|
printf("Client disconnected\n");
|
||||||
|
// if still advertising we won't sleep yet.
|
||||||
|
if (!pServer->getAdvertising()->isAdvertising()) {
|
||||||
|
printf("Sleeping for %u seconds\n", sleepTime);
|
||||||
|
esp_deep_sleep_start();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Callback class to handle advertising events */
|
||||||
|
class advCallbacks: public NimBLEExtAdvertisingCallbacks {
|
||||||
|
void onStopped(NimBLEExtAdvertising* pAdv, int reason, uint8_t inst_id) {
|
||||||
|
/* Check the reason advertising stopped, don't sleep if client is connecting */
|
||||||
|
printf("Advertising instance %u stopped\n", inst_id);
|
||||||
|
switch (reason) {
|
||||||
|
case 0:
|
||||||
|
printf(" client connecting\n");
|
||||||
|
return;
|
||||||
|
case BLE_HS_ETIMEOUT:
|
||||||
|
printf("Time expired - sleeping for %u seconds\n", sleepTime);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_deep_sleep_start();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool m_updatedSR = false;
|
||||||
|
|
||||||
|
void onScanRequest(NimBLEExtAdvertising* pAdv, uint8_t inst_id, NimBLEAddress addr) {
|
||||||
|
printf("Scan request for instance %u\n", inst_id);
|
||||||
|
// if the data has already been updated we don't need to change it again.
|
||||||
|
if (!m_updatedSR) {
|
||||||
|
printf("Updating scan data\n");
|
||||||
|
NimBLEExtAdvertisement sr;
|
||||||
|
sr.setServiceData(NimBLEUUID(SERVICE_UUID), std::string("Hello from scan response!"));
|
||||||
|
pAdv->setScanResponseData(inst_id, sr);
|
||||||
|
m_updatedSR = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void app_main (void) {
|
||||||
|
NimBLEDevice::init("Multi advertiser");
|
||||||
|
|
||||||
|
/* Create a server for our legacy advertiser */
|
||||||
|
NimBLEServer *pServer = NimBLEDevice::createServer();
|
||||||
|
pServer->setCallbacks(new ServerCallbacks);
|
||||||
|
|
||||||
|
NimBLEService *pService = pServer->createService(SERVICE_UUID);
|
||||||
|
NimBLECharacteristic *pCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID,
|
||||||
|
NIMBLE_PROPERTY::READ |
|
||||||
|
NIMBLE_PROPERTY::WRITE |
|
||||||
|
NIMBLE_PROPERTY::NOTIFY);
|
||||||
|
|
||||||
|
pCharacteristic->setValue("Hello World");
|
||||||
|
|
||||||
|
/* Start the service */
|
||||||
|
pService->start();
|
||||||
|
|
||||||
|
/* Create our multi advertising instances */
|
||||||
|
|
||||||
|
// extended scannable instance advertising on coded and 1m PHY's.
|
||||||
|
NimBLEExtAdvertisement extScannable(primaryPhy, secondaryPhy);
|
||||||
|
|
||||||
|
// Legacy advertising as a connectable device.
|
||||||
|
NimBLEExtAdvertisement legacyConnectable;
|
||||||
|
|
||||||
|
// Optional scan response data.
|
||||||
|
NimBLEExtAdvertisement legacyScanResponse;
|
||||||
|
|
||||||
|
/* As per Bluetooth specification, extended advertising cannot be both scannable and connectable */
|
||||||
|
extScannable.setScannable(true);
|
||||||
|
extScannable.setConnectable(false);
|
||||||
|
|
||||||
|
/* Set the initial data */
|
||||||
|
extScannable.setServiceData(NimBLEUUID(SERVICE_UUID), std::string("Scan me!"));
|
||||||
|
|
||||||
|
/* enable the scan response callback, we will use this to update the data. */
|
||||||
|
extScannable.enableScanRequestCallback(true);
|
||||||
|
|
||||||
|
/* Optional custom address for this advertisment. */
|
||||||
|
legacyConnectable.setAddress(NimBLEAddress("DE:AD:BE:EF:BA:AD"));
|
||||||
|
|
||||||
|
/* Set the advertising data. */
|
||||||
|
legacyConnectable.setName("Legacy");
|
||||||
|
legacyConnectable.setCompleteServices16({NimBLEUUID(SERVICE_UUID)});
|
||||||
|
|
||||||
|
/* Set the legacy and connectable flags. */
|
||||||
|
legacyConnectable.setLegacyAdvertising(true);
|
||||||
|
legacyConnectable.setConnectable(true);
|
||||||
|
|
||||||
|
/* Put some data in the scan response if desired. */
|
||||||
|
legacyScanResponse.setServiceData(NimBLEUUID(SERVICE_UUID), "Legacy SR");
|
||||||
|
|
||||||
|
/* Get the advertising ready */
|
||||||
|
NimBLEExtAdvertising* pAdvertising = NimBLEDevice::getAdvertising();
|
||||||
|
|
||||||
|
/* Set the callbacks to handle advertising events */
|
||||||
|
pAdvertising->setCallbacks(new advCallbacks);
|
||||||
|
|
||||||
|
/* Set instance data.
|
||||||
|
* Up to 5 instances can be used if configured in menuconfig, instance 0 is always available.
|
||||||
|
*
|
||||||
|
* We will set the extended scannable data on instance 0 and the legacy data on instance 1.
|
||||||
|
* Note that the legacy scan response data needs to be set to the same instance (1).
|
||||||
|
*/
|
||||||
|
if (pAdvertising->setInstanceData( 0, extScannable ) &&
|
||||||
|
pAdvertising->setInstanceData( 1, legacyConnectable ) &&
|
||||||
|
pAdvertising->setScanResponseData( 1, legacyScanResponse )) {
|
||||||
|
/*
|
||||||
|
* `NimBLEExtAdvertising::start` takes the advertisement instance ID to start
|
||||||
|
* and a duration in milliseconds or a max number of advertisements to send (or both).
|
||||||
|
*/
|
||||||
|
if (pAdvertising->start(0, advTime) && pAdvertising->start(1, advTime)) {
|
||||||
|
printf("Started advertising\n");
|
||||||
|
} else {
|
||||||
|
printf("Failed to start advertising\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printf("Failed to register advertisment data\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_sleep_enable_timer_wakeup(sleepTime * 1000000);
|
||||||
|
}
|
|
@ -45,13 +45,8 @@
|
||||||
/* of data as per HID Class standard */
|
/* of data as per HID Class standard */
|
||||||
|
|
||||||
/* Main items */
|
/* Main items */
|
||||||
#ifdef ARDUINO_ARCH_ESP32
|
|
||||||
#define HIDINPUT(size) (0x80 | size)
|
#define HIDINPUT(size) (0x80 | size)
|
||||||
#define HIDOUTPUT(size) (0x90 | size)
|
#define HIDOUTPUT(size) (0x90 | size)
|
||||||
#else
|
|
||||||
#define INPUT(size) (0x80 | size)
|
|
||||||
#define OUTPUT(size) (0x90 | size)
|
|
||||||
#endif
|
|
||||||
#define FEATURE(size) (0xb0 | size)
|
#define FEATURE(size) (0xb0 | size)
|
||||||
#define COLLECTION(size) (0xa0 | size)
|
#define COLLECTION(size) (0xa0 | size)
|
||||||
#define END_COLLECTION(size) (0xc0 | size)
|
#define END_COLLECTION(size) (0xc0 | size)
|
||||||
|
|
|
@ -16,11 +16,8 @@
|
||||||
* See also:
|
* See also:
|
||||||
* https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.characteristic_presentation_format.xml
|
* https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.characteristic_presentation_format.xml
|
||||||
*/
|
*/
|
||||||
#include "sdkconfig.h"
|
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
|
||||||
|
|
||||||
#include "nimconfig.h"
|
#include "nimconfig.h"
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||||
|
|
||||||
#include "NimBLE2904.h"
|
#include "NimBLE2904.h"
|
||||||
|
|
||||||
|
@ -86,5 +83,4 @@ void NimBLE2904::setUnit(uint16_t unit) {
|
||||||
setValue((uint8_t*) &m_data, sizeof(m_data));
|
setValue((uint8_t*) &m_data, sizeof(m_data));
|
||||||
} // setUnit
|
} // setUnit
|
||||||
|
|
||||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||||
#endif
|
|
||||||
|
|
|
@ -14,11 +14,8 @@
|
||||||
|
|
||||||
#ifndef MAIN_NIMBLE2904_H_
|
#ifndef MAIN_NIMBLE2904_H_
|
||||||
#define MAIN_NIMBLE2904_H_
|
#define MAIN_NIMBLE2904_H_
|
||||||
#include "sdkconfig.h"
|
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
|
||||||
|
|
||||||
#include "nimconfig.h"
|
#include "nimconfig.h"
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||||
|
|
||||||
#include "NimBLEDescriptor.h"
|
#include "NimBLEDescriptor.h"
|
||||||
|
|
||||||
|
@ -82,6 +79,5 @@ private:
|
||||||
BLE2904_Data m_data;
|
BLE2904_Data m_data;
|
||||||
}; // BLE2904
|
}; // BLE2904
|
||||||
|
|
||||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||||
#endif /* CONFIG_BT_ENABLED */
|
|
||||||
#endif /* MAIN_NIMBLE2904_H_ */
|
#endif /* MAIN_NIMBLE2904_H_ */
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
* Created on: Jul 2, 2017
|
* Created on: Jul 2, 2017
|
||||||
* Author: kolban
|
* Author: kolban
|
||||||
*/
|
*/
|
||||||
#include "sdkconfig.h"
|
#include "nimconfig.h"
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
#if defined(CONFIG_BT_ENABLED)
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
|
@ -14,10 +14,15 @@
|
||||||
|
|
||||||
#ifndef COMPONENTS_NIMBLEADDRESS_H_
|
#ifndef COMPONENTS_NIMBLEADDRESS_H_
|
||||||
#define COMPONENTS_NIMBLEADDRESS_H_
|
#define COMPONENTS_NIMBLEADDRESS_H_
|
||||||
#include "sdkconfig.h"
|
#include "nimconfig.h"
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
#if defined(CONFIG_BT_ENABLED)
|
||||||
|
|
||||||
|
#if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||||
#include "nimble/ble.h"
|
#include "nimble/ble.h"
|
||||||
|
#else
|
||||||
|
#include "nimble/nimble/include/nimble/ble.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
/**** FIX COMPILATION ****/
|
/**** FIX COMPILATION ****/
|
||||||
#undef min
|
#undef min
|
||||||
#undef max
|
#undef max
|
||||||
|
|
|
@ -11,17 +11,17 @@
|
||||||
* Created on: Jul 3, 2017
|
* Created on: Jul 3, 2017
|
||||||
* Author: kolban
|
* Author: kolban
|
||||||
*/
|
*/
|
||||||
#include "sdkconfig.h"
|
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
|
||||||
|
|
||||||
#include "nimconfig.h"
|
#include "nimconfig.h"
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||||
|
|
||||||
#include "NimBLEDevice.h"
|
#include "NimBLEDevice.h"
|
||||||
#include "NimBLEAdvertisedDevice.h"
|
#include "NimBLEAdvertisedDevice.h"
|
||||||
#include "NimBLEUtils.h"
|
#include "NimBLEUtils.h"
|
||||||
#include "NimBLELog.h"
|
#include "NimBLELog.h"
|
||||||
|
|
||||||
|
#include <climits>
|
||||||
|
|
||||||
static const char* LOG_TAG = "NimBLEAdvertisedDevice";
|
static const char* LOG_TAG = "NimBLEAdvertisedDevice";
|
||||||
|
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ uint8_t NimBLEAdvertisedDevice::getAdvType() {
|
||||||
* @return The appearance of the advertised device.
|
* @return The appearance of the advertised device.
|
||||||
*/
|
*/
|
||||||
uint16_t NimBLEAdvertisedDevice::getAppearance() {
|
uint16_t NimBLEAdvertisedDevice::getAppearance() {
|
||||||
uint8_t data_loc = 0;
|
size_t data_loc = 0;
|
||||||
|
|
||||||
if(findAdvField(BLE_HS_ADV_TYPE_APPEARANCE, 0, &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];
|
ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||||
|
@ -89,7 +89,7 @@ uint16_t NimBLEAdvertisedDevice::getAppearance() {
|
||||||
* @return The advertisement interval in 0.625ms units.
|
* @return The advertisement interval in 0.625ms units.
|
||||||
*/
|
*/
|
||||||
uint16_t NimBLEAdvertisedDevice::getAdvInterval() {
|
uint16_t NimBLEAdvertisedDevice::getAdvInterval() {
|
||||||
uint8_t data_loc = 0;
|
size_t data_loc = 0;
|
||||||
|
|
||||||
if(findAdvField(BLE_HS_ADV_TYPE_ADV_ITVL, 0, &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];
|
ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||||
|
@ -107,7 +107,7 @@ uint16_t NimBLEAdvertisedDevice::getAdvInterval() {
|
||||||
* @return The preferred min connection interval in 1.25ms units.
|
* @return The preferred min connection interval in 1.25ms units.
|
||||||
*/
|
*/
|
||||||
uint16_t NimBLEAdvertisedDevice::getMinInterval() {
|
uint16_t NimBLEAdvertisedDevice::getMinInterval() {
|
||||||
uint8_t data_loc = 0;
|
size_t data_loc = 0;
|
||||||
|
|
||||||
if(findAdvField(BLE_HS_ADV_TYPE_SLAVE_ITVL_RANGE, 0, &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];
|
ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||||
|
@ -125,7 +125,7 @@ uint16_t NimBLEAdvertisedDevice::getMinInterval() {
|
||||||
* @return The preferred max connection interval in 1.25ms units.
|
* @return The preferred max connection interval in 1.25ms units.
|
||||||
*/
|
*/
|
||||||
uint16_t NimBLEAdvertisedDevice::getMaxInterval() {
|
uint16_t NimBLEAdvertisedDevice::getMaxInterval() {
|
||||||
uint8_t data_loc = 0;
|
size_t data_loc = 0;
|
||||||
|
|
||||||
if(findAdvField(BLE_HS_ADV_TYPE_SLAVE_ITVL_RANGE, 0, &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];
|
ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||||
|
@ -143,7 +143,7 @@ uint16_t NimBLEAdvertisedDevice::getMaxInterval() {
|
||||||
* @return The manufacturer data of the advertised device.
|
* @return The manufacturer data of the advertised device.
|
||||||
*/
|
*/
|
||||||
std::string NimBLEAdvertisedDevice::getManufacturerData() {
|
std::string NimBLEAdvertisedDevice::getManufacturerData() {
|
||||||
uint8_t data_loc = 0;
|
size_t data_loc = 0;
|
||||||
|
|
||||||
if(findAdvField(BLE_HS_ADV_TYPE_MFG_DATA, 0, &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];
|
ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||||
|
@ -161,7 +161,7 @@ std::string NimBLEAdvertisedDevice::getManufacturerData() {
|
||||||
* @return The URI data.
|
* @return The URI data.
|
||||||
*/
|
*/
|
||||||
std::string NimBLEAdvertisedDevice::getURI() {
|
std::string NimBLEAdvertisedDevice::getURI() {
|
||||||
uint8_t data_loc = 0;
|
size_t data_loc = 0;
|
||||||
|
|
||||||
if(findAdvField(BLE_HS_ADV_TYPE_URI, 0, &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];
|
ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||||
|
@ -179,7 +179,7 @@ std::string NimBLEAdvertisedDevice::getURI() {
|
||||||
* @return The name of the advertised device.
|
* @return The name of the advertised device.
|
||||||
*/
|
*/
|
||||||
std::string NimBLEAdvertisedDevice::getName() {
|
std::string NimBLEAdvertisedDevice::getName() {
|
||||||
uint8_t data_loc = 0;
|
size_t data_loc = 0;
|
||||||
|
|
||||||
if(findAdvField(BLE_HS_ADV_TYPE_COMP_NAME, 0, &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)
|
findAdvField(BLE_HS_ADV_TYPE_INCOMP_NAME, 0, &data_loc) > 0)
|
||||||
|
@ -216,7 +216,7 @@ NimBLEScan* NimBLEAdvertisedDevice::getScan() {
|
||||||
* @brief Get the number of target addresses.
|
* @brief Get the number of target addresses.
|
||||||
* @return The number of addresses.
|
* @return The number of addresses.
|
||||||
*/
|
*/
|
||||||
size_t NimBLEAdvertisedDevice::getTargetAddressCount() {
|
uint8_t NimBLEAdvertisedDevice::getTargetAddressCount() {
|
||||||
uint8_t count = 0;
|
uint8_t count = 0;
|
||||||
|
|
||||||
count = findAdvField(BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR);
|
count = findAdvField(BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR);
|
||||||
|
@ -234,7 +234,7 @@ size_t NimBLEAdvertisedDevice::getTargetAddressCount() {
|
||||||
NimBLEAddress NimBLEAdvertisedDevice::getTargetAddress(uint8_t index) {
|
NimBLEAddress NimBLEAdvertisedDevice::getTargetAddress(uint8_t index) {
|
||||||
ble_hs_adv_field *field = nullptr;
|
ble_hs_adv_field *field = nullptr;
|
||||||
uint8_t count = 0;
|
uint8_t count = 0;
|
||||||
uint8_t data_loc = 0xFF;
|
size_t data_loc = ULONG_MAX;
|
||||||
|
|
||||||
index++;
|
index++;
|
||||||
count = findAdvField(BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR, index, &data_loc);
|
count = findAdvField(BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR, index, &data_loc);
|
||||||
|
@ -244,7 +244,7 @@ NimBLEAddress NimBLEAdvertisedDevice::getTargetAddress(uint8_t index) {
|
||||||
count = findAdvField(BLE_HS_ADV_TYPE_RANDOM_TGT_ADDR, index, &data_loc);
|
count = findAdvField(BLE_HS_ADV_TYPE_RANDOM_TGT_ADDR, index, &data_loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(count > 0 && data_loc != 0xFF) {
|
if(count > 0 && data_loc != ULONG_MAX) {
|
||||||
field = (ble_hs_adv_field *)&m_payload[data_loc];
|
field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||||
if(field->length < index * BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN) {
|
if(field->length < index * BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN) {
|
||||||
index -= count - field->length / BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN;
|
index -= count - field->length / BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN;
|
||||||
|
@ -266,9 +266,9 @@ NimBLEAddress NimBLEAdvertisedDevice::getTargetAddress(uint8_t index) {
|
||||||
std::string NimBLEAdvertisedDevice::getServiceData(uint8_t index) {
|
std::string NimBLEAdvertisedDevice::getServiceData(uint8_t index) {
|
||||||
ble_hs_adv_field *field = nullptr;
|
ble_hs_adv_field *field = nullptr;
|
||||||
uint8_t bytes;
|
uint8_t bytes;
|
||||||
uint8_t data_loc = findServiceData(index, &bytes);
|
size_t data_loc = findServiceData(index, &bytes);
|
||||||
|
|
||||||
if(data_loc != 0xFF) {
|
if(data_loc != ULONG_MAX) {
|
||||||
field = (ble_hs_adv_field *)&m_payload[data_loc];
|
field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||||
if(field->length > bytes) {
|
if(field->length > bytes) {
|
||||||
return std::string((char*)(field->value + bytes), field->length - bytes - 1);
|
return std::string((char*)(field->value + bytes), field->length - bytes - 1);
|
||||||
|
@ -288,9 +288,9 @@ std::string NimBLEAdvertisedDevice::getServiceData(const NimBLEUUID &uuid) {
|
||||||
ble_hs_adv_field *field = nullptr;
|
ble_hs_adv_field *field = nullptr;
|
||||||
uint8_t bytes;
|
uint8_t bytes;
|
||||||
uint8_t index = 0;
|
uint8_t index = 0;
|
||||||
uint8_t data_loc = findServiceData(index, &bytes);
|
size_t data_loc = findServiceData(index, &bytes);
|
||||||
|
size_t plSize = m_payload.size() - 2;
|
||||||
uint8_t uuidBytes = uuid.bitSize() / 8;
|
uint8_t uuidBytes = uuid.bitSize() / 8;
|
||||||
uint8_t plSize = m_payload.size() - 2;
|
|
||||||
|
|
||||||
while(data_loc < plSize) {
|
while(data_loc < plSize) {
|
||||||
field = (ble_hs_adv_field *)&m_payload[data_loc];
|
field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||||
|
@ -315,9 +315,9 @@ std::string NimBLEAdvertisedDevice::getServiceData(const NimBLEUUID &uuid) {
|
||||||
NimBLEUUID NimBLEAdvertisedDevice::getServiceDataUUID(uint8_t index) {
|
NimBLEUUID NimBLEAdvertisedDevice::getServiceDataUUID(uint8_t index) {
|
||||||
ble_hs_adv_field *field = nullptr;
|
ble_hs_adv_field *field = nullptr;
|
||||||
uint8_t bytes;
|
uint8_t bytes;
|
||||||
uint8_t data_loc = findServiceData(index, &bytes);
|
size_t data_loc = findServiceData(index, &bytes);
|
||||||
|
|
||||||
if(data_loc != 0xFF) {
|
if(data_loc != ULONG_MAX) {
|
||||||
field = (ble_hs_adv_field *)&m_payload[data_loc];
|
field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||||
if(field->length >= bytes) {
|
if(field->length >= bytes) {
|
||||||
return NimBLEUUID(field->value, bytes, false);
|
return NimBLEUUID(field->value, bytes, false);
|
||||||
|
@ -332,10 +332,10 @@ NimBLEUUID NimBLEAdvertisedDevice::getServiceDataUUID(uint8_t index) {
|
||||||
* @brief Find the service data at the index.
|
* @brief Find the service data at the index.
|
||||||
* @param [in] index The index of the service data to find.
|
* @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.
|
* @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.
|
* @return The index in the vector where the data is located, ULONG_MAX if not found.
|
||||||
*/
|
*/
|
||||||
uint8_t NimBLEAdvertisedDevice::findServiceData(uint8_t index, uint8_t *bytes) {
|
size_t NimBLEAdvertisedDevice::findServiceData(uint8_t index, uint8_t *bytes) {
|
||||||
uint8_t data_loc = 0;
|
size_t data_loc = 0;
|
||||||
uint8_t found = 0;
|
uint8_t found = 0;
|
||||||
|
|
||||||
*bytes = 0;
|
*bytes = 0;
|
||||||
|
@ -360,7 +360,7 @@ uint8_t NimBLEAdvertisedDevice::findServiceData(uint8_t index, uint8_t *bytes) {
|
||||||
return data_loc;
|
return data_loc;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0xFF;
|
return ULONG_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -368,7 +368,7 @@ uint8_t NimBLEAdvertisedDevice::findServiceData(uint8_t index, uint8_t *bytes) {
|
||||||
* @brief Get the count of advertised service data UUIDS
|
* @brief Get the count of advertised service data UUIDS
|
||||||
* @return The number of service data UUIDS in the vector.
|
* @return The number of service data UUIDS in the vector.
|
||||||
*/
|
*/
|
||||||
size_t NimBLEAdvertisedDevice::getServiceDataCount() {
|
uint8_t NimBLEAdvertisedDevice::getServiceDataCount() {
|
||||||
uint8_t count = 0;
|
uint8_t count = 0;
|
||||||
|
|
||||||
count += findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID16);
|
count += findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID16);
|
||||||
|
@ -386,7 +386,7 @@ size_t NimBLEAdvertisedDevice::getServiceDataCount() {
|
||||||
*/
|
*/
|
||||||
NimBLEUUID NimBLEAdvertisedDevice::getServiceUUID(uint8_t index) {
|
NimBLEUUID NimBLEAdvertisedDevice::getServiceUUID(uint8_t index) {
|
||||||
uint8_t count = 0;
|
uint8_t count = 0;
|
||||||
uint8_t data_loc = 0;
|
size_t data_loc = 0;
|
||||||
uint8_t uuidBytes = 0;
|
uint8_t uuidBytes = 0;
|
||||||
uint8_t type = BLE_HS_ADV_TYPE_INCOMP_UUIDS16;
|
uint8_t type = BLE_HS_ADV_TYPE_INCOMP_UUIDS16;
|
||||||
ble_hs_adv_field *field = nullptr;
|
ble_hs_adv_field *field = nullptr;
|
||||||
|
@ -433,7 +433,7 @@ NimBLEUUID NimBLEAdvertisedDevice::getServiceUUID(uint8_t index) {
|
||||||
* @brief Get the number of services advertised
|
* @brief Get the number of services advertised
|
||||||
* @return The count of services in the advertising packet.
|
* @return The count of services in the advertising packet.
|
||||||
*/
|
*/
|
||||||
size_t NimBLEAdvertisedDevice::getServiceUUIDCount() {
|
uint8_t NimBLEAdvertisedDevice::getServiceUUIDCount() {
|
||||||
uint8_t count = 0;
|
uint8_t count = 0;
|
||||||
|
|
||||||
count += findAdvField(BLE_HS_ADV_TYPE_INCOMP_UUIDS16);
|
count += findAdvField(BLE_HS_ADV_TYPE_INCOMP_UUIDS16);
|
||||||
|
@ -469,7 +469,7 @@ bool NimBLEAdvertisedDevice::isAdvertisingService(const NimBLEUUID &uuid) {
|
||||||
* @return The TX Power of the advertised device.
|
* @return The TX Power of the advertised device.
|
||||||
*/
|
*/
|
||||||
int8_t NimBLEAdvertisedDevice::getTXPower() {
|
int8_t NimBLEAdvertisedDevice::getTXPower() {
|
||||||
uint8_t data_loc = 0;
|
size_t data_loc = 0;
|
||||||
|
|
||||||
if(findAdvField(BLE_HS_ADV_TYPE_TX_PWR_LVL, 0, &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];
|
ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||||
|
@ -583,17 +583,60 @@ bool NimBLEAdvertisedDevice::haveTXPower() {
|
||||||
} // haveTXPower
|
} // haveTXPower
|
||||||
|
|
||||||
|
|
||||||
uint8_t NimBLEAdvertisedDevice::findAdvField(uint8_t type, uint8_t index, uint8_t *data_loc) {
|
#if CONFIG_BT_NIMBLE_EXT_ADV
|
||||||
|
/**
|
||||||
|
* @brief Get the set ID of the extended advertisement.
|
||||||
|
* @return The set ID.
|
||||||
|
*/
|
||||||
|
uint8_t NimBLEAdvertisedDevice::getSetId() {
|
||||||
|
return m_sid;
|
||||||
|
} // getSetId
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the primary PHY used by this advertisement.
|
||||||
|
* @return The PHY type, one of:
|
||||||
|
* * BLE_HCI_LE_PHY_1M
|
||||||
|
* * BLE_HCI_LE_PHY_CODED
|
||||||
|
*/
|
||||||
|
uint8_t NimBLEAdvertisedDevice::getPrimaryPhy() {
|
||||||
|
return m_primPhy;
|
||||||
|
} // getPrimaryPhy
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the primary PHY used by this advertisement.
|
||||||
|
* @return The PHY type, one of:
|
||||||
|
* * BLE_HCI_LE_PHY_1M
|
||||||
|
* * BLE_HCI_LE_PHY_2M
|
||||||
|
* * BLE_HCI_LE_PHY_CODED
|
||||||
|
*/
|
||||||
|
uint8_t NimBLEAdvertisedDevice::getSecondaryPhy() {
|
||||||
|
return m_secPhy;
|
||||||
|
} // getSecondaryPhy
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the periodic interval of the advertisement.
|
||||||
|
* @return The periodic advertising interval, 0 if not periodic advertising.
|
||||||
|
*/
|
||||||
|
uint16_t NimBLEAdvertisedDevice::getPeriodicInterval() {
|
||||||
|
return m_periodicItvl;
|
||||||
|
} // getPeriodicInterval
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t NimBLEAdvertisedDevice::findAdvField(uint8_t type, uint8_t index, size_t * data_loc) {
|
||||||
ble_hs_adv_field *field = nullptr;
|
ble_hs_adv_field *field = nullptr;
|
||||||
uint8_t data = 0;
|
size_t length = m_payload.size();
|
||||||
uint8_t length = m_payload.size();
|
size_t data = 0;
|
||||||
uint8_t count = 0;
|
uint8_t count = 0;
|
||||||
|
|
||||||
if(length < 2) {
|
if (length < 3) {
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (length > 1) {
|
while (length > 2) {
|
||||||
field = (ble_hs_adv_field*)&m_payload[data];
|
field = (ble_hs_adv_field*)&m_payload[data];
|
||||||
|
|
||||||
if (field->length >= length) {
|
if (field->length >= length) {
|
||||||
|
@ -659,8 +702,13 @@ void NimBLEAdvertisedDevice::setAddress(NimBLEAddress address) {
|
||||||
* @brief Set the adFlag for this device.
|
* @brief Set the adFlag for this device.
|
||||||
* @param [in] advType The advertisement flag data from the advertisement.
|
* @param [in] advType The advertisement flag data from the advertisement.
|
||||||
*/
|
*/
|
||||||
void NimBLEAdvertisedDevice::setAdvType(uint8_t advType) {
|
void NimBLEAdvertisedDevice::setAdvType(uint8_t advType, bool isLegacyAdv) {
|
||||||
m_advType = advType;
|
m_advType = advType;
|
||||||
|
#if CONFIG_BT_NIMBLE_EXT_ADV
|
||||||
|
m_isLegacyAdv = isLegacyAdv;
|
||||||
|
#else
|
||||||
|
(void)isLegacyAdv;
|
||||||
|
#endif
|
||||||
} // setAdvType
|
} // setAdvType
|
||||||
|
|
||||||
|
|
||||||
|
@ -706,9 +754,9 @@ std::string NimBLEAdvertisedDevice::toString() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (haveServiceData()) {
|
if (haveServiceData()) {
|
||||||
size_t count = getServiceDataCount();
|
uint8_t count = getServiceDataCount();
|
||||||
res += "\nService Data:";
|
res += "\nService Data:";
|
||||||
for(size_t i = 0; i < count; i++) {
|
for(uint8_t i = 0; i < count; i++) {
|
||||||
res += "\nUUID: " + std::string(getServiceDataUUID(i));
|
res += "\nUUID: " + std::string(getServiceDataUUID(i));
|
||||||
res += ", Data: " + getServiceData(i);
|
res += ", Data: " + getServiceData(i);
|
||||||
}
|
}
|
||||||
|
@ -784,6 +832,33 @@ size_t NimBLEAdvertisedDevice::getPayloadLength() {
|
||||||
} // getPayloadLength
|
} // getPayloadLength
|
||||||
|
|
||||||
|
|
||||||
#endif // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
/**
|
||||||
#endif /* CONFIG_BT_ENABLED */
|
* @brief Check if this device is advertising as connectable.
|
||||||
|
* @return True if the device is connectable.
|
||||||
|
*/
|
||||||
|
bool NimBLEAdvertisedDevice::isConnectable() {
|
||||||
|
#if CONFIG_BT_NIMBLE_EXT_ADV
|
||||||
|
if (m_isLegacyAdv) {
|
||||||
|
return m_advType == BLE_HCI_ADV_RPT_EVTYPE_ADV_IND ||
|
||||||
|
m_advType == BLE_HCI_ADV_RPT_EVTYPE_DIR_IND;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return (m_advType & BLE_HCI_ADV_CONN_MASK) ||
|
||||||
|
(m_advType & BLE_HCI_ADV_DIRECT_MASK);
|
||||||
|
} // isConnectable
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if this advertisement is a legacy or extended type
|
||||||
|
* @return True if legacy (Bluetooth 4.x), false if extended (bluetooth 5.x).
|
||||||
|
*/
|
||||||
|
bool NimBLEAdvertisedDevice::isLegacyAdvertisement() {
|
||||||
|
#if CONFIG_BT_NIMBLE_EXT_ADV
|
||||||
|
return m_isLegacyAdv;
|
||||||
|
# else
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
} // isLegacyAdvertisement
|
||||||
|
|
||||||
|
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|
||||||
|
|
||||||
|
|
|
@ -14,20 +14,22 @@
|
||||||
|
|
||||||
#ifndef COMPONENTS_NIMBLEADVERTISEDDEVICE_H_
|
#ifndef COMPONENTS_NIMBLEADVERTISEDDEVICE_H_
|
||||||
#define COMPONENTS_NIMBLEADVERTISEDDEVICE_H_
|
#define COMPONENTS_NIMBLEADVERTISEDDEVICE_H_
|
||||||
#include "sdkconfig.h"
|
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
|
||||||
|
|
||||||
#include "nimconfig.h"
|
#include "nimconfig.h"
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||||
|
|
||||||
#include "NimBLEAddress.h"
|
#include "NimBLEAddress.h"
|
||||||
#include "NimBLEScan.h"
|
#include "NimBLEScan.h"
|
||||||
#include "NimBLEUUID.h"
|
#include "NimBLEUUID.h"
|
||||||
|
|
||||||
|
#if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||||
#include "host/ble_hs_adv.h"
|
#include "host/ble_hs_adv.h"
|
||||||
|
#else
|
||||||
|
#include "nimble/nimble/host/include/host/ble_hs_adv.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
|
||||||
class NimBLEScan;
|
class NimBLEScan;
|
||||||
|
@ -69,7 +71,7 @@ public:
|
||||||
std::string getName();
|
std::string getName();
|
||||||
int getRSSI();
|
int getRSSI();
|
||||||
NimBLEScan* getScan();
|
NimBLEScan* getScan();
|
||||||
size_t getServiceDataCount();
|
uint8_t getServiceDataCount();
|
||||||
std::string getServiceData(uint8_t index = 0);
|
std::string getServiceData(uint8_t index = 0);
|
||||||
std::string getServiceData(const NimBLEUUID &uuid);
|
std::string getServiceData(const NimBLEUUID &uuid);
|
||||||
|
|
||||||
|
@ -109,9 +111,9 @@ public:
|
||||||
|
|
||||||
NimBLEUUID getServiceDataUUID(uint8_t index = 0);
|
NimBLEUUID getServiceDataUUID(uint8_t index = 0);
|
||||||
NimBLEUUID getServiceUUID(uint8_t index = 0);
|
NimBLEUUID getServiceUUID(uint8_t index = 0);
|
||||||
size_t getServiceUUIDCount();
|
uint8_t getServiceUUIDCount();
|
||||||
NimBLEAddress getTargetAddress(uint8_t index = 0);
|
NimBLEAddress getTargetAddress(uint8_t index = 0);
|
||||||
size_t getTargetAddressCount();
|
uint8_t getTargetAddressCount();
|
||||||
int8_t getTXPower();
|
int8_t getTXPower();
|
||||||
uint8_t* getPayload();
|
uint8_t* getPayload();
|
||||||
uint8_t getAdvLength();
|
uint8_t getAdvLength();
|
||||||
|
@ -131,16 +133,30 @@ public:
|
||||||
bool haveTargetAddress();
|
bool haveTargetAddress();
|
||||||
bool haveURI();
|
bool haveURI();
|
||||||
std::string toString();
|
std::string toString();
|
||||||
|
bool isConnectable();
|
||||||
|
bool isLegacyAdvertisement();
|
||||||
|
#if CONFIG_BT_NIMBLE_EXT_ADV
|
||||||
|
uint8_t getSetId();
|
||||||
|
uint8_t getPrimaryPhy();
|
||||||
|
uint8_t getSecondaryPhy();
|
||||||
|
uint16_t getPeriodicInterval();
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class NimBLEScan;
|
friend class NimBLEScan;
|
||||||
|
|
||||||
void setAddress(NimBLEAddress address);
|
void setAddress(NimBLEAddress address);
|
||||||
void setAdvType(uint8_t advType);
|
void setAdvType(uint8_t advType, bool isLegacyAdv);
|
||||||
void setPayload(const uint8_t *payload, uint8_t length, bool append);
|
void setPayload(const uint8_t *payload, uint8_t length, bool append);
|
||||||
void setRSSI(int rssi);
|
void setRSSI(int rssi);
|
||||||
uint8_t findAdvField(uint8_t type, uint8_t index = 0, uint8_t *data_loc = nullptr);
|
#if CONFIG_BT_NIMBLE_EXT_ADV
|
||||||
uint8_t findServiceData(uint8_t index, uint8_t* bytes);
|
void setSetId(uint8_t sid) { m_sid = sid; }
|
||||||
|
void setPrimaryPhy(uint8_t phy) { m_primPhy = phy; }
|
||||||
|
void setSecondaryPhy(uint8_t phy) { m_secPhy = phy; }
|
||||||
|
void setPeriodicInterval(uint16_t itvl) { m_periodicItvl = itvl; }
|
||||||
|
#endif
|
||||||
|
uint8_t findAdvField(uint8_t type, uint8_t index = 0, size_t * data_loc = nullptr);
|
||||||
|
size_t findServiceData(uint8_t index, uint8_t* bytes);
|
||||||
|
|
||||||
NimBLEAddress m_address = NimBLEAddress("");
|
NimBLEAddress m_address = NimBLEAddress("");
|
||||||
uint8_t m_advType;
|
uint8_t m_advType;
|
||||||
|
@ -148,6 +164,13 @@ private:
|
||||||
time_t m_timestamp;
|
time_t m_timestamp;
|
||||||
bool m_callbackSent;
|
bool m_callbackSent;
|
||||||
uint8_t m_advLength;
|
uint8_t m_advLength;
|
||||||
|
#if CONFIG_BT_NIMBLE_EXT_ADV
|
||||||
|
bool m_isLegacyAdv;
|
||||||
|
uint8_t m_sid;
|
||||||
|
uint8_t m_primPhy;
|
||||||
|
uint8_t m_secPhy;
|
||||||
|
uint16_t m_periodicItvl;
|
||||||
|
#endif
|
||||||
|
|
||||||
std::vector<uint8_t> m_payload;
|
std::vector<uint8_t> m_payload;
|
||||||
};
|
};
|
||||||
|
@ -171,6 +194,5 @@ public:
|
||||||
virtual void onResult(NimBLEAdvertisedDevice* advertisedDevice) = 0;
|
virtual void onResult(NimBLEAdvertisedDevice* advertisedDevice) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_OBSERVER */
|
||||||
#endif /* CONFIG_BT_ENABLED */
|
|
||||||
#endif /* COMPONENTS_NIMBLEADVERTISEDDEVICE_H_ */
|
#endif /* COMPONENTS_NIMBLEADVERTISEDDEVICE_H_ */
|
||||||
|
|
|
@ -13,13 +13,16 @@
|
||||||
* Author: kolban
|
* Author: kolban
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#include "sdkconfig.h"
|
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
|
||||||
|
|
||||||
#include "nimconfig.h"
|
#include "nimconfig.h"
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
#if (defined(CONFIG_BT_ENABLED) && \
|
||||||
|
defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER) && \
|
||||||
|
!CONFIG_BT_NIMBLE_EXT_ADV) || defined(_DOXYGEN_)
|
||||||
|
|
||||||
|
#if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||||
#include "services/gap/ble_svc_gap.h"
|
#include "services/gap/ble_svc_gap.h"
|
||||||
|
#else
|
||||||
|
#include "nimble/nimble/host/services/gap/include/services/gap/ble_svc_gap.h"
|
||||||
|
#endif
|
||||||
#include "NimBLEAdvertising.h"
|
#include "NimBLEAdvertising.h"
|
||||||
#include "NimBLEDevice.h"
|
#include "NimBLEDevice.h"
|
||||||
#include "NimBLEServer.h"
|
#include "NimBLEServer.h"
|
||||||
|
@ -68,6 +71,7 @@ void NimBLEAdvertising::reset() {
|
||||||
m_advDataSet = false;
|
m_advDataSet = false;
|
||||||
// Set this to non-zero to prevent auto start if host reset before started by app.
|
// Set this to non-zero to prevent auto start if host reset before started by app.
|
||||||
m_duration = BLE_HS_FOREVER;
|
m_duration = BLE_HS_FOREVER;
|
||||||
|
m_advCompCB = nullptr;
|
||||||
} // reset
|
} // reset
|
||||||
|
|
||||||
|
|
||||||
|
@ -410,7 +414,7 @@ bool NimBLEAdvertising::start(uint32_t duration, void (*advCompleteCB)(NimBLEAdv
|
||||||
// If already advertising just return
|
// If already advertising just return
|
||||||
if(ble_gap_adv_active()) {
|
if(ble_gap_adv_active()) {
|
||||||
NIMBLE_LOGW(LOG_TAG, "Advertising already active");
|
NIMBLE_LOGW(LOG_TAG, "Advertising already active");
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save the duration incase of host reset so we can restart with the same params
|
// Save the duration incase of host reset so we can restart with the same params
|
||||||
|
@ -623,7 +627,7 @@ bool NimBLEAdvertising::start(uint32_t duration, void (*advCompleteCB)(NimBLEAdv
|
||||||
&m_advParams,
|
&m_advParams,
|
||||||
(pServer != nullptr) ? NimBLEServer::handleGapEvent :
|
(pServer != nullptr) ? NimBLEServer::handleGapEvent :
|
||||||
NimBLEAdvertising::handleGapEvent,
|
NimBLEAdvertising::handleGapEvent,
|
||||||
(pServer != nullptr) ? (void*)pServer : (void*)this);
|
(void*)this);
|
||||||
#else
|
#else
|
||||||
rc = ble_gap_adv_start(NimBLEDevice::m_own_addr_type, NULL, duration,
|
rc = ble_gap_adv_start(NimBLEDevice::m_own_addr_type, NULL, duration,
|
||||||
&m_advParams, NimBLEAdvertising::handleGapEvent, this);
|
&m_advParams, NimBLEAdvertising::handleGapEvent, this);
|
||||||
|
@ -632,6 +636,10 @@ bool NimBLEAdvertising::start(uint32_t duration, void (*advCompleteCB)(NimBLEAdv
|
||||||
case 0:
|
case 0:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case BLE_HS_EALREADY:
|
||||||
|
NIMBLE_LOGI(LOG_TAG, "Advertisement Already active");
|
||||||
|
break;
|
||||||
|
|
||||||
case BLE_HS_EINVAL:
|
case BLE_HS_EINVAL:
|
||||||
NIMBLE_LOGE(LOG_TAG, "Unable to advertise - Duration too long");
|
NIMBLE_LOGE(LOG_TAG, "Unable to advertise - Duration too long");
|
||||||
break;
|
break;
|
||||||
|
@ -653,29 +661,27 @@ bool NimBLEAdvertising::start(uint32_t duration, void (*advCompleteCB)(NimBLEAdv
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(rc != 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< Advertising start");
|
NIMBLE_LOGD(LOG_TAG, "<< Advertising start");
|
||||||
return true;
|
return (rc == 0 || rc == BLE_HS_EALREADY);
|
||||||
} // start
|
} // start
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Stop advertising.
|
* @brief Stop advertising.
|
||||||
|
* @return True if advertising stopped successfully.
|
||||||
*/
|
*/
|
||||||
void NimBLEAdvertising::stop() {
|
bool NimBLEAdvertising::stop() {
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> stop");
|
NIMBLE_LOGD(LOG_TAG, ">> stop");
|
||||||
|
|
||||||
int rc = ble_gap_adv_stop();
|
int rc = ble_gap_adv_stop();
|
||||||
if (rc != 0 && rc != BLE_HS_EALREADY) {
|
if (rc != 0 && rc != BLE_HS_EALREADY) {
|
||||||
NIMBLE_LOGE(LOG_TAG, "ble_gap_adv_stop rc=%d %s",
|
NIMBLE_LOGE(LOG_TAG, "ble_gap_adv_stop rc=%d %s",
|
||||||
rc, NimBLEUtils::returnCodeToString(rc));
|
rc, NimBLEUtils::returnCodeToString(rc));
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< stop");
|
NIMBLE_LOGD(LOG_TAG, "<< stop");
|
||||||
|
return true;
|
||||||
} // stop
|
} // stop
|
||||||
|
|
||||||
|
|
||||||
|
@ -1028,5 +1034,4 @@ std::string NimBLEAdvertisementData::getPayload() {
|
||||||
return m_payload;
|
return m_payload;
|
||||||
} // getPayload
|
} // getPayload
|
||||||
|
|
||||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER && !CONFIG_BT_NIMBLE_EXT_ADV */
|
||||||
#endif /* CONFIG_BT_ENABLED */
|
|
||||||
|
|
|
@ -14,13 +14,17 @@
|
||||||
|
|
||||||
#ifndef MAIN_BLEADVERTISING_H_
|
#ifndef MAIN_BLEADVERTISING_H_
|
||||||
#define MAIN_BLEADVERTISING_H_
|
#define MAIN_BLEADVERTISING_H_
|
||||||
#include "sdkconfig.h"
|
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
|
||||||
|
|
||||||
#include "nimconfig.h"
|
#include "nimconfig.h"
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
#if (defined(CONFIG_BT_ENABLED) && \
|
||||||
|
defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER) && \
|
||||||
|
!CONFIG_BT_NIMBLE_EXT_ADV) || defined(_DOXYGEN_)
|
||||||
|
|
||||||
|
#if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||||
#include "host/ble_gap.h"
|
#include "host/ble_gap.h"
|
||||||
|
#else
|
||||||
|
#include "nimble/nimble/host/include/host/ble_gap.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
/**** FIX COMPILATION ****/
|
/**** FIX COMPILATION ****/
|
||||||
#undef min
|
#undef min
|
||||||
#undef max
|
#undef max
|
||||||
|
@ -87,7 +91,7 @@ public:
|
||||||
void addServiceUUID(const char* serviceUUID);
|
void addServiceUUID(const char* serviceUUID);
|
||||||
void removeServiceUUID(const NimBLEUUID &serviceUUID);
|
void removeServiceUUID(const NimBLEUUID &serviceUUID);
|
||||||
bool start(uint32_t duration = 0, void (*advCompleteCB)(NimBLEAdvertising *pAdv) = nullptr);
|
bool start(uint32_t duration = 0, void (*advCompleteCB)(NimBLEAdvertising *pAdv) = nullptr);
|
||||||
void stop();
|
bool stop();
|
||||||
void setAppearance(uint16_t appearance);
|
void setAppearance(uint16_t appearance);
|
||||||
void setName(const std::string &name);
|
void setName(const std::string &name);
|
||||||
void setManufacturerData(const std::string &data);
|
void setManufacturerData(const std::string &data);
|
||||||
|
@ -109,6 +113,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class NimBLEDevice;
|
friend class NimBLEDevice;
|
||||||
|
friend class NimBLEServer;
|
||||||
|
|
||||||
void onHostSync();
|
void onHostSync();
|
||||||
static int handleGapEvent(struct ble_gap_event *event, void *arg);
|
static int handleGapEvent(struct ble_gap_event *event, void *arg);
|
||||||
|
@ -132,6 +137,5 @@ private:
|
||||||
std::vector<uint8_t> m_uri;
|
std::vector<uint8_t> m_uri;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER && !CONFIG_BT_NIMBLE_EXT_ADV */
|
||||||
#endif /* CONFIG_BT_ENABLED */
|
|
||||||
#endif /* MAIN_BLEADVERTISING_H_ */
|
#endif /* MAIN_BLEADVERTISING_H_ */
|
||||||
|
|
447
src/NimBLEAttValue.h
Normal file
447
src/NimBLEAttValue.h
Normal file
|
@ -0,0 +1,447 @@
|
||||||
|
/*
|
||||||
|
* NimBLEAttValue.h
|
||||||
|
*
|
||||||
|
* Created: on March 18, 2021
|
||||||
|
* Author H2zero
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MAIN_NIMBLEATTVALUE_H_
|
||||||
|
#define MAIN_NIMBLEATTVALUE_H_
|
||||||
|
#include "nimconfig.h"
|
||||||
|
#if defined(CONFIG_BT_ENABLED)
|
||||||
|
|
||||||
|
#ifdef NIMBLE_CPP_ARDUINO_STRING_AVAILABLE
|
||||||
|
#include <Arduino.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "NimBLELog.h"
|
||||||
|
|
||||||
|
/**** FIX COMPILATION ****/
|
||||||
|
#undef min
|
||||||
|
#undef max
|
||||||
|
/**************************/
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#ifndef CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
|
||||||
|
# define CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
|
||||||
|
# include <time.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH)
|
||||||
|
# define CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH 20
|
||||||
|
#elif CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH > BLE_ATT_ATTR_MAX_LEN
|
||||||
|
# error CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH cannot be larger than 512 (BLE_ATT_ATTR_MAX_LEN)
|
||||||
|
#elif CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH < 1
|
||||||
|
# error CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH cannot be less than 1; Range = 1 : 512
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Used to determine if the type passed to a template has a c_str() and length() method. */
|
||||||
|
template <typename T, typename = void, typename = void>
|
||||||
|
struct Has_c_str_len : std::false_type {};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct Has_c_str_len<T, decltype(void(std::declval<T &>().c_str())),
|
||||||
|
decltype(void(std::declval<T &>().length()))> : std::true_type {};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A specialized container class to hold BLE attribute values.
|
||||||
|
* @details This class is designed to be more memory efficient than using\n
|
||||||
|
* standard container types for value storage, while being convertable to\n
|
||||||
|
* many different container classes.
|
||||||
|
*/
|
||||||
|
class NimBLEAttValue
|
||||||
|
{
|
||||||
|
uint8_t* m_attr_value = nullptr;
|
||||||
|
uint16_t m_attr_max_len = 0;
|
||||||
|
uint16_t m_attr_len = 0;
|
||||||
|
uint16_t m_capacity = 0;
|
||||||
|
#if CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
|
||||||
|
time_t m_timestamp = 0;
|
||||||
|
#endif
|
||||||
|
void deepCopy(const NimBLEAttValue & source);
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Default constructor.
|
||||||
|
* @param[in] init_len The initial size in bytes.
|
||||||
|
* @param[in] max_len The max size in bytes that the value can be.
|
||||||
|
*/
|
||||||
|
NimBLEAttValue(uint16_t init_len = CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH,
|
||||||
|
uint16_t max_len = BLE_ATT_ATTR_MAX_LEN);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct with an initial value from a buffer.
|
||||||
|
* @param value A pointer to the initial value to set.
|
||||||
|
* @param[in] len The size in bytes of the value to set.
|
||||||
|
* @param[in] max_len The max size in bytes that the value can be.
|
||||||
|
*/
|
||||||
|
NimBLEAttValue(const uint8_t *value, uint16_t len,
|
||||||
|
uint16_t max_len = BLE_ATT_ATTR_MAX_LEN);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct with an initializer list.
|
||||||
|
* @param list An initializer list containing the initial value to set.
|
||||||
|
* @param[in] max_len The max size in bytes that the value can be.
|
||||||
|
*/
|
||||||
|
NimBLEAttValue(std::initializer_list<uint8_t> list,
|
||||||
|
uint16_t max_len = BLE_ATT_ATTR_MAX_LEN)
|
||||||
|
:NimBLEAttValue(list.begin(), (uint16_t)list.size(), max_len){}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct with an initial value from a const char string.
|
||||||
|
* @param value A pointer to the initial value to set.
|
||||||
|
* @param[in] max_len The max size in bytes that the value can be.
|
||||||
|
*/
|
||||||
|
NimBLEAttValue(const char *value, uint16_t max_len = BLE_ATT_ATTR_MAX_LEN)
|
||||||
|
:NimBLEAttValue((uint8_t*)value, (uint16_t)strlen(value), max_len){}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct with an initial value from a std::string.
|
||||||
|
* @param str A std::string containing to the initial value to set.
|
||||||
|
* @param[in] max_len The max size in bytes that the value can be.
|
||||||
|
*/
|
||||||
|
NimBLEAttValue(const std::string str, uint16_t max_len = BLE_ATT_ATTR_MAX_LEN)
|
||||||
|
:NimBLEAttValue((uint8_t*)str.data(), (uint16_t)str.length(), max_len){}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct with an initial value from a std::vector<uint8_t>.
|
||||||
|
* @param vec A std::vector<uint8_t> containing to the initial value to set.
|
||||||
|
* @param[in] max_len The max size in bytes that the value can be.
|
||||||
|
*/
|
||||||
|
NimBLEAttValue(const std::vector<uint8_t> vec, uint16_t max_len = BLE_ATT_ATTR_MAX_LEN)
|
||||||
|
:NimBLEAttValue(&vec[0], (uint16_t)vec.size(), max_len){}
|
||||||
|
|
||||||
|
#ifdef NIMBLE_CPP_ARDUINO_STRING_AVAILABLE
|
||||||
|
/**
|
||||||
|
* @brief Construct with an initial value from an Arduino String.
|
||||||
|
* @param str An Arduino String containing to the initial value to set.
|
||||||
|
* @param[in] max_len The max size in bytes that the value can be.
|
||||||
|
*/
|
||||||
|
NimBLEAttValue(const String str, uint16_t max_len = BLE_ATT_ATTR_MAX_LEN)
|
||||||
|
:NimBLEAttValue((uint8_t*)str.c_str(), str.length(), max_len){}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** @brief Copy constructor */
|
||||||
|
NimBLEAttValue(const NimBLEAttValue & source) { deepCopy(source); }
|
||||||
|
|
||||||
|
/** @brief Move constructor */
|
||||||
|
NimBLEAttValue(NimBLEAttValue && source) { *this = std::move(source); }
|
||||||
|
|
||||||
|
/** @brief Destructor */
|
||||||
|
~NimBLEAttValue();
|
||||||
|
|
||||||
|
/** @brief Returns the max size in bytes */
|
||||||
|
uint16_t max_size() const { return m_attr_max_len; }
|
||||||
|
|
||||||
|
/** @brief Returns the currently allocated capacity in bytes */
|
||||||
|
uint16_t capacity() const { return m_capacity; }
|
||||||
|
|
||||||
|
/** @brief Returns the current length of the value in bytes */
|
||||||
|
uint16_t length() const { return m_attr_len; }
|
||||||
|
|
||||||
|
/** @brief Returns the current size of the value in bytes */
|
||||||
|
uint16_t size() const { return m_attr_len; }
|
||||||
|
|
||||||
|
/** @brief Returns a pointer to the internal buffer of the value */
|
||||||
|
const uint8_t* data() const { return m_attr_value; }
|
||||||
|
|
||||||
|
/** @brief Returns a pointer to the internal buffer of the value as a const char* */
|
||||||
|
const char* c_str() const { return (const char*)m_attr_value; }
|
||||||
|
|
||||||
|
/** @brief Iterator begin */
|
||||||
|
const uint8_t* begin() const { return m_attr_value; }
|
||||||
|
|
||||||
|
/** @brief Iterator end */
|
||||||
|
const uint8_t* end() const { return m_attr_value + m_attr_len; }
|
||||||
|
|
||||||
|
#if CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
|
||||||
|
/** @brief Returns a timestamp of when the value was last updated */
|
||||||
|
time_t getTimeStamp() const { return m_timestamp; }
|
||||||
|
|
||||||
|
/** @brief Set the timestamp to the current time */
|
||||||
|
void setTimeStamp() { m_timestamp = time(nullptr); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the timestamp to the specified time
|
||||||
|
* @param[in] t The timestamp value to set
|
||||||
|
*/
|
||||||
|
void setTimeStamp(time_t t) { m_timestamp = t; }
|
||||||
|
#else
|
||||||
|
time_t getTimeStamp() const { return 0; }
|
||||||
|
void setTimeStamp() { }
|
||||||
|
void setTimeStamp(time_t t) { }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the value from a buffer
|
||||||
|
* @param[in] value A ponter to a buffer containing the value.
|
||||||
|
* @param[in] len The length of the value in bytes.
|
||||||
|
* @returns True if successful.
|
||||||
|
*/
|
||||||
|
bool setValue(const uint8_t *value, uint16_t len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set value to the value of const char*.
|
||||||
|
* @param [in] s A ponter to a const char value to set.
|
||||||
|
*/
|
||||||
|
bool setValue(const char* s) {
|
||||||
|
return setValue((uint8_t*)s, (uint16_t)strlen(s)); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get a pointer to the value buffer with timestamp.
|
||||||
|
* @param[in] timestamp A ponter to a time_t variable to store the timestamp.
|
||||||
|
* @returns A pointer to the internal value buffer.
|
||||||
|
*/
|
||||||
|
const uint8_t* getValue(time_t *timestamp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Append data to the value.
|
||||||
|
* @param[in] value A ponter to a data buffer with the value to append.
|
||||||
|
* @param[in] len The length of the value to append in bytes.
|
||||||
|
* @returns A reference to the appended NimBLEAttValue.
|
||||||
|
*/
|
||||||
|
NimBLEAttValue& append(const uint8_t *value, uint16_t len);
|
||||||
|
|
||||||
|
|
||||||
|
/*********************** Template Functions ************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Template to set value to the value of <type\>val.
|
||||||
|
* @param [in] s The <type\>value to set.
|
||||||
|
* @details Only used for types without a `c_str()` method.
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
#ifdef _DOXYGEN_
|
||||||
|
bool
|
||||||
|
#else
|
||||||
|
typename std::enable_if<!Has_c_str_len<T>::value, bool>::type
|
||||||
|
#endif
|
||||||
|
setValue(const T &s) {
|
||||||
|
return setValue((uint8_t*)&s, sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Template to set value to the value of <type\>val.
|
||||||
|
* @param [in] s The <type\>value to set.
|
||||||
|
* @details Only used if the <type\> has a `c_str()` method.
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
#ifdef _DOXYGEN_
|
||||||
|
bool
|
||||||
|
#else
|
||||||
|
typename std::enable_if<Has_c_str_len<T>::value, bool>::type
|
||||||
|
#endif
|
||||||
|
setValue(const T & s) {
|
||||||
|
return setValue((uint8_t*)s.c_str(), (uint16_t)s.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Template to return the value as a <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\n
|
||||||
|
* <tt>sizeof(<type\>)</tt>.
|
||||||
|
* @return The data converted to <type\> or NULL if skipSizeCheck is false and the data is\n
|
||||||
|
* 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) {
|
||||||
|
if(!skipSizeCheck && size() < sizeof(T)) {
|
||||||
|
return T();
|
||||||
|
}
|
||||||
|
return *((T *)getValue(timestamp));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*********************** Operators ************************/
|
||||||
|
|
||||||
|
/** @brief Subscript operator */
|
||||||
|
uint8_t operator [](int pos) const {
|
||||||
|
assert(pos < m_attr_len && "out of range"); return m_attr_value[pos]; }
|
||||||
|
|
||||||
|
/** @brief Operator; Get the value as a std::vector<uint8_t>. */
|
||||||
|
operator std::vector<uint8_t>() const {
|
||||||
|
return std::vector<uint8_t>(m_attr_value, m_attr_value + m_attr_len); }
|
||||||
|
|
||||||
|
/** @brief Operator; Get the value as a std::string. */
|
||||||
|
operator std::string() const {
|
||||||
|
return std::string((char*)m_attr_value, m_attr_len); }
|
||||||
|
|
||||||
|
/** @brief Operator; Get the value as a const uint8_t*. */
|
||||||
|
operator const uint8_t*() const { return m_attr_value; }
|
||||||
|
|
||||||
|
/** @brief Operator; Append another NimBLEAttValue. */
|
||||||
|
NimBLEAttValue& operator +=(const NimBLEAttValue & source) {
|
||||||
|
return append(source.data(), source.size()); }
|
||||||
|
|
||||||
|
/** @brief Operator; Set the value from a std::string source. */
|
||||||
|
NimBLEAttValue& operator =(const std::string & source) {
|
||||||
|
setValue((uint8_t*)source.data(), (uint16_t)source.size()); return *this; }
|
||||||
|
|
||||||
|
/** @brief Move assignment operator */
|
||||||
|
NimBLEAttValue& operator =(NimBLEAttValue && source);
|
||||||
|
|
||||||
|
/** @brief Copy assignment operator */
|
||||||
|
NimBLEAttValue& operator =(const NimBLEAttValue & source);
|
||||||
|
|
||||||
|
/** @brief Equality operator */
|
||||||
|
bool operator ==(const NimBLEAttValue & source) {
|
||||||
|
return (m_attr_len == source.size()) ?
|
||||||
|
memcmp(m_attr_value, source.data(), m_attr_len) == 0 : false; }
|
||||||
|
|
||||||
|
/** @brief Inequality operator */
|
||||||
|
bool operator !=(const NimBLEAttValue & source){ return !(*this == source); }
|
||||||
|
|
||||||
|
#ifdef NIMBLE_CPP_ARDUINO_STRING_AVAILABLE
|
||||||
|
/** @brief Operator; Get the value as an Arduino String value. */
|
||||||
|
operator String() const { return String((char*)m_attr_value); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
inline NimBLEAttValue::NimBLEAttValue(uint16_t init_len, uint16_t max_len) {
|
||||||
|
m_attr_value = (uint8_t*)calloc(init_len + 1, 1);
|
||||||
|
assert(m_attr_value && "No Mem");
|
||||||
|
m_attr_max_len = std::min(BLE_ATT_ATTR_MAX_LEN, (int)max_len);
|
||||||
|
m_attr_len = 0;
|
||||||
|
m_capacity = init_len;
|
||||||
|
setTimeStamp(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline NimBLEAttValue::NimBLEAttValue(const uint8_t *value, uint16_t len, uint16_t max_len)
|
||||||
|
: NimBLEAttValue(len, max_len) {
|
||||||
|
memcpy(m_attr_value, value, len);
|
||||||
|
m_attr_value[len] = '\0';
|
||||||
|
m_attr_len = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline NimBLEAttValue::~NimBLEAttValue() {
|
||||||
|
if(m_attr_value != nullptr) {
|
||||||
|
free(m_attr_value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline NimBLEAttValue& NimBLEAttValue::operator =(NimBLEAttValue && source) {
|
||||||
|
if (this != &source){
|
||||||
|
free(m_attr_value);
|
||||||
|
|
||||||
|
m_attr_value = source.m_attr_value;
|
||||||
|
m_attr_max_len = source.m_attr_max_len;
|
||||||
|
m_attr_len = source.m_attr_len;
|
||||||
|
m_capacity = source.m_capacity;
|
||||||
|
setTimeStamp(source.getTimeStamp());
|
||||||
|
source.m_attr_value = nullptr;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline NimBLEAttValue& NimBLEAttValue::operator =(const NimBLEAttValue & source) {
|
||||||
|
if (this != &source) {
|
||||||
|
deepCopy(source);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void NimBLEAttValue::deepCopy(const NimBLEAttValue & source) {
|
||||||
|
uint8_t* res = (uint8_t*)realloc( m_attr_value, source.m_capacity + 1);
|
||||||
|
assert(res && "deepCopy: realloc failed");
|
||||||
|
|
||||||
|
ble_npl_hw_enter_critical();
|
||||||
|
m_attr_value = res;
|
||||||
|
m_attr_max_len = source.m_attr_max_len;
|
||||||
|
m_attr_len = source.m_attr_len;
|
||||||
|
m_capacity = source.m_capacity;
|
||||||
|
setTimeStamp(source.getTimeStamp());
|
||||||
|
memcpy(m_attr_value, source.m_attr_value, m_attr_len + 1);
|
||||||
|
ble_npl_hw_exit_critical(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const uint8_t* NimBLEAttValue::getValue(time_t *timestamp) {
|
||||||
|
if(timestamp != nullptr) {
|
||||||
|
#if CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
|
||||||
|
*timestamp = m_timestamp;
|
||||||
|
#else
|
||||||
|
*timestamp = 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return m_attr_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool NimBLEAttValue::setValue(const uint8_t *value, uint16_t len) {
|
||||||
|
if (len > m_attr_max_len) {
|
||||||
|
NIMBLE_LOGE("NimBLEAttValue", "value exceeds max, len=%u, max=%u",
|
||||||
|
len, m_attr_max_len);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *res = m_attr_value;
|
||||||
|
if (len > m_capacity) {
|
||||||
|
res = (uint8_t*)realloc(m_attr_value, (len + 1));
|
||||||
|
m_capacity = len;
|
||||||
|
}
|
||||||
|
assert(res && "setValue: realloc failed");
|
||||||
|
|
||||||
|
#if CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
|
||||||
|
time_t t = time(nullptr);
|
||||||
|
#else
|
||||||
|
time_t t = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ble_npl_hw_enter_critical();
|
||||||
|
m_attr_value = res;
|
||||||
|
memcpy(m_attr_value, value, len);
|
||||||
|
m_attr_value[len] = '\0';
|
||||||
|
m_attr_len = len;
|
||||||
|
setTimeStamp(t);
|
||||||
|
ble_npl_hw_exit_critical(0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline NimBLEAttValue& NimBLEAttValue::append(const uint8_t *value, uint16_t len) {
|
||||||
|
if (len < 1) {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((m_attr_len + len) > m_attr_max_len) {
|
||||||
|
NIMBLE_LOGE("NimBLEAttValue", "val > max, len=%u, max=%u",
|
||||||
|
len, m_attr_max_len);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* res = m_attr_value;
|
||||||
|
uint16_t new_len = m_attr_len + len;
|
||||||
|
if (new_len > m_capacity) {
|
||||||
|
res = (uint8_t*)realloc(m_attr_value, (new_len + 1));
|
||||||
|
m_capacity = new_len;
|
||||||
|
}
|
||||||
|
assert(res && "append: realloc failed");
|
||||||
|
|
||||||
|
#if CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
|
||||||
|
time_t t = time(nullptr);
|
||||||
|
#else
|
||||||
|
time_t t = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ble_npl_hw_enter_critical();
|
||||||
|
m_attr_value = res;
|
||||||
|
memcpy(m_attr_value + m_attr_len, value, len);
|
||||||
|
m_attr_len = new_len;
|
||||||
|
m_attr_value[m_attr_len] = '\0';
|
||||||
|
setTimeStamp(t);
|
||||||
|
ble_npl_hw_exit_critical(0);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /*(CONFIG_BT_ENABLED) */
|
||||||
|
#endif /* MAIN_NIMBLEATTVALUE_H_ */
|
|
@ -11,7 +11,7 @@
|
||||||
* Created on: Jan 4, 2018
|
* Created on: Jan 4, 2018
|
||||||
* Author: kolban
|
* Author: kolban
|
||||||
*/
|
*/
|
||||||
#include "sdkconfig.h"
|
#include "nimconfig.h"
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
#if defined(CONFIG_BT_ENABLED)
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
|
@ -9,11 +9,9 @@
|
||||||
* Created on: Jun 22, 2017
|
* Created on: Jun 22, 2017
|
||||||
* Author: kolban
|
* Author: kolban
|
||||||
*/
|
*/
|
||||||
#include "sdkconfig.h"
|
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
|
||||||
|
|
||||||
#include "nimconfig.h"
|
#include "nimconfig.h"
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||||
|
|
||||||
#include "NimBLECharacteristic.h"
|
#include "NimBLECharacteristic.h"
|
||||||
#include "NimBLE2904.h"
|
#include "NimBLE2904.h"
|
||||||
|
@ -32,27 +30,29 @@ static const char* LOG_TAG = "NimBLECharacteristic";
|
||||||
* @brief Construct a characteristic
|
* @brief Construct a characteristic
|
||||||
* @param [in] uuid - UUID (const char*) for the characteristic.
|
* @param [in] uuid - UUID (const char*) for the characteristic.
|
||||||
* @param [in] properties - Properties for the characteristic.
|
* @param [in] properties - Properties for the characteristic.
|
||||||
|
* @param [in] max_len - The maximum length in bytes that the characteristic value can hold. (Default: 512 bytes for esp32, 20 for all others).
|
||||||
* @param [in] pService - pointer to the service instance this characteristic belongs to.
|
* @param [in] pService - pointer to the service instance this characteristic belongs to.
|
||||||
*/
|
*/
|
||||||
NimBLECharacteristic::NimBLECharacteristic(const char* uuid, uint16_t properties, NimBLEService* pService)
|
NimBLECharacteristic::NimBLECharacteristic(const char* uuid, uint16_t properties,
|
||||||
: NimBLECharacteristic(NimBLEUUID(uuid), properties, pService) {
|
uint16_t max_len, NimBLEService* pService)
|
||||||
|
: NimBLECharacteristic(NimBLEUUID(uuid), properties, max_len, pService) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Construct a characteristic
|
* @brief Construct a characteristic
|
||||||
* @param [in] uuid - UUID for the characteristic.
|
* @param [in] uuid - UUID for the characteristic.
|
||||||
* @param [in] properties - Properties for the characteristic.
|
* @param [in] properties - Properties for the characteristic.
|
||||||
|
* @param [in] max_len - The maximum length in bytes that the characteristic value can hold. (Default: 512 bytes for esp32, 20 for all others).
|
||||||
* @param [in] pService - pointer to the service instance this characteristic belongs to.
|
* @param [in] pService - pointer to the service instance this characteristic belongs to.
|
||||||
*/
|
*/
|
||||||
NimBLECharacteristic::NimBLECharacteristic(const NimBLEUUID &uuid, uint16_t properties, NimBLEService* pService) {
|
NimBLECharacteristic::NimBLECharacteristic(const NimBLEUUID &uuid, uint16_t properties,
|
||||||
|
uint16_t max_len, NimBLEService* pService)
|
||||||
|
: m_value(std::min(CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH , (int)max_len), max_len) {
|
||||||
m_uuid = uuid;
|
m_uuid = uuid;
|
||||||
m_handle = NULL_HANDLE;
|
m_handle = NULL_HANDLE;
|
||||||
m_properties = properties;
|
m_properties = properties;
|
||||||
m_pCallbacks = &defaultCallback;
|
m_pCallbacks = &defaultCallback;
|
||||||
m_pService = pService;
|
m_pService = pService;
|
||||||
m_value = "";
|
|
||||||
m_valMux = portMUX_INITIALIZER_UNLOCKED;
|
|
||||||
m_timestamp = 0;
|
|
||||||
m_removed = 0;
|
m_removed = 0;
|
||||||
} // NimBLECharacteristic
|
} // NimBLECharacteristic
|
||||||
|
|
||||||
|
@ -234,17 +234,14 @@ NimBLEUUID NimBLECharacteristic::getUUID() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Retrieve the current value of the characteristic.
|
* @brief Retrieve the current value of the characteristic.
|
||||||
* @return A std::string containing the current characteristic value.
|
* @return The NimBLEAttValue containing the current characteristic value.
|
||||||
*/
|
*/
|
||||||
std::string NimBLECharacteristic::getValue(time_t *timestamp) {
|
NimBLEAttValue NimBLECharacteristic::getValue(time_t *timestamp) {
|
||||||
portENTER_CRITICAL(&m_valMux);
|
|
||||||
std::string retVal = m_value;
|
|
||||||
if(timestamp != nullptr) {
|
if(timestamp != nullptr) {
|
||||||
*timestamp = m_timestamp;
|
m_value.getValue(timestamp);
|
||||||
}
|
}
|
||||||
portEXIT_CRITICAL(&m_valMux);
|
|
||||||
|
|
||||||
return retVal;
|
return m_value;
|
||||||
} // getValue
|
} // getValue
|
||||||
|
|
||||||
|
|
||||||
|
@ -253,11 +250,7 @@ std::string NimBLECharacteristic::getValue(time_t *timestamp) {
|
||||||
* @return The length of the current characteristic data.
|
* @return The length of the current characteristic data.
|
||||||
*/
|
*/
|
||||||
size_t NimBLECharacteristic::getDataLength() {
|
size_t NimBLECharacteristic::getDataLength() {
|
||||||
portENTER_CRITICAL(&m_valMux);
|
return m_value.size();
|
||||||
size_t len = m_value.length();
|
|
||||||
portEXIT_CRITICAL(&m_valMux);
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -289,27 +282,27 @@ int NimBLECharacteristic::handleGapEvent(uint16_t conn_handle, uint16_t attr_han
|
||||||
pCharacteristic->m_pCallbacks->onRead(pCharacteristic, &desc);
|
pCharacteristic->m_pCallbacks->onRead(pCharacteristic, &desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
portENTER_CRITICAL(&pCharacteristic->m_valMux);
|
ble_npl_hw_enter_critical();
|
||||||
rc = os_mbuf_append(ctxt->om, (uint8_t*)pCharacteristic->m_value.data(),
|
rc = os_mbuf_append(ctxt->om, pCharacteristic->m_value.data(), pCharacteristic->m_value.size());
|
||||||
pCharacteristic->m_value.length());
|
ble_npl_hw_exit_critical(0);
|
||||||
portEXIT_CRITICAL(&pCharacteristic->m_valMux);
|
|
||||||
|
|
||||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||||
}
|
}
|
||||||
|
|
||||||
case BLE_GATT_ACCESS_OP_WRITE_CHR: {
|
case BLE_GATT_ACCESS_OP_WRITE_CHR: {
|
||||||
if (ctxt->om->om_len > BLE_ATT_ATTR_MAX_LEN) {
|
uint16_t att_max_len = pCharacteristic->m_value.max_size();
|
||||||
|
|
||||||
|
if (ctxt->om->om_len > att_max_len) {
|
||||||
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t buf[BLE_ATT_ATTR_MAX_LEN];
|
uint8_t buf[att_max_len];
|
||||||
size_t len = ctxt->om->om_len;
|
size_t len = ctxt->om->om_len;
|
||||||
memcpy(buf, ctxt->om->om_data,len);
|
memcpy(buf, ctxt->om->om_data,len);
|
||||||
|
|
||||||
os_mbuf *next;
|
os_mbuf *next;
|
||||||
next = SLIST_NEXT(ctxt->om, om_next);
|
next = SLIST_NEXT(ctxt->om, om_next);
|
||||||
while(next != NULL){
|
while(next != NULL){
|
||||||
if((len + next->om_len) > BLE_ATT_ATTR_MAX_LEN) {
|
if((len + next->om_len) > att_max_len) {
|
||||||
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||||
}
|
}
|
||||||
memcpy(&buf[len], next->om_data, next->om_len);
|
memcpy(&buf[len], next->om_data, next->om_len);
|
||||||
|
@ -389,26 +382,60 @@ void NimBLECharacteristic::setSubscribe(struct ble_gap_event *event) {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Send an indication.\n
|
* @brief Send an indication.
|
||||||
* 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() {
|
void NimBLECharacteristic::indicate() {
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> indicate: length: %d", getDataLength());
|
|
||||||
notify(false);
|
notify(false);
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< indicate");
|
|
||||||
} // indicate
|
} // indicate
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Send a notification.\n
|
* @brief Send an indication.
|
||||||
* A notification is a transmission of up to the first 20 bytes of the characteristic value.\n
|
* @param[in] value A pointer to the data to send.
|
||||||
* A notification will not block; it is a fire and forget.
|
* @param[in] length The length of the data to send.
|
||||||
|
*/
|
||||||
|
void NimBLECharacteristic::indicate(const uint8_t* value, size_t length) {
|
||||||
|
notify(value, length, false);
|
||||||
|
} // indicate
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send an indication.
|
||||||
|
* @param[in] value A std::vector<uint8_t> containing the value to send as the notification value.
|
||||||
|
*/
|
||||||
|
void NimBLECharacteristic::indicate(const std::vector<uint8_t>& value) {
|
||||||
|
notify(value.data(), value.size(), false);
|
||||||
|
} // indicate
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send a notification or indication.
|
||||||
* @param[in] is_notification if true sends a notification, false sends an indication.
|
* @param[in] is_notification if true sends a notification, false sends an indication.
|
||||||
*/
|
*/
|
||||||
void NimBLECharacteristic::notify(bool is_notification) {
|
void NimBLECharacteristic::notify(bool is_notification) {
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> notify: length: %d", getDataLength());
|
notify(m_value.data(), m_value.length(), is_notification);
|
||||||
|
} // notify
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send a notification or indication.
|
||||||
|
* @param[in] value A std::vector<uint8_t> containing the value to send as the notification value.
|
||||||
|
* @param[in] is_notification if true sends a notification, false sends an indication.
|
||||||
|
*/
|
||||||
|
void NimBLECharacteristic::notify(const std::vector<uint8_t>& value, bool is_notification) {
|
||||||
|
notify(value.data(), value.size(), is_notification);
|
||||||
|
} // notify
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send a notification or indication.
|
||||||
|
* @param[in] value A pointer to the data to send.
|
||||||
|
* @param[in] length The length of the data to send.
|
||||||
|
* @param[in] is_notification if true sends a notification, false sends an indication.
|
||||||
|
*/
|
||||||
|
void NimBLECharacteristic::notify(const uint8_t* value, size_t length, bool is_notification) {
|
||||||
|
NIMBLE_LOGD(LOG_TAG, ">> notify: length: %d", length);
|
||||||
|
|
||||||
if(!(m_properties & NIMBLE_PROPERTY::NOTIFY) &&
|
if(!(m_properties & NIMBLE_PROPERTY::NOTIFY) &&
|
||||||
!(m_properties & NIMBLE_PROPERTY::INDICATE))
|
!(m_properties & NIMBLE_PROPERTY::INDICATE))
|
||||||
{
|
{
|
||||||
|
@ -424,15 +451,13 @@ void NimBLECharacteristic::notify(bool is_notification) {
|
||||||
|
|
||||||
m_pCallbacks->onNotify(this);
|
m_pCallbacks->onNotify(this);
|
||||||
|
|
||||||
std::string value = getValue();
|
|
||||||
size_t length = value.length();
|
|
||||||
bool reqSec = (m_properties & BLE_GATT_CHR_F_READ_AUTHEN) ||
|
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_AUTHOR) ||
|
||||||
(m_properties & BLE_GATT_CHR_F_READ_ENC);
|
(m_properties & BLE_GATT_CHR_F_READ_ENC);
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
for (auto &it : m_subscribedVec) {
|
for (auto &it : m_subscribedVec) {
|
||||||
uint16_t _mtu = getService()->getServer()->getPeerMTU(it.first);
|
uint16_t _mtu = getService()->getServer()->getPeerMTU(it.first) - 3;
|
||||||
|
|
||||||
// check if connected and subscribed
|
// check if connected and subscribed
|
||||||
if(_mtu == 0 || it.second == 0) {
|
if(_mtu == 0 || it.second == 0) {
|
||||||
|
@ -448,8 +473,8 @@ void NimBLECharacteristic::notify(bool is_notification) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (length > _mtu - 3) {
|
if (length > _mtu) {
|
||||||
NIMBLE_LOGW(LOG_TAG, "- Truncating to %d bytes (maximum notify size)", _mtu - 3);
|
NIMBLE_LOGW(LOG_TAG, "- Truncating to %d bytes (maximum notify size)", _mtu);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(is_notification && (!(it.second & NIMBLE_SUB_NOTIFY))) {
|
if(is_notification && (!(it.second & NIMBLE_SUB_NOTIFY))) {
|
||||||
|
@ -467,7 +492,7 @@ void NimBLECharacteristic::notify(bool is_notification) {
|
||||||
// don't create the m_buf until we are sure to send the data or else
|
// 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 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.
|
// 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);
|
os_mbuf *om = ble_hs_mbuf_from_flat(value, length);
|
||||||
|
|
||||||
if(!is_notification && (m_properties & NIMBLE_PROPERTY::INDICATE)) {
|
if(!is_notification && (m_properties & NIMBLE_PROPERTY::INDICATE)) {
|
||||||
if(!NimBLEDevice::getServer()->setIndicateWait(it.first)) {
|
if(!NimBLEDevice::getServer()->setIndicateWait(it.first)) {
|
||||||
|
@ -511,39 +536,29 @@ NimBLECharacteristicCallbacks* NimBLECharacteristic::getCallbacks() {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set the value of the characteristic.
|
* @brief Set the value of the characteristic from a data buffer .
|
||||||
* @param [in] data The data to set for the characteristic.
|
* @param [in] data The data buffer to set for the characteristic.
|
||||||
* @param [in] length The length of the data in bytes.
|
* @param [in] length The number of bytes in the data buffer.
|
||||||
*/
|
*/
|
||||||
void NimBLECharacteristic::setValue(const uint8_t* data, size_t length) {
|
void NimBLECharacteristic::setValue(const uint8_t* data, size_t length) {
|
||||||
#if CONFIG_LOG_DEFAULT_LEVEL > 3 || (ARDUINO_ARCH_ESP32 && CORE_DEBUG_LEVEL >= 4)
|
#if CONFIG_NIMBLE_CPP_LOG_LEVEL >= 4
|
||||||
char* pHex = NimBLEUtils::buildHexData(nullptr, data, length);
|
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());
|
NIMBLE_LOGD(LOG_TAG, ">> setValue: length=%d, data=%s, characteristic UUID=%s",
|
||||||
|
length, pHex, getUUID().toString().c_str());
|
||||||
free(pHex);
|
free(pHex);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (length > BLE_ATT_ATTR_MAX_LEN) {
|
m_value.setValue(data, length);
|
||||||
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);
|
|
||||||
portENTER_CRITICAL(&m_valMux);
|
|
||||||
m_value = std::string((char*)data, length);
|
|
||||||
m_timestamp = t;
|
|
||||||
portEXIT_CRITICAL(&m_valMux);
|
|
||||||
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< setValue");
|
NIMBLE_LOGD(LOG_TAG, "<< setValue");
|
||||||
} // setValue
|
} // setValue
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set the value of the characteristic from string data.\n
|
* @brief Set the value of the characteristic from a `std::vector<uint8_t>`.\n
|
||||||
* We set the value of the characteristic from the bytes contained in the string.
|
* @param [in] vec The std::vector<uint8_t> reference to set the characteristic value from.
|
||||||
* @param [in] value the std::string value of the characteristic.
|
|
||||||
*/
|
*/
|
||||||
void NimBLECharacteristic::setValue(const std::string &value) {
|
void NimBLECharacteristic::setValue(const std::vector<uint8_t>& vec) {
|
||||||
setValue((uint8_t*)(value.data()), value.length());
|
return setValue((uint8_t*)&vec[0], vec.size());
|
||||||
}// setValue
|
}// setValue
|
||||||
|
|
||||||
|
|
||||||
|
@ -641,6 +656,4 @@ void NimBLECharacteristicCallbacks::onSubscribe(NimBLECharacteristic* pCharacter
|
||||||
NIMBLE_LOGD("NimBLECharacteristicCallbacks", "onSubscribe: default");
|
NIMBLE_LOGD("NimBLECharacteristicCallbacks", "onSubscribe: default");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
|
||||||
#endif /* CONFIG_BT_ENABLED */
|
|
||||||
|
|
|
@ -13,13 +13,15 @@
|
||||||
|
|
||||||
#ifndef MAIN_NIMBLECHARACTERISTIC_H_
|
#ifndef MAIN_NIMBLECHARACTERISTIC_H_
|
||||||
#define MAIN_NIMBLECHARACTERISTIC_H_
|
#define MAIN_NIMBLECHARACTERISTIC_H_
|
||||||
#include "sdkconfig.h"
|
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
|
||||||
|
|
||||||
#include "nimconfig.h"
|
#include "nimconfig.h"
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||||
|
|
||||||
|
#if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||||
#include "host/ble_hs.h"
|
#include "host/ble_hs.h"
|
||||||
|
#else
|
||||||
|
#include "nimble/nimble/host/include/host/ble_hs.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
/**** FIX COMPILATION ****/
|
/**** FIX COMPILATION ****/
|
||||||
#undef min
|
#undef min
|
||||||
#undef max
|
#undef max
|
||||||
|
@ -42,6 +44,7 @@ typedef enum {
|
||||||
|
|
||||||
#include "NimBLEService.h"
|
#include "NimBLEService.h"
|
||||||
#include "NimBLEDescriptor.h"
|
#include "NimBLEDescriptor.h"
|
||||||
|
#include "NimBLEAttValue.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -63,11 +66,13 @@ public:
|
||||||
uint16_t properties =
|
uint16_t properties =
|
||||||
NIMBLE_PROPERTY::READ |
|
NIMBLE_PROPERTY::READ |
|
||||||
NIMBLE_PROPERTY::WRITE,
|
NIMBLE_PROPERTY::WRITE,
|
||||||
|
uint16_t max_len = BLE_ATT_ATTR_MAX_LEN,
|
||||||
NimBLEService* pService = nullptr);
|
NimBLEService* pService = nullptr);
|
||||||
NimBLECharacteristic(const NimBLEUUID &uuid,
|
NimBLECharacteristic(const NimBLEUUID &uuid,
|
||||||
uint16_t properties =
|
uint16_t properties =
|
||||||
NIMBLE_PROPERTY::READ |
|
NIMBLE_PROPERTY::READ |
|
||||||
NIMBLE_PROPERTY::WRITE,
|
NIMBLE_PROPERTY::WRITE,
|
||||||
|
uint16_t max_len = BLE_ATT_ATTR_MAX_LEN,
|
||||||
NimBLEService* pService = nullptr);
|
NimBLEService* pService = nullptr);
|
||||||
|
|
||||||
~NimBLECharacteristic();
|
~NimBLECharacteristic();
|
||||||
|
@ -75,64 +80,93 @@ public:
|
||||||
uint16_t getHandle();
|
uint16_t getHandle();
|
||||||
NimBLEUUID getUUID();
|
NimBLEUUID getUUID();
|
||||||
std::string toString();
|
std::string toString();
|
||||||
|
|
||||||
void setCallbacks(NimBLECharacteristicCallbacks* pCallbacks);
|
|
||||||
NimBLECharacteristicCallbacks*
|
|
||||||
getCallbacks();
|
|
||||||
|
|
||||||
void indicate();
|
void indicate();
|
||||||
|
void indicate(const uint8_t* value, size_t length);
|
||||||
|
void indicate(const std::vector<uint8_t>& value);
|
||||||
void notify(bool is_notification = true);
|
void notify(bool is_notification = true);
|
||||||
|
void notify(const uint8_t* value, size_t length, bool is_notification = true);
|
||||||
|
void notify(const std::vector<uint8_t>& value, bool is_notification = true);
|
||||||
size_t getSubscribedCount();
|
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);
|
void addDescriptor(NimBLEDescriptor *pDescriptor);
|
||||||
NimBLEDescriptor* getDescriptorByUUID(const char* uuid);
|
NimBLEDescriptor* getDescriptorByUUID(const char* uuid);
|
||||||
NimBLEDescriptor* getDescriptorByUUID(const NimBLEUUID &uuid);
|
NimBLEDescriptor* getDescriptorByUUID(const NimBLEUUID &uuid);
|
||||||
NimBLEDescriptor* getDescriptorByHandle(uint16_t handle);
|
NimBLEDescriptor* getDescriptorByHandle(uint16_t handle);
|
||||||
void removeDescriptor(NimBLEDescriptor *pDescriptor, bool deleteDsc = false);
|
void removeDescriptor(NimBLEDescriptor *pDescriptor, bool deleteDsc = false);
|
||||||
|
NimBLEService* getService();
|
||||||
std::string getValue(time_t *timestamp = nullptr);
|
uint16_t getProperties();
|
||||||
|
NimBLEAttValue getValue(time_t *timestamp = nullptr);
|
||||||
size_t getDataLength();
|
size_t getDataLength();
|
||||||
|
void setValue(const uint8_t* data, size_t size);
|
||||||
|
void setValue(const std::vector<uint8_t>& vec);
|
||||||
|
void setCallbacks(NimBLECharacteristicCallbacks* pCallbacks);
|
||||||
|
NimBLEDescriptor* createDescriptor(const char* uuid,
|
||||||
|
uint32_t properties =
|
||||||
|
NIMBLE_PROPERTY::READ |
|
||||||
|
NIMBLE_PROPERTY::WRITE,
|
||||||
|
uint16_t max_len = BLE_ATT_ATTR_MAX_LEN);;
|
||||||
|
NimBLEDescriptor* createDescriptor(const NimBLEUUID &uuid,
|
||||||
|
uint32_t properties =
|
||||||
|
NIMBLE_PROPERTY::READ |
|
||||||
|
NIMBLE_PROPERTY::WRITE,
|
||||||
|
uint16_t max_len = BLE_ATT_ATTR_MAX_LEN);
|
||||||
|
|
||||||
|
NimBLECharacteristicCallbacks* getCallbacks();
|
||||||
|
|
||||||
|
|
||||||
|
/*********************** Template Functions ************************/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A template to convert the characteristic data to <type\>.
|
* @brief Template to set the characteristic value to <type\>val.
|
||||||
|
* @param [in] s The value to set.
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
void setValue(const T &s) { m_value.setValue<T>(s); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Template to convert the characteristic data to <type\>.
|
||||||
* @tparam T The type to convert the data to.
|
* @tparam T The type to convert the data to.
|
||||||
* @param [in] timestamp A pointer to a time_t struct to store the time the value was read.
|
* @param [in] timestamp (Optional) 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>.
|
* @param [in] skipSizeCheck (Optional) 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
|
* @return The data converted to <type\> or NULL if skipSizeCheck is false and the data is less than <tt>sizeof(<type\>)</tt>.
|
||||||
* less than <tt>sizeof(<type\>)</tt>.
|
|
||||||
* @details <b>Use:</b> <tt>getValue<type>(×tamp, skipSizeCheck);</tt>
|
* @details <b>Use:</b> <tt>getValue<type>(×tamp, skipSizeCheck);</tt>
|
||||||
*/
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T getValue(time_t *timestamp = nullptr, bool skipSizeCheck = false) {
|
T getValue(time_t *timestamp = nullptr, bool skipSizeCheck = false) {
|
||||||
std::string value = getValue();
|
return m_value.getValue<T>(timestamp, skipSizeCheck);
|
||||||
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.
|
* @brief Template to send a notification from a class type that has a c_str() and length() method.
|
||||||
* @param [in] s The value to set.
|
* @tparam T The a reference to a class containing the data to send.
|
||||||
|
* @param[in] value The <type\>value to set.
|
||||||
|
* @param[in] is_notification if true sends a notification, false sends an indication.
|
||||||
|
* @details Only used if the <type\> has a `c_str()` method.
|
||||||
*/
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void setValue(const T &s) {
|
#ifdef _DOXYGEN_
|
||||||
setValue((uint8_t*)&s, sizeof(T));
|
void
|
||||||
|
#else
|
||||||
|
typename std::enable_if<Has_c_str_len<T>::value, void>::type
|
||||||
|
#endif
|
||||||
|
notify(const T& value, bool is_notification = true) {
|
||||||
|
notify((uint8_t*)value.c_str(), value.length(), is_notification);
|
||||||
}
|
}
|
||||||
|
|
||||||
NimBLEService* getService();
|
/**
|
||||||
uint16_t getProperties();
|
* @brief Template to send an indication from a class type that has a c_str() and length() method.
|
||||||
|
* @tparam T The a reference to a class containing the data to send.
|
||||||
|
* @param[in] value The <type\>value to set.
|
||||||
|
* @details Only used if the <type\> has a `c_str()` method.
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
#ifdef _DOXYGEN_
|
||||||
|
void
|
||||||
|
#else
|
||||||
|
typename std::enable_if<Has_c_str_len<T>::value, void>::type
|
||||||
|
#endif
|
||||||
|
indicate(const T& value) {
|
||||||
|
indicate((uint8_t*)value.c_str(), value.length());
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -149,10 +183,8 @@ private:
|
||||||
uint16_t m_properties;
|
uint16_t m_properties;
|
||||||
NimBLECharacteristicCallbacks* m_pCallbacks;
|
NimBLECharacteristicCallbacks* m_pCallbacks;
|
||||||
NimBLEService* m_pService;
|
NimBLEService* m_pService;
|
||||||
std::string m_value;
|
NimBLEAttValue m_value;
|
||||||
std::vector<NimBLEDescriptor*> m_dscVec;
|
std::vector<NimBLEDescriptor*> m_dscVec;
|
||||||
portMUX_TYPE m_valMux;
|
|
||||||
time_t m_timestamp;
|
|
||||||
uint8_t m_removed;
|
uint8_t m_removed;
|
||||||
|
|
||||||
std::vector<std::pair<uint16_t, uint16_t>> m_subscribedVec;
|
std::vector<std::pair<uint16_t, uint16_t>> m_subscribedVec;
|
||||||
|
@ -195,6 +227,5 @@ public:
|
||||||
virtual void onSubscribe(NimBLECharacteristic* pCharacteristic, ble_gap_conn_desc* desc, uint16_t subValue);
|
virtual void onSubscribe(NimBLECharacteristic* pCharacteristic, ble_gap_conn_desc* desc, uint16_t subValue);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||||
#endif /* CONFIG_BT_ENABLED */
|
|
||||||
#endif /*MAIN_NIMBLECHARACTERISTIC_H_*/
|
#endif /*MAIN_NIMBLECHARACTERISTIC_H_*/
|
||||||
|
|
|
@ -11,11 +11,8 @@
|
||||||
* Author: kolban
|
* Author: kolban
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "sdkconfig.h"
|
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
|
||||||
|
|
||||||
#include "nimconfig.h"
|
#include "nimconfig.h"
|
||||||
#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||||
|
|
||||||
#include "NimBLEClient.h"
|
#include "NimBLEClient.h"
|
||||||
#include "NimBLEDevice.h"
|
#include "NimBLEDevice.h"
|
||||||
|
@ -23,9 +20,13 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
#include <climits>
|
||||||
|
|
||||||
|
#if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||||
#include "nimble/nimble_port.h"
|
#include "nimble/nimble_port.h"
|
||||||
|
#else
|
||||||
|
#include "nimble/porting/nimble/include/nimble/nimble_port.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
static const char* LOG_TAG = "NimBLEClient";
|
static const char* LOG_TAG = "NimBLEClient";
|
||||||
static NimBLEClientCallbacks defaultCallbacks;
|
static NimBLEClientCallbacks defaultCallbacks;
|
||||||
|
@ -63,6 +64,12 @@ NimBLEClient::NimBLEClient(const NimBLEAddress &peerAddress) : m_peerAddress(pee
|
||||||
m_deleteCallbacks = false;
|
m_deleteCallbacks = false;
|
||||||
m_pTaskData = nullptr;
|
m_pTaskData = nullptr;
|
||||||
m_connEstablished = false;
|
m_connEstablished = false;
|
||||||
|
m_lastErr = 0;
|
||||||
|
#if CONFIG_BT_NIMBLE_EXT_ADV
|
||||||
|
m_phyMask = BLE_GAP_LE_PHY_1M_MASK |
|
||||||
|
BLE_GAP_LE_PHY_2M_MASK |
|
||||||
|
BLE_GAP_LE_PHY_CODED_MASK;
|
||||||
|
#endif
|
||||||
|
|
||||||
m_pConnParams.scan_itvl = 16; // Scan interval in 0.625ms units (NimBLE Default)
|
m_pConnParams.scan_itvl = 16; // Scan interval in 0.625ms units (NimBLE Default)
|
||||||
m_pConnParams.scan_window = 16; // Scan window in 0.625ms units (NimBLE Default)
|
m_pConnParams.scan_window = 16; // Scan window in 0.625ms units (NimBLE Default)
|
||||||
|
@ -73,6 +80,7 @@ NimBLEClient::NimBLEClient(const NimBLEAddress &peerAddress) : m_peerAddress(pee
|
||||||
m_pConnParams.min_ce_len = BLE_GAP_INITIAL_CONN_MIN_CE_LEN; // Minimum length of connection event in 0.625ms units
|
m_pConnParams.min_ce_len = BLE_GAP_INITIAL_CONN_MIN_CE_LEN; // Minimum length of connection event in 0.625ms units
|
||||||
m_pConnParams.max_ce_len = BLE_GAP_INITIAL_CONN_MAX_CE_LEN; // Maximum length of connection event in 0.625ms units
|
m_pConnParams.max_ce_len = BLE_GAP_INITIAL_CONN_MAX_CE_LEN; // Maximum length of connection event in 0.625ms units
|
||||||
|
|
||||||
|
memset(&m_dcTimer, 0, sizeof(m_dcTimer));
|
||||||
ble_npl_callout_init(&m_dcTimer, nimble_port_get_dflt_eventq(),
|
ble_npl_callout_init(&m_dcTimer, nimble_port_get_dflt_eventq(),
|
||||||
NimBLEClient::dcTimerCb, this);
|
NimBLEClient::dcTimerCb, this);
|
||||||
} // NimBLEClient
|
} // NimBLEClient
|
||||||
|
@ -91,6 +99,8 @@ NimBLEClient::~NimBLEClient() {
|
||||||
delete m_pClientCallbacks;
|
delete m_pClientCallbacks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ble_npl_callout_deinit(&m_dcTimer);
|
||||||
|
|
||||||
} // ~NimBLEClient
|
} // ~NimBLEClient
|
||||||
|
|
||||||
|
|
||||||
|
@ -205,7 +215,8 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttibutes) {
|
||||||
m_peerAddress = address;
|
m_peerAddress = address;
|
||||||
}
|
}
|
||||||
|
|
||||||
ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(), 0, nullptr};
|
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
|
||||||
|
ble_task_data_t taskData = {this, cur_task, 0, nullptr};
|
||||||
m_pTaskData = &taskData;
|
m_pTaskData = &taskData;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
|
@ -214,9 +225,22 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttibutes) {
|
||||||
* Loop on BLE_HS_EBUSY if the scan hasn't stopped yet.
|
* Loop on BLE_HS_EBUSY if the scan hasn't stopped yet.
|
||||||
*/
|
*/
|
||||||
do {
|
do {
|
||||||
|
#if CONFIG_BT_NIMBLE_EXT_ADV
|
||||||
|
rc = ble_gap_ext_connect(NimBLEDevice::m_own_addr_type,
|
||||||
|
&peerAddr_t,
|
||||||
|
m_connectTimeout,
|
||||||
|
m_phyMask,
|
||||||
|
&m_pConnParams,
|
||||||
|
&m_pConnParams,
|
||||||
|
&m_pConnParams,
|
||||||
|
NimBLEClient::handleGapEvent,
|
||||||
|
this);
|
||||||
|
|
||||||
|
#else
|
||||||
rc = ble_gap_connect(NimBLEDevice::m_own_addr_type, &peerAddr_t,
|
rc = ble_gap_connect(NimBLEDevice::m_own_addr_type, &peerAddr_t,
|
||||||
m_connectTimeout, &m_pConnParams,
|
m_connectTimeout, &m_pConnParams,
|
||||||
NimBLEClient::handleGapEvent, this);
|
NimBLEClient::handleGapEvent, this);
|
||||||
|
#endif
|
||||||
switch (rc) {
|
switch (rc) {
|
||||||
case 0:
|
case 0:
|
||||||
break;
|
break;
|
||||||
|
@ -251,11 +275,17 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttibutes) {
|
||||||
|
|
||||||
} while (rc == BLE_HS_EBUSY);
|
} while (rc == BLE_HS_EBUSY);
|
||||||
|
|
||||||
|
m_lastErr = rc;
|
||||||
|
|
||||||
if(rc != 0) {
|
if(rc != 0) {
|
||||||
m_pTaskData = nullptr;
|
m_pTaskData = nullptr;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ulTaskNotifyValueClear
|
||||||
|
// Clear the task notification value to ensure we block
|
||||||
|
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
|
||||||
|
#endif
|
||||||
// Wait for the connect timeout time +1 second for the connection to complete
|
// Wait for the connect timeout time +1 second for the connection to complete
|
||||||
if(ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(m_connectTimeout + 1000)) == pdFALSE) {
|
if(ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(m_connectTimeout + 1000)) == pdFALSE) {
|
||||||
m_pTaskData = nullptr;
|
m_pTaskData = nullptr;
|
||||||
|
@ -273,6 +303,7 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttibutes) {
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
} else if(taskData.rc != 0){
|
} else if(taskData.rc != 0){
|
||||||
|
m_lastErr = taskData.rc;
|
||||||
NIMBLE_LOGE(LOG_TAG, "Connection failed; status=%d %s",
|
NIMBLE_LOGE(LOG_TAG, "Connection failed; status=%d %s",
|
||||||
taskData.rc,
|
taskData.rc,
|
||||||
NimBLEUtils::returnCodeToString(taskData.rc));
|
NimBLEUtils::returnCodeToString(taskData.rc));
|
||||||
|
@ -305,7 +336,8 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttibutes) {
|
||||||
* @return True on success.
|
* @return True on success.
|
||||||
*/
|
*/
|
||||||
bool NimBLEClient::secureConnection() {
|
bool NimBLEClient::secureConnection() {
|
||||||
ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(), 0, nullptr};
|
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
|
||||||
|
ble_task_data_t taskData = {this, cur_task, 0, nullptr};
|
||||||
|
|
||||||
int retryCount = 1;
|
int retryCount = 1;
|
||||||
|
|
||||||
|
@ -314,14 +346,20 @@ bool NimBLEClient::secureConnection() {
|
||||||
|
|
||||||
int rc = NimBLEDevice::startSecurity(m_conn_id);
|
int rc = NimBLEDevice::startSecurity(m_conn_id);
|
||||||
if(rc != 0){
|
if(rc != 0){
|
||||||
|
m_lastErr = rc;
|
||||||
m_pTaskData = nullptr;
|
m_pTaskData = nullptr;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ulTaskNotifyValueClear
|
||||||
|
// Clear the task notification value to ensure we block
|
||||||
|
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
|
||||||
|
#endif
|
||||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||||
} while (taskData.rc == (BLE_HS_ERR_HCI_BASE + BLE_ERR_PINKEY_MISSING) && retryCount--);
|
} while (taskData.rc == (BLE_HS_ERR_HCI_BASE + BLE_ERR_PINKEY_MISSING) && retryCount--);
|
||||||
|
|
||||||
if(taskData.rc != 0){
|
if(taskData.rc != 0){
|
||||||
|
m_lastErr = taskData.rc;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -372,10 +410,26 @@ int NimBLEClient::disconnect(uint8_t reason) {
|
||||||
}
|
}
|
||||||
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< disconnect()");
|
NIMBLE_LOGD(LOG_TAG, "<< disconnect()");
|
||||||
|
m_lastErr = rc;
|
||||||
return rc;
|
return rc;
|
||||||
} // disconnect
|
} // disconnect
|
||||||
|
|
||||||
|
|
||||||
|
#if CONFIG_BT_NIMBLE_EXT_ADV
|
||||||
|
/**
|
||||||
|
* @brief Set the PHY types to use when connecting to a server.
|
||||||
|
* @param [in] mask A bitmask indicating what PHYS to connect with.\n
|
||||||
|
* The available bits are:
|
||||||
|
* * 0x01 BLE_GAP_LE_PHY_1M_MASK
|
||||||
|
* * 0x02 BLE_GAP_LE_PHY_2M_MASK
|
||||||
|
* * 0x04 BLE_GAP_LE_PHY_CODED_MASK
|
||||||
|
*/
|
||||||
|
void NimBLEClient::setConnectPhy(uint8_t mask) {
|
||||||
|
m_phyMask = mask;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set the connection paramaters to use when connecting to a server.
|
* @brief Set the connection paramaters to use when connecting to a server.
|
||||||
* @param [in] minInterval The minimum connection interval in 1.25ms units.
|
* @param [in] minInterval The minimum connection interval in 1.25ms units.
|
||||||
|
@ -436,6 +490,29 @@ void NimBLEClient::updateConnParams(uint16_t minInterval, uint16_t maxInterval,
|
||||||
} // updateConnParams
|
} // updateConnParams
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Request an update of the data packet length.
|
||||||
|
* * Can only be used after a connection has been established.
|
||||||
|
* @details Sends a data length update request to the server the client is connected to.
|
||||||
|
* The Data Length Extension (DLE) allows to increase the Data Channel Payload from 27 bytes to up to 251 bytes.
|
||||||
|
* The server needs to support the Bluetooth 4.2 specifications, to be capable of DLE.
|
||||||
|
* @param [in] tx_octets The preferred number of payload octets to use (Range 0x001B-0x00FB).
|
||||||
|
*/
|
||||||
|
void NimBLEClient::setDataLen(uint16_t tx_octets) {
|
||||||
|
#if defined(CONFIG_NIMBLE_CPP_IDF) && !defined(ESP_IDF_VERSION) || \
|
||||||
|
(ESP_IDF_VERSION_MAJOR * 100 + ESP_IDF_VERSION_MINOR * 10 + ESP_IDF_VERSION_PATCH) < 432
|
||||||
|
return;
|
||||||
|
#else
|
||||||
|
uint16_t tx_time = (tx_octets + 14) * 8;
|
||||||
|
|
||||||
|
int rc = ble_gap_set_data_len(m_conn_id, tx_octets, tx_time);
|
||||||
|
if(rc != 0) {
|
||||||
|
NIMBLE_LOGE(LOG_TAG, "Set data length error: %d, %s", rc, NimBLEUtils::returnCodeToString(rc));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} // setDataLen
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get detailed information about the current peer connection.
|
* @brief Get detailed information about the current peer connection.
|
||||||
*/
|
*/
|
||||||
|
@ -512,6 +589,7 @@ int NimBLEClient::getRssi() {
|
||||||
if(rc != 0) {
|
if(rc != 0) {
|
||||||
NIMBLE_LOGE(LOG_TAG, "Failed to read RSSI error code: %d, %s",
|
NIMBLE_LOGE(LOG_TAG, "Failed to read RSSI error code: %d, %s",
|
||||||
rc, NimBLEUtils::returnCodeToString(rc));
|
rc, NimBLEUtils::returnCodeToString(rc));
|
||||||
|
m_lastErr = rc;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -568,14 +646,31 @@ NimBLERemoteService* NimBLEClient::getService(const NimBLEUUID &uuid) {
|
||||||
return m_servicesVector.back();
|
return m_servicesVector.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the request was successful but 16/32 bit service not found
|
// If the request was successful but 16/32 bit uuid not found
|
||||||
// try again with the 128 bit uuid.
|
// try again with the 128 bit uuid.
|
||||||
if(uuid.bitSize() == BLE_UUID_TYPE_16 ||
|
if(uuid.bitSize() == BLE_UUID_TYPE_16 ||
|
||||||
uuid.bitSize() == BLE_UUID_TYPE_32)
|
uuid.bitSize() == BLE_UUID_TYPE_32)
|
||||||
{
|
{
|
||||||
NimBLEUUID uuid128(uuid);
|
NimBLEUUID uuid128(uuid);
|
||||||
uuid128.to128();
|
uuid128.to128();
|
||||||
return getService(uuid128);
|
if(retrieveServices(&uuid128)) {
|
||||||
|
if(m_servicesVector.size() > prev_size) {
|
||||||
|
return m_servicesVector.back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// If the request was successful but the 128 bit uuid not found
|
||||||
|
// try again with the 16 bit uuid.
|
||||||
|
NimBLEUUID uuid16(uuid);
|
||||||
|
uuid16.to16();
|
||||||
|
// if the uuid was 128 bit but not of the BLE base type this check will fail
|
||||||
|
if (uuid16.bitSize() == BLE_UUID_TYPE_16) {
|
||||||
|
if(retrieveServices(&uuid16)) {
|
||||||
|
if(m_servicesVector.size() > prev_size) {
|
||||||
|
return m_servicesVector.back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -639,7 +734,8 @@ bool NimBLEClient::retrieveServices(const NimBLEUUID *uuid_filter) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(), 0, nullptr};
|
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
|
||||||
|
ble_task_data_t taskData = {this, cur_task, 0, nullptr};
|
||||||
|
|
||||||
if(uuid_filter == nullptr) {
|
if(uuid_filter == nullptr) {
|
||||||
rc = ble_gattc_disc_all_svcs(m_conn_id, NimBLEClient::serviceDiscoveredCB, &taskData);
|
rc = ble_gattc_disc_all_svcs(m_conn_id, NimBLEClient::serviceDiscoveredCB, &taskData);
|
||||||
|
@ -650,11 +746,18 @@ bool NimBLEClient::retrieveServices(const NimBLEUUID *uuid_filter) {
|
||||||
|
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
NIMBLE_LOGE(LOG_TAG, "ble_gattc_disc_all_svcs: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
|
NIMBLE_LOGE(LOG_TAG, "ble_gattc_disc_all_svcs: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
|
||||||
|
m_lastErr = rc;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ulTaskNotifyValueClear
|
||||||
|
// Clear the task notification value to ensure we block
|
||||||
|
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
|
||||||
|
#endif
|
||||||
|
|
||||||
// wait until we have all the services
|
// wait until we have all the services
|
||||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||||
|
m_lastErr = taskData.rc;
|
||||||
|
|
||||||
if(taskData.rc == 0){
|
if(taskData.rc == 0){
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< retrieveServices");
|
NIMBLE_LOGD(LOG_TAG, "<< retrieveServices");
|
||||||
|
@ -698,7 +801,7 @@ int NimBLEClient::serviceDiscoveredCB(
|
||||||
if(error->status == BLE_HS_EDONE) {
|
if(error->status == BLE_HS_EDONE) {
|
||||||
pTaskData->rc = 0;
|
pTaskData->rc = 0;
|
||||||
} else {
|
} else {
|
||||||
NIMBLE_LOGE(LOG_TAG, "characteristicDiscCB() rc=%d %s",
|
NIMBLE_LOGE(LOG_TAG, "serviceDiscoveredCB() rc=%d %s",
|
||||||
error->status,
|
error->status,
|
||||||
NimBLEUtils::returnCodeToString(error->status));
|
NimBLEUtils::returnCodeToString(error->status));
|
||||||
pTaskData->rc = error->status;
|
pTaskData->rc = error->status;
|
||||||
|
@ -706,7 +809,7 @@ int NimBLEClient::serviceDiscoveredCB(
|
||||||
|
|
||||||
xTaskNotifyGive(pTaskData->task);
|
xTaskNotifyGive(pTaskData->task);
|
||||||
|
|
||||||
NIMBLE_LOGD(LOG_TAG,"<< << Service Discovered");
|
NIMBLE_LOGD(LOG_TAG,"<< Service Discovered");
|
||||||
return error->status;
|
return error->status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -717,11 +820,11 @@ int NimBLEClient::serviceDiscoveredCB(
|
||||||
* @param [in] characteristicUUID The characteristic whose value we wish to read.
|
* @param [in] characteristicUUID The characteristic whose value we wish to read.
|
||||||
* @returns characteristic value or an empty string if not found
|
* @returns characteristic value or an empty string if not found
|
||||||
*/
|
*/
|
||||||
std::string NimBLEClient::getValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID) {
|
NimBLEAttValue NimBLEClient::getValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID) {
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> getValue: serviceUUID: %s, characteristicUUID: %s",
|
NIMBLE_LOGD(LOG_TAG, ">> getValue: serviceUUID: %s, characteristicUUID: %s",
|
||||||
serviceUUID.toString().c_str(), characteristicUUID.toString().c_str());
|
serviceUUID.toString().c_str(), characteristicUUID.toString().c_str());
|
||||||
|
|
||||||
std::string ret = "";
|
NimBLEAttValue ret;
|
||||||
NimBLERemoteService* pService = getService(serviceUUID);
|
NimBLERemoteService* pService = getService(serviceUUID);
|
||||||
|
|
||||||
if(pService != nullptr) {
|
if(pService != nullptr) {
|
||||||
|
@ -745,7 +848,7 @@ std::string NimBLEClient::getValue(const NimBLEUUID &serviceUUID, const NimBLEUU
|
||||||
* @returns true if successful otherwise false
|
* @returns true if successful otherwise false
|
||||||
*/
|
*/
|
||||||
bool NimBLEClient::setValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID,
|
bool NimBLEClient::setValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID,
|
||||||
const std::string &value, bool response)
|
const NimBLEAttValue &value, bool response)
|
||||||
{
|
{
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> setValue: serviceUUID: %s, characteristicUUID: %s",
|
NIMBLE_LOGD(LOG_TAG, ">> setValue: serviceUUID: %s, characteristicUUID: %s",
|
||||||
serviceUUID.toString().c_str(), characteristicUUID.toString().c_str());
|
serviceUUID.toString().c_str(), characteristicUUID.toString().c_str());
|
||||||
|
@ -924,19 +1027,14 @@ uint16_t NimBLEClient::getMTU() {
|
||||||
NIMBLE_LOGD(LOG_TAG, "Got Notification for characteristic %s",
|
NIMBLE_LOGD(LOG_TAG, "Got Notification for characteristic %s",
|
||||||
(*characteristic)->toString().c_str());
|
(*characteristic)->toString().c_str());
|
||||||
|
|
||||||
time_t t = time(nullptr);
|
uint32_t data_len = OS_MBUF_PKTLEN(event->notify_rx.om);
|
||||||
portENTER_CRITICAL(&(*characteristic)->m_valMux);
|
(*characteristic)->m_value.setValue(event->notify_rx.om->om_data, data_len);
|
||||||
(*characteristic)->m_value = std::string((char *)event->notify_rx.om->om_data,
|
|
||||||
event->notify_rx.om->om_len);
|
|
||||||
(*characteristic)->m_timestamp = t;
|
|
||||||
portEXIT_CRITICAL(&(*characteristic)->m_valMux);
|
|
||||||
|
|
||||||
if ((*characteristic)->m_notifyCallback != nullptr) {
|
if ((*characteristic)->m_notifyCallback != nullptr) {
|
||||||
NIMBLE_LOGD(LOG_TAG, "Invoking callback for notification on characteristic %s",
|
NIMBLE_LOGD(LOG_TAG, "Invoking callback for notification on characteristic %s",
|
||||||
(*characteristic)->toString().c_str());
|
(*characteristic)->toString().c_str());
|
||||||
(*characteristic)->m_notifyCallback(*characteristic, event->notify_rx.om->om_data,
|
(*characteristic)->m_notifyCallback(*characteristic, event->notify_rx.om->om_data,
|
||||||
event->notify_rx.om->om_len,
|
data_len, !event->notify_rx.indication);
|
||||||
!event->notify_rx.indication);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1034,7 +1132,7 @@ uint16_t NimBLEClient::getMTU() {
|
||||||
NIMBLE_LOGD(LOG_TAG, "ble_sm_inject_io result: %d", rc);
|
NIMBLE_LOGD(LOG_TAG, "ble_sm_inject_io result: %d", rc);
|
||||||
|
|
||||||
} else if (event->passkey.params.action == BLE_SM_IOACT_NUMCMP) {
|
} else if (event->passkey.params.action == BLE_SM_IOACT_NUMCMP) {
|
||||||
NIMBLE_LOGD(LOG_TAG, "Passkey on device's display: %d", event->passkey.params.numcmp);
|
NIMBLE_LOGD(LOG_TAG, "Passkey on device's display: %" PRIu32, event->passkey.params.numcmp);
|
||||||
pkey.action = event->passkey.params.action;
|
pkey.action = event->passkey.params.action;
|
||||||
// Compatibility only - Do not use, should be removed the in future
|
// Compatibility only - Do not use, should be removed the in future
|
||||||
if(NimBLEDevice::m_securityCallbacks != nullptr) {
|
if(NimBLEDevice::m_securityCallbacks != nullptr) {
|
||||||
|
@ -1136,6 +1234,15 @@ std::string NimBLEClient::toString() {
|
||||||
} // toString
|
} // toString
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the last error code reported by the NimBLE host
|
||||||
|
* @return int, the NimBLE error code.
|
||||||
|
*/
|
||||||
|
int NimBLEClient::getLastError() {
|
||||||
|
return m_lastErr;
|
||||||
|
} // getLastError
|
||||||
|
|
||||||
|
|
||||||
void NimBLEClientCallbacks::onConnect(NimBLEClient* pClient) {
|
void NimBLEClientCallbacks::onConnect(NimBLEClient* pClient) {
|
||||||
NIMBLE_LOGD("NimBLEClientCallbacks", "onConnect: default");
|
NIMBLE_LOGD("NimBLEClientCallbacks", "onConnect: default");
|
||||||
}
|
}
|
||||||
|
@ -1170,5 +1277,4 @@ bool NimBLEClientCallbacks::onConfirmPIN(uint32_t pin){
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|
||||||
#endif // CONFIG_BT_ENABLED
|
|
||||||
|
|
|
@ -14,16 +14,14 @@
|
||||||
#ifndef MAIN_NIMBLECLIENT_H_
|
#ifndef MAIN_NIMBLECLIENT_H_
|
||||||
#define MAIN_NIMBLECLIENT_H_
|
#define MAIN_NIMBLECLIENT_H_
|
||||||
|
|
||||||
#include "sdkconfig.h"
|
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
|
||||||
|
|
||||||
#include "nimconfig.h"
|
#include "nimconfig.h"
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||||
|
|
||||||
#include "NimBLEAddress.h"
|
#include "NimBLEAddress.h"
|
||||||
#include "NimBLEUUID.h"
|
#include "NimBLEUUID.h"
|
||||||
#include "NimBLEUtils.h"
|
#include "NimBLEUtils.h"
|
||||||
#include "NimBLEConnInfo.h"
|
#include "NimBLEConnInfo.h"
|
||||||
|
#include "NimBLEAttValue.h"
|
||||||
#include "NimBLEAdvertisedDevice.h"
|
#include "NimBLEAdvertisedDevice.h"
|
||||||
#include "NimBLERemoteService.h"
|
#include "NimBLERemoteService.h"
|
||||||
|
|
||||||
|
@ -54,9 +52,9 @@ public:
|
||||||
NimBLERemoteService* getService(const NimBLEUUID &uuid);
|
NimBLERemoteService* getService(const NimBLEUUID &uuid);
|
||||||
void deleteServices();
|
void deleteServices();
|
||||||
size_t deleteService(const NimBLEUUID &uuid);
|
size_t deleteService(const NimBLEUUID &uuid);
|
||||||
std::string getValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID);
|
NimBLEAttValue getValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID);
|
||||||
bool setValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID,
|
bool setValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID,
|
||||||
const std::string &value, bool response = false);
|
const NimBLEAttValue &value, bool response = false);
|
||||||
NimBLERemoteCharacteristic* getCharacteristic(const uint16_t handle);
|
NimBLERemoteCharacteristic* getCharacteristic(const uint16_t handle);
|
||||||
bool isConnected();
|
bool isConnected();
|
||||||
void setClientCallbacks(NimBLEClientCallbacks *pClientCallbacks,
|
void setClientCallbacks(NimBLEClientCallbacks *pClientCallbacks,
|
||||||
|
@ -71,8 +69,13 @@ public:
|
||||||
uint16_t scanInterval=16, uint16_t scanWindow=16);
|
uint16_t scanInterval=16, uint16_t scanWindow=16);
|
||||||
void updateConnParams(uint16_t minInterval, uint16_t maxInterval,
|
void updateConnParams(uint16_t minInterval, uint16_t maxInterval,
|
||||||
uint16_t latency, uint16_t timeout);
|
uint16_t latency, uint16_t timeout);
|
||||||
|
void setDataLen(uint16_t tx_octets);
|
||||||
void discoverAttributes();
|
void discoverAttributes();
|
||||||
NimBLEConnInfo getConnInfo();
|
NimBLEConnInfo getConnInfo();
|
||||||
|
int getLastError();
|
||||||
|
#if CONFIG_BT_NIMBLE_EXT_ADV
|
||||||
|
void setConnectPhy(uint8_t mask);
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NimBLEClient(const NimBLEAddress &peerAddress);
|
NimBLEClient(const NimBLEAddress &peerAddress);
|
||||||
|
@ -90,6 +93,7 @@ private:
|
||||||
bool retrieveServices(const NimBLEUUID *uuid_filter = nullptr);
|
bool retrieveServices(const NimBLEUUID *uuid_filter = nullptr);
|
||||||
|
|
||||||
NimBLEAddress m_peerAddress;
|
NimBLEAddress m_peerAddress;
|
||||||
|
int m_lastErr;
|
||||||
uint16_t m_conn_id;
|
uint16_t m_conn_id;
|
||||||
bool m_connEstablished;
|
bool m_connEstablished;
|
||||||
bool m_deleteCallbacks;
|
bool m_deleteCallbacks;
|
||||||
|
@ -97,6 +101,9 @@ private:
|
||||||
NimBLEClientCallbacks* m_pClientCallbacks;
|
NimBLEClientCallbacks* m_pClientCallbacks;
|
||||||
ble_task_data_t* m_pTaskData;
|
ble_task_data_t* m_pTaskData;
|
||||||
ble_npl_callout m_dcTimer;
|
ble_npl_callout m_dcTimer;
|
||||||
|
#if CONFIG_BT_NIMBLE_EXT_ADV
|
||||||
|
uint8_t m_phyMask;
|
||||||
|
#endif
|
||||||
|
|
||||||
std::vector<NimBLERemoteService*> m_servicesVector;
|
std::vector<NimBLERemoteService*> m_servicesVector;
|
||||||
|
|
||||||
|
@ -158,6 +165,5 @@ public:
|
||||||
virtual bool onConfirmPIN(uint32_t pin);
|
virtual bool onConfirmPIN(uint32_t pin);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|
||||||
#endif // CONFIG_BT_ENABLED
|
|
||||||
#endif /* MAIN_NIMBLECLIENT_H_ */
|
#endif /* MAIN_NIMBLECLIENT_H_ */
|
||||||
|
|
|
@ -11,11 +11,9 @@
|
||||||
* Created on: Jun 22, 2017
|
* Created on: Jun 22, 2017
|
||||||
* Author: kolban
|
* Author: kolban
|
||||||
*/
|
*/
|
||||||
#include "sdkconfig.h"
|
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
|
||||||
|
|
||||||
#include "nimconfig.h"
|
#include "nimconfig.h"
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||||
|
|
||||||
#include "NimBLEService.h"
|
#include "NimBLEService.h"
|
||||||
#include "NimBLEDescriptor.h"
|
#include "NimBLEDescriptor.h"
|
||||||
|
@ -30,28 +28,32 @@ static NimBLEDescriptorCallbacks defaultCallbacks;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief NimBLEDescriptor constructor.
|
* @brief Construct a descriptor
|
||||||
|
* @param [in] uuid - UUID (const char*) for the descriptor.
|
||||||
|
* @param [in] properties - Properties for the descriptor.
|
||||||
|
* @param [in] max_len - The maximum length in bytes that the descriptor value can hold. (Default: 512 bytes for esp32, 20 for all others).
|
||||||
|
* @param [in] pCharacteristic - pointer to the characteristic instance this descriptor belongs to.
|
||||||
*/
|
*/
|
||||||
NimBLEDescriptor::NimBLEDescriptor(const char* uuid, uint16_t properties, uint16_t max_len,
|
NimBLEDescriptor::NimBLEDescriptor(const char* uuid, uint16_t properties, uint16_t max_len,
|
||||||
NimBLECharacteristic* pCharacteristic)
|
NimBLECharacteristic* pCharacteristic)
|
||||||
: NimBLEDescriptor(NimBLEUUID(uuid), max_len, properties, pCharacteristic) {
|
: NimBLEDescriptor(NimBLEUUID(uuid), properties, max_len, pCharacteristic) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief NimBLEDescriptor constructor.
|
* @brief Construct a descriptor
|
||||||
|
* @param [in] uuid - UUID (const char*) for the descriptor.
|
||||||
|
* @param [in] properties - Properties for the descriptor.
|
||||||
|
* @param [in] max_len - The maximum length in bytes that the descriptor value can hold. (Default: 512 bytes for esp32, 20 for all others).
|
||||||
|
* @param [in] pCharacteristic - pointer to the characteristic instance this descriptor belongs to.
|
||||||
*/
|
*/
|
||||||
NimBLEDescriptor::NimBLEDescriptor(NimBLEUUID uuid, uint16_t properties, uint16_t max_len,
|
NimBLEDescriptor::NimBLEDescriptor(NimBLEUUID uuid, uint16_t properties, uint16_t max_len,
|
||||||
NimBLECharacteristic* pCharacteristic)
|
NimBLECharacteristic* pCharacteristic)
|
||||||
{
|
: m_value(std::min(CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH , (int)max_len), max_len) {
|
||||||
m_uuid = uuid;
|
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_handle = NULL_HANDLE; // Handle is initially unknown.
|
||||||
m_pCharacteristic = pCharacteristic;
|
m_pCharacteristic = pCharacteristic;
|
||||||
m_pCallbacks = &defaultCallbacks; // No initial callback.
|
m_pCallbacks = &defaultCallbacks; // No initial callback.
|
||||||
m_value.attr_value = (uint8_t*) calloc(max_len,1); // Allocate storage for the value.
|
|
||||||
m_valMux = portMUX_INITIALIZER_UNLOCKED;
|
|
||||||
m_properties = 0;
|
m_properties = 0;
|
||||||
m_removed = 0;
|
m_removed = 0;
|
||||||
|
|
||||||
|
@ -87,7 +89,6 @@ NimBLEDescriptor::NimBLEDescriptor(NimBLEUUID uuid, uint16_t properties, uint16_
|
||||||
* @brief NimBLEDescriptor destructor.
|
* @brief NimBLEDescriptor destructor.
|
||||||
*/
|
*/
|
||||||
NimBLEDescriptor::~NimBLEDescriptor() {
|
NimBLEDescriptor::~NimBLEDescriptor() {
|
||||||
free(m_value.attr_value); // Release the storage we created in the constructor.
|
|
||||||
} // ~NimBLEDescriptor
|
} // ~NimBLEDescriptor
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -104,7 +105,7 @@ uint16_t NimBLEDescriptor::getHandle() {
|
||||||
* @return The length (in bytes) of the value of this descriptor.
|
* @return The length (in bytes) of the value of this descriptor.
|
||||||
*/
|
*/
|
||||||
size_t NimBLEDescriptor::getLength() {
|
size_t NimBLEDescriptor::getLength() {
|
||||||
return m_value.attr_len;
|
return m_value.size();
|
||||||
} // getLength
|
} // getLength
|
||||||
|
|
||||||
|
|
||||||
|
@ -118,10 +119,14 @@ NimBLEUUID NimBLEDescriptor::getUUID() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the value of this descriptor.
|
* @brief Get the value of this descriptor.
|
||||||
* @return A pointer to the value of this descriptor.
|
* @return The NimBLEAttValue of this descriptor.
|
||||||
*/
|
*/
|
||||||
uint8_t* NimBLEDescriptor::getValue() {
|
NimBLEAttValue NimBLEDescriptor::getValue(time_t *timestamp) {
|
||||||
return m_value.attr_value;
|
if (timestamp != nullptr) {
|
||||||
|
m_value.getValue(timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_value;
|
||||||
} // getValue
|
} // getValue
|
||||||
|
|
||||||
|
|
||||||
|
@ -130,7 +135,7 @@ uint8_t* NimBLEDescriptor::getValue() {
|
||||||
* @return A std::string instance containing a copy of the descriptor's value.
|
* @return A std::string instance containing a copy of the descriptor's value.
|
||||||
*/
|
*/
|
||||||
std::string NimBLEDescriptor::getStringValue() {
|
std::string NimBLEDescriptor::getStringValue() {
|
||||||
return std::string((char *) m_value.attr_value, m_value.attr_len);
|
return std::string(m_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -145,6 +150,9 @@ NimBLECharacteristic* NimBLEDescriptor::getCharacteristic() {
|
||||||
|
|
||||||
int NimBLEDescriptor::handleGapEvent(uint16_t conn_handle, uint16_t attr_handle,
|
int NimBLEDescriptor::handleGapEvent(uint16_t conn_handle, uint16_t attr_handle,
|
||||||
struct ble_gatt_access_ctxt *ctxt, void *arg) {
|
struct ble_gatt_access_ctxt *ctxt, void *arg) {
|
||||||
|
(void)conn_handle;
|
||||||
|
(void)attr_handle;
|
||||||
|
|
||||||
const ble_uuid_t *uuid;
|
const ble_uuid_t *uuid;
|
||||||
int rc;
|
int rc;
|
||||||
NimBLEDescriptor* pDescriptor = (NimBLEDescriptor*)arg;
|
NimBLEDescriptor* pDescriptor = (NimBLEDescriptor*)arg;
|
||||||
|
@ -161,24 +169,27 @@ int NimBLEDescriptor::handleGapEvent(uint16_t conn_handle, uint16_t attr_handle,
|
||||||
if(ctxt->om->om_pkthdr_len > 8) {
|
if(ctxt->om->om_pkthdr_len > 8) {
|
||||||
pDescriptor->m_pCallbacks->onRead(pDescriptor);
|
pDescriptor->m_pCallbacks->onRead(pDescriptor);
|
||||||
}
|
}
|
||||||
portENTER_CRITICAL(&pDescriptor->m_valMux);
|
|
||||||
rc = os_mbuf_append(ctxt->om, pDescriptor->getValue(), pDescriptor->getLength());
|
ble_npl_hw_enter_critical();
|
||||||
portEXIT_CRITICAL(&pDescriptor->m_valMux);
|
rc = os_mbuf_append(ctxt->om, pDescriptor->m_value.data(), pDescriptor->m_value.size());
|
||||||
|
ble_npl_hw_exit_critical(0);
|
||||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||||
}
|
}
|
||||||
|
|
||||||
case BLE_GATT_ACCESS_OP_WRITE_DSC: {
|
case BLE_GATT_ACCESS_OP_WRITE_DSC: {
|
||||||
if (ctxt->om->om_len > pDescriptor->m_value.attr_max_len) {
|
uint16_t att_max_len = pDescriptor->m_value.max_size();
|
||||||
|
|
||||||
|
if (ctxt->om->om_len > att_max_len) {
|
||||||
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t buf[pDescriptor->m_value.attr_max_len];
|
uint8_t buf[att_max_len];
|
||||||
size_t len = ctxt->om->om_len;
|
size_t len = ctxt->om->om_len;
|
||||||
memcpy(buf, ctxt->om->om_data,len);
|
memcpy(buf, ctxt->om->om_data,len);
|
||||||
os_mbuf *next;
|
os_mbuf *next;
|
||||||
next = SLIST_NEXT(ctxt->om, om_next);
|
next = SLIST_NEXT(ctxt->om, om_next);
|
||||||
while(next != NULL){
|
while(next != NULL){
|
||||||
if((len + next->om_len) > pDescriptor->m_value.attr_max_len) {
|
if((len + next->om_len) > att_max_len) {
|
||||||
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||||
}
|
}
|
||||||
memcpy(&buf[len], next->om_data, next->om_len);
|
memcpy(&buf[len], next->om_data, next->om_len);
|
||||||
|
@ -230,25 +241,19 @@ void NimBLEDescriptor::setHandle(uint16_t handle) {
|
||||||
* @param [in] length The length of the data in bytes.
|
* @param [in] length The length of the data in bytes.
|
||||||
*/
|
*/
|
||||||
void NimBLEDescriptor::setValue(const uint8_t* data, size_t length) {
|
void NimBLEDescriptor::setValue(const uint8_t* data, size_t length) {
|
||||||
if (length > m_value.attr_max_len) {
|
m_value.setValue(data, length);
|
||||||
NIMBLE_LOGE(LOG_TAG, "Size %d too large, must be no bigger than %d", length, m_value.attr_max_len);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
portENTER_CRITICAL(&m_valMux);
|
|
||||||
m_value.attr_len = length;
|
|
||||||
memcpy(m_value.attr_value, data, length);
|
|
||||||
portEXIT_CRITICAL(&m_valMux);
|
|
||||||
} // setValue
|
} // setValue
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set the value of the descriptor.
|
* @brief Set the value of the descriptor from a `std::vector<uint8_t>`.\n
|
||||||
* @param [in] value The value of the descriptor in string form.
|
* @param [in] vec The std::vector<uint8_t> reference to set the descriptor value from.
|
||||||
*/
|
*/
|
||||||
void NimBLEDescriptor::setValue(const std::string &value) {
|
void NimBLEDescriptor::setValue(const std::vector<uint8_t>& vec) {
|
||||||
setValue((uint8_t*) value.data(), value.length());
|
return setValue((uint8_t*)&vec[0], vec.size());
|
||||||
} // setValue
|
} // setValue
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set the characteristic this descriptor belongs to.
|
* @brief Set the characteristic this descriptor belongs to.
|
||||||
* @param [in] pChar A pointer to the characteristic this descriptior belongs to.
|
* @param [in] pChar A pointer to the characteristic this descriptior belongs to.
|
||||||
|
@ -277,6 +282,7 @@ NimBLEDescriptorCallbacks::~NimBLEDescriptorCallbacks() {}
|
||||||
* @param [in] pDescriptor The descriptor that is the source of the event.
|
* @param [in] pDescriptor The descriptor that is the source of the event.
|
||||||
*/
|
*/
|
||||||
void NimBLEDescriptorCallbacks::onRead(NimBLEDescriptor* pDescriptor) {
|
void NimBLEDescriptorCallbacks::onRead(NimBLEDescriptor* pDescriptor) {
|
||||||
|
(void)pDescriptor;
|
||||||
NIMBLE_LOGD("NimBLEDescriptorCallbacks", "onRead: default");
|
NIMBLE_LOGD("NimBLEDescriptorCallbacks", "onRead: default");
|
||||||
} // onRead
|
} // onRead
|
||||||
|
|
||||||
|
@ -286,8 +292,8 @@ void NimBLEDescriptorCallbacks::onRead(NimBLEDescriptor* pDescriptor) {
|
||||||
* @param [in] pDescriptor The descriptor that is the source of the event.
|
* @param [in] pDescriptor The descriptor that is the source of the event.
|
||||||
*/
|
*/
|
||||||
void NimBLEDescriptorCallbacks::onWrite(NimBLEDescriptor* pDescriptor) {
|
void NimBLEDescriptorCallbacks::onWrite(NimBLEDescriptor* pDescriptor) {
|
||||||
|
(void)pDescriptor;
|
||||||
NIMBLE_LOGD("NimBLEDescriptorCallbacks", "onWrite: default");
|
NIMBLE_LOGD("NimBLEDescriptorCallbacks", "onWrite: default");
|
||||||
} // onWrite
|
} // onWrite
|
||||||
|
|
||||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||||
#endif /* CONFIG_BT_ENABLED */
|
|
||||||
|
|
|
@ -14,25 +14,16 @@
|
||||||
|
|
||||||
#ifndef MAIN_NIMBLEDESCRIPTOR_H_
|
#ifndef MAIN_NIMBLEDESCRIPTOR_H_
|
||||||
#define MAIN_NIMBLEDESCRIPTOR_H_
|
#define MAIN_NIMBLEDESCRIPTOR_H_
|
||||||
#include "sdkconfig.h"
|
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
|
||||||
|
|
||||||
#include "nimconfig.h"
|
#include "nimconfig.h"
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||||
|
|
||||||
#include "NimBLECharacteristic.h"
|
#include "NimBLECharacteristic.h"
|
||||||
#include "NimBLEUUID.h"
|
#include "NimBLEUUID.h"
|
||||||
|
#include "NimBLEAttValue.h"
|
||||||
|
|
||||||
#include <string>
|
#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 NimBLEService;
|
||||||
class NimBLECharacteristic;
|
class NimBLECharacteristic;
|
||||||
class NimBLEDescriptorCallbacks;
|
class NimBLEDescriptorCallbacks;
|
||||||
|
@ -56,24 +47,36 @@ public:
|
||||||
uint16_t getHandle();
|
uint16_t getHandle();
|
||||||
NimBLEUUID getUUID();
|
NimBLEUUID getUUID();
|
||||||
std::string toString();
|
std::string toString();
|
||||||
|
|
||||||
void setCallbacks(NimBLEDescriptorCallbacks* pCallbacks);
|
void setCallbacks(NimBLEDescriptorCallbacks* pCallbacks);
|
||||||
|
NimBLECharacteristic* getCharacteristic();
|
||||||
|
|
||||||
size_t getLength();
|
size_t getLength();
|
||||||
uint8_t* getValue();
|
NimBLEAttValue getValue(time_t *timestamp = nullptr);
|
||||||
std::string getStringValue();
|
std::string getStringValue();
|
||||||
|
|
||||||
void setValue(const uint8_t* data, size_t size);
|
void setValue(const uint8_t* data, size_t size);
|
||||||
void setValue(const std::string &value);
|
void setValue(const std::vector<uint8_t>& vec);
|
||||||
NimBLECharacteristic* getCharacteristic();
|
|
||||||
|
/*********************** Template Functions ************************/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Convenience template to set the descriptor value to <type\>val.
|
* @brief Template to set the characteristic value to <type\>val.
|
||||||
* @param [in] s The value to set.
|
* @param [in] s The value to set.
|
||||||
*/
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void setValue(const T &s) {
|
void setValue(const T &s) { m_value.setValue<T>(s); }
|
||||||
setValue((uint8_t*)&s, sizeof(T));
|
|
||||||
|
/**
|
||||||
|
* @brief Template to convert the descriptor data to <type\>.
|
||||||
|
* @tparam T The type to convert the data to.
|
||||||
|
* @param [in] timestamp (Optional) A pointer to a time_t struct to store the time the value was read.
|
||||||
|
* @param [in] skipSizeCheck (Optional) 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) {
|
||||||
|
return m_value.getValue<T>(timestamp, skipSizeCheck);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -91,8 +94,7 @@ private:
|
||||||
NimBLEDescriptorCallbacks* m_pCallbacks;
|
NimBLEDescriptorCallbacks* m_pCallbacks;
|
||||||
NimBLECharacteristic* m_pCharacteristic;
|
NimBLECharacteristic* m_pCharacteristic;
|
||||||
uint8_t m_properties;
|
uint8_t m_properties;
|
||||||
attr_value_t m_value;
|
NimBLEAttValue m_value;
|
||||||
portMUX_TYPE m_valMux;
|
|
||||||
uint8_t m_removed;
|
uint8_t m_removed;
|
||||||
}; // NimBLEDescriptor
|
}; // NimBLEDescriptor
|
||||||
|
|
||||||
|
@ -113,6 +115,5 @@ public:
|
||||||
|
|
||||||
#include "NimBLE2904.h"
|
#include "NimBLE2904.h"
|
||||||
|
|
||||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||||
#endif /* CONFIG_BT_ENABLED */
|
|
||||||
#endif /* MAIN_NIMBLEDESCRIPTOR_H_ */
|
#endif /* MAIN_NIMBLEDESCRIPTOR_H_ */
|
||||||
|
|
|
@ -11,16 +11,18 @@
|
||||||
* Created on: Mar 16, 2017
|
* Created on: Mar 16, 2017
|
||||||
* Author: kolban
|
* Author: kolban
|
||||||
*/
|
*/
|
||||||
#include "sdkconfig.h"
|
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
|
||||||
|
|
||||||
#include "nimconfig.h"
|
#include "nimconfig.h"
|
||||||
|
#if defined(CONFIG_BT_ENABLED)
|
||||||
|
|
||||||
#include "NimBLEDevice.h"
|
#include "NimBLEDevice.h"
|
||||||
#include "NimBLEUtils.h"
|
#include "NimBLEUtils.h"
|
||||||
|
|
||||||
|
#ifdef ESP_PLATFORM
|
||||||
# include "esp_err.h"
|
# include "esp_err.h"
|
||||||
# include "esp_bt.h"
|
# include "esp_bt.h"
|
||||||
# include "nvs_flash.h"
|
# include "nvs_flash.h"
|
||||||
|
# if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||||
# include "esp_nimble_hci.h"
|
# include "esp_nimble_hci.h"
|
||||||
# include "nimble/nimble_port.h"
|
# include "nimble/nimble_port.h"
|
||||||
# include "nimble/nimble_port_freertos.h"
|
# include "nimble/nimble_port_freertos.h"
|
||||||
|
@ -29,8 +31,24 @@
|
||||||
# include "host/util/util.h"
|
# include "host/util/util.h"
|
||||||
# include "services/gap/ble_svc_gap.h"
|
# include "services/gap/ble_svc_gap.h"
|
||||||
# include "services/gatt/ble_svc_gatt.h"
|
# include "services/gatt/ble_svc_gatt.h"
|
||||||
|
# else
|
||||||
|
# include "nimble/esp_port/esp-hci/include/esp_nimble_hci.h"
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# include "nimble/nimble/controller/include/controller/ble_phy.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_ENABLE_ARDUINO_DEPENDS
|
#ifndef CONFIG_NIMBLE_CPP_IDF
|
||||||
|
# include "nimble/porting/nimble/include/nimble/nimble_port.h"
|
||||||
|
# include "nimble/porting/npl/freertos/include/nimble/nimble_port_freertos.h"
|
||||||
|
# include "nimble/nimble/host/include/host/ble_hs.h"
|
||||||
|
# include "nimble/nimble/host/include/host/ble_hs_pvcy.h"
|
||||||
|
# include "nimble/nimble/host/util/include/host/util/util.h"
|
||||||
|
# include "nimble/nimble/host/services/gap/include/services/gap/ble_svc_gap.h"
|
||||||
|
# include "nimble/nimble/host/services/gatt/include/services/gatt/ble_svc_gatt.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(ESP_PLATFORM) && defined(CONFIG_ENABLE_ARDUINO_DEPENDS)
|
||||||
# include "esp32-hal-bt.h"
|
# include "esp32-hal-bt.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -51,8 +69,12 @@ NimBLEServer* NimBLEDevice::m_pServer = nullptr;
|
||||||
uint32_t NimBLEDevice::m_passkey = 123456;
|
uint32_t NimBLEDevice::m_passkey = 123456;
|
||||||
bool NimBLEDevice::m_synced = false;
|
bool NimBLEDevice::m_synced = false;
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||||
|
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||||
|
NimBLEExtAdvertising* NimBLEDevice::m_bleAdvertising = nullptr;
|
||||||
|
# else
|
||||||
NimBLEAdvertising* NimBLEDevice::m_bleAdvertising = nullptr;
|
NimBLEAdvertising* NimBLEDevice::m_bleAdvertising = nullptr;
|
||||||
# endif
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
NimBLEMeshNode* NimBLEDevice::m_pMeshNode = nullptr;
|
NimBLEMeshNode* NimBLEDevice::m_pMeshNode = nullptr;
|
||||||
|
|
||||||
|
@ -65,9 +87,10 @@ std::list <NimBLEAddress> NimBLEDevice::m_ignoreList;
|
||||||
std::vector<NimBLEAddress> NimBLEDevice::m_whiteList;
|
std::vector<NimBLEAddress> NimBLEDevice::m_whiteList;
|
||||||
NimBLESecurityCallbacks* NimBLEDevice::m_securityCallbacks = nullptr;
|
NimBLESecurityCallbacks* NimBLEDevice::m_securityCallbacks = nullptr;
|
||||||
uint8_t NimBLEDevice::m_own_addr_type = BLE_OWN_ADDR_PUBLIC;
|
uint8_t NimBLEDevice::m_own_addr_type = BLE_OWN_ADDR_PUBLIC;
|
||||||
|
#ifdef ESP_PLATFORM
|
||||||
uint16_t NimBLEDevice::m_scanDuplicateSize = CONFIG_BTDM_SCAN_DUPL_CACHE_SIZE;
|
uint16_t NimBLEDevice::m_scanDuplicateSize = CONFIG_BTDM_SCAN_DUPL_CACHE_SIZE;
|
||||||
uint8_t NimBLEDevice::m_scanFilterMode = CONFIG_BTDM_SCAN_DUPL_TYPE;
|
uint8_t NimBLEDevice::m_scanFilterMode = CONFIG_BTDM_SCAN_DUPL_TYPE;
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create a new mesh node.
|
* @brief Create a new mesh node.
|
||||||
|
@ -121,6 +144,45 @@ NimBLEMeshNode* NimBLEDevice::getMeshNode() {
|
||||||
|
|
||||||
|
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||||
|
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||||
|
/**
|
||||||
|
* @brief Get the instance of the advertising object.
|
||||||
|
* @return A pointer to the advertising object.
|
||||||
|
*/
|
||||||
|
NimBLEExtAdvertising* NimBLEDevice::getAdvertising() {
|
||||||
|
if(m_bleAdvertising == nullptr) {
|
||||||
|
m_bleAdvertising = new NimBLEExtAdvertising();
|
||||||
|
}
|
||||||
|
return m_bleAdvertising;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Convenience function to begin advertising.
|
||||||
|
* @param [in] inst_id The extended advertisement instance ID to start.
|
||||||
|
* @param [in] duration How long to advertise for in milliseconds, 0 = forever (default).
|
||||||
|
* @param [in] max_events Maximum number of advertisement events to send, 0 = no limit (default).
|
||||||
|
* @return True if advertising started successfully.
|
||||||
|
*/
|
||||||
|
bool NimBLEDevice::startAdvertising(uint8_t inst_id,
|
||||||
|
int duration,
|
||||||
|
int max_events) {
|
||||||
|
return getAdvertising()->start(inst_id, duration, max_events);
|
||||||
|
} // startAdvertising
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Convenience function to stop advertising a data set.
|
||||||
|
* @param [in] inst_id The extended advertisement instance ID to stop advertising.
|
||||||
|
* @return True if advertising stopped successfully.
|
||||||
|
*/
|
||||||
|
bool NimBLEDevice::stopAdvertising(uint8_t inst_id) {
|
||||||
|
return getAdvertising()->stop(inst_id);
|
||||||
|
} // stopAdvertising
|
||||||
|
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_)
|
||||||
/**
|
/**
|
||||||
* @brief Get the instance of the advertising object.
|
* @brief Get the instance of the advertising object.
|
||||||
* @return A pointer to the advertising object.
|
* @return A pointer to the advertising object.
|
||||||
|
@ -135,17 +197,19 @@ NimBLEAdvertising* NimBLEDevice::getAdvertising() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Convenience function to begin advertising.
|
* @brief Convenience function to begin advertising.
|
||||||
|
* @return True if advertising started successfully.
|
||||||
*/
|
*/
|
||||||
void NimBLEDevice::startAdvertising() {
|
bool NimBLEDevice::startAdvertising() {
|
||||||
getAdvertising()->start();
|
return getAdvertising()->start();
|
||||||
} // startAdvertising
|
} // startAdvertising
|
||||||
|
# endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Convenience function to stop advertising.
|
* @brief Convenience function to stop all advertising.
|
||||||
|
* @return True if advertising stopped successfully.
|
||||||
*/
|
*/
|
||||||
void NimBLEDevice::stopAdvertising() {
|
bool NimBLEDevice::stopAdvertising() {
|
||||||
getAdvertising()->stop();
|
return getAdvertising()->stop();
|
||||||
} // stopAdvertising
|
} // stopAdvertising
|
||||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||||
|
|
||||||
|
@ -156,7 +220,8 @@ void NimBLEDevice::stopAdvertising() {
|
||||||
* try and release/delete it.
|
* try and release/delete it.
|
||||||
*/
|
*/
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||||
/* STATIC */ NimBLEScan* NimBLEDevice::getScan() {
|
/* STATIC */
|
||||||
|
NimBLEScan* NimBLEDevice::getScan() {
|
||||||
if (m_pScan == nullptr) {
|
if (m_pScan == nullptr) {
|
||||||
m_pScan = new NimBLEScan();
|
m_pScan = new NimBLEScan();
|
||||||
}
|
}
|
||||||
|
@ -173,7 +238,8 @@ void NimBLEDevice::stopAdvertising() {
|
||||||
* @return A reference to the new client object.
|
* @return A reference to the new client object.
|
||||||
*/
|
*/
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
#if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||||
/* STATIC */ NimBLEClient* NimBLEDevice::createClient(NimBLEAddress peerAddress) {
|
/* STATIC */
|
||||||
|
NimBLEClient* NimBLEDevice::createClient(NimBLEAddress peerAddress) {
|
||||||
if(m_cList.size() >= NIMBLE_MAX_CONNECTIONS) {
|
if(m_cList.size() >= NIMBLE_MAX_CONNECTIONS) {
|
||||||
NIMBLE_LOGW(LOG_TAG,"Number of clients exceeds Max connections. Cur=%d Max=%d",
|
NIMBLE_LOGW(LOG_TAG,"Number of clients exceeds Max connections. Cur=%d Max=%d",
|
||||||
m_cList.size(), NIMBLE_MAX_CONNECTIONS);
|
m_cList.size(), NIMBLE_MAX_CONNECTIONS);
|
||||||
|
@ -191,7 +257,8 @@ void NimBLEDevice::stopAdvertising() {
|
||||||
* Checks if it is connected or trying to connect and disconnects/stops it first.
|
* Checks if it is connected or trying to connect and disconnects/stops it first.
|
||||||
* @param [in] pClient A pointer to the client object.
|
* @param [in] pClient A pointer to the client object.
|
||||||
*/
|
*/
|
||||||
/* STATIC */ bool NimBLEDevice::deleteClient(NimBLEClient* pClient) {
|
/* STATIC */
|
||||||
|
bool NimBLEDevice::deleteClient(NimBLEClient* pClient) {
|
||||||
if(pClient == nullptr) {
|
if(pClient == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -235,7 +302,8 @@ void NimBLEDevice::stopAdvertising() {
|
||||||
* @brief Get the list of created client objects.
|
* @brief Get the list of created client objects.
|
||||||
* @return A pointer to the list of clients.
|
* @return A pointer to the list of clients.
|
||||||
*/
|
*/
|
||||||
/* STATIC */std::list<NimBLEClient*>* NimBLEDevice::getClientList() {
|
/* STATIC */
|
||||||
|
std::list<NimBLEClient*>* NimBLEDevice::getClientList() {
|
||||||
return &m_cList;
|
return &m_cList;
|
||||||
} // getClientList
|
} // getClientList
|
||||||
|
|
||||||
|
@ -244,7 +312,8 @@ void NimBLEDevice::stopAdvertising() {
|
||||||
* @brief Get the number of created client objects.
|
* @brief Get the number of created client objects.
|
||||||
* @return Number of client objects created.
|
* @return Number of client objects created.
|
||||||
*/
|
*/
|
||||||
/* STATIC */size_t NimBLEDevice::getClientListSize() {
|
/* STATIC */
|
||||||
|
size_t NimBLEDevice::getClientListSize() {
|
||||||
return m_cList.size();
|
return m_cList.size();
|
||||||
} // getClientList
|
} // getClientList
|
||||||
|
|
||||||
|
@ -254,7 +323,8 @@ void NimBLEDevice::stopAdvertising() {
|
||||||
* @param [in] conn_id The client connection ID to search for.
|
* @param [in] conn_id The client connection ID to search for.
|
||||||
* @return A pointer to the client object with the spcified connection ID.
|
* @return A pointer to the client object with the spcified connection ID.
|
||||||
*/
|
*/
|
||||||
/* STATIC */NimBLEClient* NimBLEDevice::getClientByID(uint16_t conn_id) {
|
/* STATIC */
|
||||||
|
NimBLEClient* NimBLEDevice::getClientByID(uint16_t conn_id) {
|
||||||
for(auto it = m_cList.cbegin(); it != m_cList.cend(); ++it) {
|
for(auto it = m_cList.cbegin(); it != m_cList.cend(); ++it) {
|
||||||
if((*it)->getConnId() == conn_id) {
|
if((*it)->getConnId() == conn_id) {
|
||||||
return (*it);
|
return (*it);
|
||||||
|
@ -270,7 +340,8 @@ void NimBLEDevice::stopAdvertising() {
|
||||||
* @param [in] peer_addr The address of the peer to search for.
|
* @param [in] peer_addr The address of the peer to search for.
|
||||||
* @return A pointer to the client object with the peer address.
|
* @return A pointer to the client object with the peer address.
|
||||||
*/
|
*/
|
||||||
/* STATIC */NimBLEClient* NimBLEDevice::getClientByPeerAddress(const NimBLEAddress &peer_addr) {
|
/* STATIC */
|
||||||
|
NimBLEClient* NimBLEDevice::getClientByPeerAddress(const NimBLEAddress &peer_addr) {
|
||||||
for(auto it = m_cList.cbegin(); it != m_cList.cend(); ++it) {
|
for(auto it = m_cList.cbegin(); it != m_cList.cend(); ++it) {
|
||||||
if((*it)->getPeerAddress().equals(peer_addr)) {
|
if((*it)->getPeerAddress().equals(peer_addr)) {
|
||||||
return (*it);
|
return (*it);
|
||||||
|
@ -284,7 +355,8 @@ void NimBLEDevice::stopAdvertising() {
|
||||||
* @brief Finds the first disconnected client in the list.
|
* @brief Finds the first disconnected client in the list.
|
||||||
* @return A pointer to the first client object that is not connected to a peer.
|
* @return A pointer to the first client object that is not connected to a peer.
|
||||||
*/
|
*/
|
||||||
/* STATIC */NimBLEClient* NimBLEDevice::getDisconnectedClient() {
|
/* STATIC */
|
||||||
|
NimBLEClient* NimBLEDevice::getDisconnectedClient() {
|
||||||
for(auto it = m_cList.cbegin(); it != m_cList.cend(); ++it) {
|
for(auto it = m_cList.cbegin(); it != m_cList.cend(); ++it) {
|
||||||
if(!(*it)->isConnected()) {
|
if(!(*it)->isConnected()) {
|
||||||
return (*it);
|
return (*it);
|
||||||
|
@ -295,7 +367,7 @@ void NimBLEDevice::stopAdvertising() {
|
||||||
|
|
||||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||||
|
|
||||||
|
#ifdef ESP_PLATFORM
|
||||||
/**
|
/**
|
||||||
* @brief Set the transmission power.
|
* @brief Set the transmission power.
|
||||||
* @param [in] powerLevel The power level to set, can be one of:
|
* @param [in] powerLevel The power level to set, can be one of:
|
||||||
|
@ -321,12 +393,15 @@ void NimBLEDevice::stopAdvertising() {
|
||||||
* * ESP_BLE_PWR_TYPE_SCAN = 10, For scan
|
* * ESP_BLE_PWR_TYPE_SCAN = 10, For scan
|
||||||
* * ESP_BLE_PWR_TYPE_DEFAULT = 11, For default, if not set other, it will use default value
|
* * ESP_BLE_PWR_TYPE_DEFAULT = 11, For default, if not set other, it will use default value
|
||||||
*/
|
*/
|
||||||
/* STATIC */ void NimBLEDevice::setPower(esp_power_level_t powerLevel, esp_ble_power_type_t powerType) {
|
/* STATIC */
|
||||||
|
void NimBLEDevice::setPower(esp_power_level_t powerLevel, esp_ble_power_type_t powerType) {
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> setPower: %d (type: %d)", powerLevel, powerType);
|
NIMBLE_LOGD(LOG_TAG, ">> setPower: %d (type: %d)", powerLevel, powerType);
|
||||||
|
|
||||||
esp_err_t errRc = esp_ble_tx_power_set(powerType, powerLevel);
|
esp_err_t errRc = esp_ble_tx_power_set(powerType, powerLevel);
|
||||||
if (errRc != ESP_OK) {
|
if (errRc != ESP_OK) {
|
||||||
NIMBLE_LOGE(LOG_TAG, "esp_ble_tx_power_set: rc=%d", errRc);
|
NIMBLE_LOGE(LOG_TAG, "esp_ble_tx_power_set: rc=%d", errRc);
|
||||||
}
|
}
|
||||||
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< setPower");
|
NIMBLE_LOGD(LOG_TAG, "<< setPower");
|
||||||
} // setPower
|
} // setPower
|
||||||
|
|
||||||
|
@ -348,9 +423,8 @@ void NimBLEDevice::stopAdvertising() {
|
||||||
* * ESP_BLE_PWR_TYPE_DEFAULT = 11, For default, if not set other, it will use default value
|
* * ESP_BLE_PWR_TYPE_DEFAULT = 11, For default, if not set other, it will use default value
|
||||||
* @return the power level currently used by the type specified.
|
* @return the power level currently used by the type specified.
|
||||||
*/
|
*/
|
||||||
|
/* STATIC */
|
||||||
/* STATIC */ int NimBLEDevice::getPower(esp_ble_power_type_t powerType) {
|
int NimBLEDevice::getPower(esp_ble_power_type_t powerType) {
|
||||||
|
|
||||||
switch(esp_ble_tx_power_get(powerType)) {
|
switch(esp_ble_tx_power_get(powerType)) {
|
||||||
case ESP_PWR_LVL_N12:
|
case ESP_PWR_LVL_N12:
|
||||||
return -12;
|
return -12;
|
||||||
|
@ -373,13 +447,25 @@ void NimBLEDevice::stopAdvertising() {
|
||||||
}
|
}
|
||||||
} // getPower
|
} // getPower
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
void NimBLEDevice::setPower(int dbm) {
|
||||||
|
ble_phy_txpwr_set(dbm);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int NimBLEDevice::getPower() {
|
||||||
|
return ble_phy_txpwr_get();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get our device address.
|
* @brief Get our device address.
|
||||||
* @return A NimBLEAddress object of our public address if we have one,
|
* @return A NimBLEAddress object of our public address if we have one,
|
||||||
* if not then our current random address.
|
* if not then our current random address.
|
||||||
*/
|
*/
|
||||||
/* STATIC*/ NimBLEAddress NimBLEDevice::getAddress() {
|
/* STATIC*/
|
||||||
|
NimBLEAddress NimBLEDevice::getAddress() {
|
||||||
ble_addr_t addr = {BLE_ADDR_PUBLIC, 0};
|
ble_addr_t addr = {BLE_ADDR_PUBLIC, 0};
|
||||||
|
|
||||||
if(BLE_HS_ENOADDR == ble_hs_id_copy_addr(BLE_ADDR_PUBLIC, addr.val, NULL)) {
|
if(BLE_HS_ENOADDR == ble_hs_id_copy_addr(BLE_ADDR_PUBLIC, addr.val, NULL)) {
|
||||||
|
@ -396,7 +482,8 @@ void NimBLEDevice::stopAdvertising() {
|
||||||
* @brief Return a string representation of the address of this device.
|
* @brief Return a string representation of the address of this device.
|
||||||
* @return A string representation of this device address.
|
* @return A string representation of this device address.
|
||||||
*/
|
*/
|
||||||
/* STATIC */ std::string NimBLEDevice::toString() {
|
/* STATIC */
|
||||||
|
std::string NimBLEDevice::toString() {
|
||||||
return getAddress().toString();
|
return getAddress().toString();
|
||||||
} // toString
|
} // toString
|
||||||
|
|
||||||
|
@ -406,7 +493,8 @@ void NimBLEDevice::stopAdvertising() {
|
||||||
* @param [in] mtu Value to set local mtu:
|
* @param [in] mtu Value to set local mtu:
|
||||||
* * This should be larger than 23 and lower or equal to BLE_ATT_MTU_MAX = 527.
|
* * This should be larger than 23 and lower or equal to BLE_ATT_MTU_MAX = 527.
|
||||||
*/
|
*/
|
||||||
/* STATIC */int NimBLEDevice::setMTU(uint16_t mtu) {
|
/* STATIC */
|
||||||
|
int NimBLEDevice::setMTU(uint16_t mtu) {
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> setLocalMTU: %d", mtu);
|
NIMBLE_LOGD(LOG_TAG, ">> setLocalMTU: %d", mtu);
|
||||||
|
|
||||||
int rc = ble_att_set_preferred_mtu(mtu);
|
int rc = ble_att_set_preferred_mtu(mtu);
|
||||||
|
@ -424,11 +512,13 @@ void NimBLEDevice::stopAdvertising() {
|
||||||
* @brief Get local MTU value set.
|
* @brief Get local MTU value set.
|
||||||
* @return The current preferred MTU setting.
|
* @return The current preferred MTU setting.
|
||||||
*/
|
*/
|
||||||
/* STATIC */uint16_t NimBLEDevice::getMTU() {
|
/* STATIC */
|
||||||
|
uint16_t NimBLEDevice::getMTU() {
|
||||||
return ble_att_preferred_mtu();
|
return ble_att_preferred_mtu();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef ESP_PLATFORM
|
||||||
/**
|
/**
|
||||||
* @brief Set the duplicate filter cache size for filtering scanned devices.
|
* @brief Set the duplicate filter cache size for filtering scanned devices.
|
||||||
* @param [in] cacheSize The number of advertisements filtered before the cache is reset.\n
|
* @param [in] cacheSize The number of advertisements filtered before the cache is reset.\n
|
||||||
|
@ -474,6 +564,7 @@ void NimBLEDevice::setScanFilterMode(uint8_t mode) {
|
||||||
|
|
||||||
m_scanFilterMode = mode;
|
m_scanFilterMode = mode;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL) || defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
#if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL) || defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||||
/**
|
/**
|
||||||
|
@ -576,6 +667,7 @@ NimBLEAddress NimBLEDevice::getBondedAddress(int index) {
|
||||||
* @param [in] address The address to check for in the whitelist.
|
* @param [in] address The address to check for in the whitelist.
|
||||||
* @returns true if the address is in the whitelist.
|
* @returns true if the address is in the whitelist.
|
||||||
*/
|
*/
|
||||||
|
/*STATIC*/
|
||||||
bool NimBLEDevice::onWhiteList(const NimBLEAddress & address) {
|
bool NimBLEDevice::onWhiteList(const NimBLEAddress & address) {
|
||||||
for (auto &it : m_whiteList) {
|
for (auto &it : m_whiteList) {
|
||||||
if (it == address) {
|
if (it == address) {
|
||||||
|
@ -592,6 +684,7 @@ bool NimBLEDevice::onWhiteList(const NimBLEAddress & address) {
|
||||||
* @param [in] address The address to add to the whitelist.
|
* @param [in] address The address to add to the whitelist.
|
||||||
* @returns true if successful.
|
* @returns true if successful.
|
||||||
*/
|
*/
|
||||||
|
/*STATIC*/
|
||||||
bool NimBLEDevice::whiteListAdd(const NimBLEAddress & address) {
|
bool NimBLEDevice::whiteListAdd(const NimBLEAddress & address) {
|
||||||
if (NimBLEDevice::onWhiteList(address)) {
|
if (NimBLEDevice::onWhiteList(address)) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -623,6 +716,7 @@ bool NimBLEDevice::whiteListAdd(const NimBLEAddress & address) {
|
||||||
* @param [in] address The address to remove from the whitelist.
|
* @param [in] address The address to remove from the whitelist.
|
||||||
* @returns true if successful.
|
* @returns true if successful.
|
||||||
*/
|
*/
|
||||||
|
/*STATIC*/
|
||||||
bool NimBLEDevice::whiteListRemove(const NimBLEAddress & address) {
|
bool NimBLEDevice::whiteListRemove(const NimBLEAddress & address) {
|
||||||
if (!NimBLEDevice::onWhiteList(address)) {
|
if (!NimBLEDevice::onWhiteList(address)) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -662,6 +756,7 @@ bool NimBLEDevice::whiteListRemove(const NimBLEAddress & address) {
|
||||||
* @brief Gets the count of addresses in the whitelist.
|
* @brief Gets the count of addresses in the whitelist.
|
||||||
* @returns The number of addresses in the whitelist.
|
* @returns The number of addresses in the whitelist.
|
||||||
*/
|
*/
|
||||||
|
/*STATIC*/
|
||||||
size_t NimBLEDevice::getWhiteListCount() {
|
size_t NimBLEDevice::getWhiteListCount() {
|
||||||
return m_whiteList.size();
|
return m_whiteList.size();
|
||||||
}
|
}
|
||||||
|
@ -672,6 +767,7 @@ size_t NimBLEDevice::getWhiteListCount() {
|
||||||
* @param [in] index The vector index to retrieve the address from.
|
* @param [in] index The vector index to retrieve the address from.
|
||||||
* @returns the NimBLEAddress at the whitelist index or nullptr if not found.
|
* @returns the NimBLEAddress at the whitelist index or nullptr if not found.
|
||||||
*/
|
*/
|
||||||
|
/*STATIC*/
|
||||||
NimBLEAddress NimBLEDevice::getWhiteListAddress(size_t index) {
|
NimBLEAddress NimBLEDevice::getWhiteListAddress(size_t index) {
|
||||||
if (index > m_whiteList.size()) {
|
if (index > m_whiteList.size()) {
|
||||||
NIMBLE_LOGE(LOG_TAG, "Invalid index; %u", index);
|
NIMBLE_LOGE(LOG_TAG, "Invalid index; %u", index);
|
||||||
|
@ -685,7 +781,8 @@ NimBLEAddress NimBLEDevice::getWhiteListAddress(size_t index) {
|
||||||
* @brief Host reset, we pass the message so we don't make calls until resynced.
|
* @brief Host reset, we pass the message so we don't make calls until resynced.
|
||||||
* @param [in] reason The reason code for the reset.
|
* @param [in] reason The reason code for the reset.
|
||||||
*/
|
*/
|
||||||
/* STATIC */ void NimBLEDevice::onReset(int reason)
|
/* STATIC */
|
||||||
|
void NimBLEDevice::onReset(int reason)
|
||||||
{
|
{
|
||||||
if(!m_synced) {
|
if(!m_synced) {
|
||||||
return;
|
return;
|
||||||
|
@ -709,7 +806,8 @@ NimBLEAddress NimBLEDevice::getWhiteListAddress(size_t index) {
|
||||||
/**
|
/**
|
||||||
* @brief Host resynced with controller, all clear to make calls to the stack.
|
* @brief Host resynced with controller, all clear to make calls to the stack.
|
||||||
*/
|
*/
|
||||||
/* STATIC */ void NimBLEDevice::onSync(void)
|
/* STATIC */
|
||||||
|
void NimBLEDevice::onSync(void)
|
||||||
{
|
{
|
||||||
NIMBLE_LOGI(LOG_TAG, "NimBle host synced.");
|
NIMBLE_LOGI(LOG_TAG, "NimBle host synced.");
|
||||||
// This check is needed due to potentially being called multiple times in succession
|
// This check is needed due to potentially being called multiple times in succession
|
||||||
|
@ -722,6 +820,14 @@ NimBLEAddress NimBLEDevice::getWhiteListAddress(size_t index) {
|
||||||
int rc = ble_hs_util_ensure_addr(0);
|
int rc = ble_hs_util_ensure_addr(0);
|
||||||
assert(rc == 0);
|
assert(rc == 0);
|
||||||
|
|
||||||
|
#ifndef ESP_PLATFORM
|
||||||
|
rc = ble_hs_id_infer_auto(m_own_addr_type, &m_own_addr_type);
|
||||||
|
if (rc != 0) {
|
||||||
|
NIMBLE_LOGE(LOG_TAG, "error determining address type; rc=%d", rc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Yield for houskeeping before returning to operations.
|
// Yield for houskeeping before returning to operations.
|
||||||
// Occasionally triggers exception without.
|
// Occasionally triggers exception without.
|
||||||
taskYIELD();
|
taskYIELD();
|
||||||
|
@ -747,9 +853,11 @@ NimBLEAddress NimBLEDevice::getWhiteListAddress(size_t index) {
|
||||||
/**
|
/**
|
||||||
* @brief The main host task.
|
* @brief The main host task.
|
||||||
*/
|
*/
|
||||||
/* STATIC */ void NimBLEDevice::host_task(void *param)
|
/* STATIC */
|
||||||
|
void NimBLEDevice::host_task(void *param)
|
||||||
{
|
{
|
||||||
NIMBLE_LOGI(LOG_TAG, "BLE Host Task Started");
|
NIMBLE_LOGI(LOG_TAG, "BLE Host Task Started");
|
||||||
|
|
||||||
/* This function will return only when nimble_port_stop() is executed */
|
/* This function will return only when nimble_port_stop() is executed */
|
||||||
nimble_port_run();
|
nimble_port_run();
|
||||||
|
|
||||||
|
@ -761,9 +869,11 @@ NimBLEAddress NimBLEDevice::getWhiteListAddress(size_t index) {
|
||||||
* @brief Initialize the %BLE environment.
|
* @brief Initialize the %BLE environment.
|
||||||
* @param [in] deviceName The device name of the device.
|
* @param [in] deviceName The device name of the device.
|
||||||
*/
|
*/
|
||||||
/* STATIC */ void NimBLEDevice::init(const std::string &deviceName) {
|
/* STATIC */
|
||||||
|
void NimBLEDevice::init(const std::string &deviceName) {
|
||||||
if(!initialized){
|
if(!initialized){
|
||||||
int rc=0;
|
int rc=0;
|
||||||
|
#ifdef ESP_PLATFORM
|
||||||
esp_err_t errRc = ESP_OK;
|
esp_err_t errRc = ESP_OK;
|
||||||
|
|
||||||
#ifdef CONFIG_ENABLE_ARDUINO_DEPENDS
|
#ifdef CONFIG_ENABLE_ARDUINO_DEPENDS
|
||||||
|
@ -783,7 +893,7 @@ NimBLEAddress NimBLEDevice::getWhiteListAddress(size_t index) {
|
||||||
esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT);
|
esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT);
|
||||||
|
|
||||||
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
||||||
#ifdef CONFIG_IDF_TARGET_ESP32C3
|
#if defined (CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||||
bt_cfg.bluetooth_mode = ESP_BT_MODE_BLE;
|
bt_cfg.bluetooth_mode = ESP_BT_MODE_BLE;
|
||||||
#else
|
#else
|
||||||
bt_cfg.mode = ESP_BT_MODE_BLE;
|
bt_cfg.mode = ESP_BT_MODE_BLE;
|
||||||
|
@ -795,6 +905,7 @@ NimBLEAddress NimBLEDevice::getWhiteListAddress(size_t index) {
|
||||||
ESP_ERROR_CHECK(esp_bt_controller_init(&bt_cfg));
|
ESP_ERROR_CHECK(esp_bt_controller_init(&bt_cfg));
|
||||||
ESP_ERROR_CHECK(esp_bt_controller_enable(ESP_BT_MODE_BLE));
|
ESP_ERROR_CHECK(esp_bt_controller_enable(ESP_BT_MODE_BLE));
|
||||||
ESP_ERROR_CHECK(esp_nimble_hci_init());
|
ESP_ERROR_CHECK(esp_nimble_hci_init());
|
||||||
|
#endif
|
||||||
nimble_port_init();
|
nimble_port_init();
|
||||||
|
|
||||||
// Setup callbacks for host events
|
// Setup callbacks for host events
|
||||||
|
@ -819,9 +930,10 @@ NimBLEAddress NimBLEDevice::getWhiteListAddress(size_t index) {
|
||||||
|
|
||||||
nimble_port_freertos_init(NimBLEDevice::host_task);
|
nimble_port_freertos_init(NimBLEDevice::host_task);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for host and controller to sync before returning and accepting new tasks
|
// Wait for host and controller to sync before returning and accepting new tasks
|
||||||
while(!m_synced){
|
while(!m_synced){
|
||||||
vTaskDelay(1 / portTICK_PERIOD_MS);
|
taskYIELD();
|
||||||
}
|
}
|
||||||
|
|
||||||
initialized = true; // Set the initialization flag to ensure we are only initialized once.
|
initialized = true; // Set the initialization flag to ensure we are only initialized once.
|
||||||
|
@ -833,16 +945,17 @@ NimBLEAddress NimBLEDevice::getWhiteListAddress(size_t index) {
|
||||||
* @param [in] clearAll If true, deletes all server/advertising/scan/client objects after deinitializing.
|
* @param [in] clearAll If true, deletes all server/advertising/scan/client objects after deinitializing.
|
||||||
* @note If clearAll is true when called, any references to the created objects become invalid.
|
* @note If clearAll is true when called, any references to the created objects become invalid.
|
||||||
*/
|
*/
|
||||||
/* STATIC */ void NimBLEDevice::deinit(bool clearAll) {
|
/* STATIC */
|
||||||
|
void NimBLEDevice::deinit(bool clearAll) {
|
||||||
int ret = nimble_port_stop();
|
int ret = nimble_port_stop();
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
nimble_port_deinit();
|
nimble_port_deinit();
|
||||||
|
#ifdef ESP_PLATFORM
|
||||||
ret = esp_nimble_hci_and_controller_deinit();
|
ret = esp_nimble_hci_and_controller_deinit();
|
||||||
if (ret != ESP_OK) {
|
if (ret != ESP_OK) {
|
||||||
NIMBLE_LOGE(LOG_TAG, "esp_nimble_hci_and_controller_deinit() failed with error: %d", ret);
|
NIMBLE_LOGE(LOG_TAG, "esp_nimble_hci_and_controller_deinit() failed with error: %d", ret);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
initialized = false;
|
initialized = false;
|
||||||
m_synced = false;
|
m_synced = false;
|
||||||
|
|
||||||
|
@ -889,6 +1002,7 @@ NimBLEAddress NimBLEDevice::getWhiteListAddress(size_t index) {
|
||||||
* @brief Check if the initialization is complete.
|
* @brief Check if the initialization is complete.
|
||||||
* @return true if initialized.
|
* @return true if initialized.
|
||||||
*/
|
*/
|
||||||
|
/*STATIC*/
|
||||||
bool NimBLEDevice::getInitialized() {
|
bool NimBLEDevice::getInitialized() {
|
||||||
return initialized;
|
return initialized;
|
||||||
} // getInitialized
|
} // getInitialized
|
||||||
|
@ -900,7 +1014,8 @@ bool NimBLEDevice::getInitialized() {
|
||||||
* @param mitm If true we are capable of man in the middle protection, false if not.
|
* @param mitm If true we are capable of man in the middle protection, false if not.
|
||||||
* @param sc If true we will perform secure connection pairing, false we will use legacy pairing.
|
* @param sc If true we will perform secure connection pairing, false we will use legacy pairing.
|
||||||
*/
|
*/
|
||||||
/*STATIC*/ void NimBLEDevice::setSecurityAuth(bool bonding, bool mitm, bool sc) {
|
/*STATIC*/
|
||||||
|
void NimBLEDevice::setSecurityAuth(bool bonding, bool mitm, bool sc) {
|
||||||
NIMBLE_LOGD(LOG_TAG, "Setting bonding: %d, mitm: %d, sc: %d",bonding,mitm,sc);
|
NIMBLE_LOGD(LOG_TAG, "Setting bonding: %d, mitm: %d, sc: %d",bonding,mitm,sc);
|
||||||
ble_hs_cfg.sm_bonding = bonding;
|
ble_hs_cfg.sm_bonding = bonding;
|
||||||
ble_hs_cfg.sm_mitm = mitm;
|
ble_hs_cfg.sm_mitm = mitm;
|
||||||
|
@ -917,7 +1032,8 @@ bool NimBLEDevice::getInitialized() {
|
||||||
* * 0x08 BLE_SM_PAIR_AUTHREQ_SC
|
* * 0x08 BLE_SM_PAIR_AUTHREQ_SC
|
||||||
* * 0x10 BLE_SM_PAIR_AUTHREQ_KEYPRESS - not yet supported.
|
* * 0x10 BLE_SM_PAIR_AUTHREQ_KEYPRESS - not yet supported.
|
||||||
*/
|
*/
|
||||||
/*STATIC*/void NimBLEDevice::setSecurityAuth(uint8_t auth_req) {
|
/*STATIC*/
|
||||||
|
void NimBLEDevice::setSecurityAuth(uint8_t auth_req) {
|
||||||
NimBLEDevice::setSecurityAuth((auth_req & BLE_SM_PAIR_AUTHREQ_BOND)>0,
|
NimBLEDevice::setSecurityAuth((auth_req & BLE_SM_PAIR_AUTHREQ_BOND)>0,
|
||||||
(auth_req & BLE_SM_PAIR_AUTHREQ_MITM)>0,
|
(auth_req & BLE_SM_PAIR_AUTHREQ_MITM)>0,
|
||||||
(auth_req & BLE_SM_PAIR_AUTHREQ_SC)>0);
|
(auth_req & BLE_SM_PAIR_AUTHREQ_SC)>0);
|
||||||
|
@ -933,7 +1049,8 @@ bool NimBLEDevice::getInitialized() {
|
||||||
* * 0x03 BLE_HS_IO_NO_INPUT_OUTPUT NoInputNoOutput IO capability
|
* * 0x03 BLE_HS_IO_NO_INPUT_OUTPUT NoInputNoOutput IO capability
|
||||||
* * 0x04 BLE_HS_IO_KEYBOARD_DISPLAY KeyboardDisplay Only IO capability
|
* * 0x04 BLE_HS_IO_KEYBOARD_DISPLAY KeyboardDisplay Only IO capability
|
||||||
*/
|
*/
|
||||||
/*STATIC*/ void NimBLEDevice::setSecurityIOCap(uint8_t iocap) {
|
/*STATIC*/
|
||||||
|
void NimBLEDevice::setSecurityIOCap(uint8_t iocap) {
|
||||||
ble_hs_cfg.sm_io_cap = iocap;
|
ble_hs_cfg.sm_io_cap = iocap;
|
||||||
} // setSecurityIOCap
|
} // setSecurityIOCap
|
||||||
|
|
||||||
|
@ -947,7 +1064,8 @@ bool NimBLEDevice::getInitialized() {
|
||||||
* * 0x04: BLE_SM_PAIR_KEY_DIST_SIGN
|
* * 0x04: BLE_SM_PAIR_KEY_DIST_SIGN
|
||||||
* * 0x08: BLE_SM_PAIR_KEY_DIST_LINK
|
* * 0x08: BLE_SM_PAIR_KEY_DIST_LINK
|
||||||
*/
|
*/
|
||||||
/*STATIC*/void NimBLEDevice::setSecurityInitKey(uint8_t init_key) {
|
/*STATIC*/
|
||||||
|
void NimBLEDevice::setSecurityInitKey(uint8_t init_key) {
|
||||||
ble_hs_cfg.sm_our_key_dist = init_key;
|
ble_hs_cfg.sm_our_key_dist = init_key;
|
||||||
} // setsSecurityInitKey
|
} // setsSecurityInitKey
|
||||||
|
|
||||||
|
@ -961,7 +1079,8 @@ bool NimBLEDevice::getInitialized() {
|
||||||
* * 0x04: BLE_SM_PAIR_KEY_DIST_SIGN
|
* * 0x04: BLE_SM_PAIR_KEY_DIST_SIGN
|
||||||
* * 0x08: BLE_SM_PAIR_KEY_DIST_LINK
|
* * 0x08: BLE_SM_PAIR_KEY_DIST_LINK
|
||||||
*/
|
*/
|
||||||
/*STATIC*/void NimBLEDevice::setSecurityRespKey(uint8_t resp_key) {
|
/*STATIC*/
|
||||||
|
void NimBLEDevice::setSecurityRespKey(uint8_t resp_key) {
|
||||||
ble_hs_cfg.sm_their_key_dist = resp_key;
|
ble_hs_cfg.sm_their_key_dist = resp_key;
|
||||||
} // setsSecurityRespKey
|
} // setsSecurityRespKey
|
||||||
|
|
||||||
|
@ -970,7 +1089,8 @@ bool NimBLEDevice::getInitialized() {
|
||||||
* @brief Set the passkey the server will ask for when pairing.
|
* @brief Set the passkey the server will ask for when pairing.
|
||||||
* @param [in] pin The passkey to use.
|
* @param [in] pin The passkey to use.
|
||||||
*/
|
*/
|
||||||
/*STATIC*/void NimBLEDevice::setSecurityPasskey(uint32_t pin) {
|
/*STATIC*/
|
||||||
|
void NimBLEDevice::setSecurityPasskey(uint32_t pin) {
|
||||||
m_passkey = pin;
|
m_passkey = pin;
|
||||||
} // setSecurityPasskey
|
} // setSecurityPasskey
|
||||||
|
|
||||||
|
@ -979,7 +1099,8 @@ bool NimBLEDevice::getInitialized() {
|
||||||
* @brief Get the current passkey used for pairing.
|
* @brief Get the current passkey used for pairing.
|
||||||
* @return The current passkey.
|
* @return The current passkey.
|
||||||
*/
|
*/
|
||||||
/*STATIC*/uint32_t NimBLEDevice::getSecurityPasskey() {
|
/*STATIC*/
|
||||||
|
uint32_t NimBLEDevice::getSecurityPasskey() {
|
||||||
return m_passkey;
|
return m_passkey;
|
||||||
} // getSecurityPasskey
|
} // getSecurityPasskey
|
||||||
|
|
||||||
|
@ -989,11 +1110,13 @@ bool NimBLEDevice::getInitialized() {
|
||||||
* @param [in] callbacks Pointer to NimBLESecurityCallbacks class
|
* @param [in] callbacks Pointer to NimBLESecurityCallbacks class
|
||||||
* @deprecated For backward compatibility, New code should use client/server callback methods.
|
* @deprecated For backward compatibility, New code should use client/server callback methods.
|
||||||
*/
|
*/
|
||||||
|
/*STATIC*/
|
||||||
void NimBLEDevice::setSecurityCallbacks(NimBLESecurityCallbacks* callbacks) {
|
void NimBLEDevice::setSecurityCallbacks(NimBLESecurityCallbacks* callbacks) {
|
||||||
NimBLEDevice::m_securityCallbacks = callbacks;
|
NimBLEDevice::m_securityCallbacks = callbacks;
|
||||||
} // setSecurityCallbacks
|
} // setSecurityCallbacks
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef ESP_PLATFORM
|
||||||
/**
|
/**
|
||||||
* @brief Set the own address type.
|
* @brief Set the own address type.
|
||||||
* @param [in] own_addr_type Own Bluetooth Device address type.\n
|
* @param [in] own_addr_type Own Bluetooth Device address type.\n
|
||||||
|
@ -1004,6 +1127,7 @@ void NimBLEDevice::setSecurityCallbacks(NimBLESecurityCallbacks* callbacks) {
|
||||||
* * 0x03: BLE_OWN_ADDR_RPA_RANDOM_DEFAULT
|
* * 0x03: BLE_OWN_ADDR_RPA_RANDOM_DEFAULT
|
||||||
* @param [in] useNRPA If true, and address type is random, uses a non-resolvable random address.
|
* @param [in] useNRPA If true, and address type is random, uses a non-resolvable random address.
|
||||||
*/
|
*/
|
||||||
|
/*STATIC*/
|
||||||
void NimBLEDevice::setOwnAddrType(uint8_t own_addr_type, bool useNRPA) {
|
void NimBLEDevice::setOwnAddrType(uint8_t own_addr_type, bool useNRPA) {
|
||||||
m_own_addr_type = own_addr_type;
|
m_own_addr_type = own_addr_type;
|
||||||
switch (own_addr_type) {
|
switch (own_addr_type) {
|
||||||
|
@ -1027,18 +1151,15 @@ void NimBLEDevice::setOwnAddrType(uint8_t own_addr_type, bool useNRPA) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} // setOwnAddrType
|
} // setOwnAddrType
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Start the connection securing and authorization for this connection.
|
* @brief Start the connection securing and authorization for this connection.
|
||||||
* @param conn_id The connection id of the peer device.
|
* @param conn_id The connection id of the peer device.
|
||||||
* @returns NimBLE stack return code, 0 = success.
|
* @returns NimBLE stack return code, 0 = success.
|
||||||
*/
|
*/
|
||||||
/* STATIC */int NimBLEDevice::startSecurity(uint16_t conn_id) {
|
/* STATIC */
|
||||||
/* if(m_securityCallbacks != nullptr) {
|
int NimBLEDevice::startSecurity(uint16_t conn_id) {
|
||||||
m_securityCallbacks->onSecurityRequest();
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
int rc = ble_gap_security_initiate(conn_id);
|
int rc = ble_gap_security_initiate(conn_id);
|
||||||
if(rc != 0){
|
if(rc != 0){
|
||||||
NIMBLE_LOGE(LOG_TAG, "ble_gap_security_initiate: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
|
NIMBLE_LOGE(LOG_TAG, "ble_gap_security_initiate: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
|
||||||
|
@ -1053,7 +1174,8 @@ void NimBLEDevice::setOwnAddrType(uint8_t own_addr_type, bool useNRPA) {
|
||||||
* @param [in] address The address to look for.
|
* @param [in] address The address to look for.
|
||||||
* @return True if ignoring.
|
* @return True if ignoring.
|
||||||
*/
|
*/
|
||||||
/*STATIC*/ bool NimBLEDevice::isIgnored(const NimBLEAddress &address) {
|
/*STATIC*/
|
||||||
|
bool NimBLEDevice::isIgnored(const NimBLEAddress &address) {
|
||||||
for(auto &it : m_ignoreList) {
|
for(auto &it : m_ignoreList) {
|
||||||
if(it.equals(address)){
|
if(it.equals(address)){
|
||||||
return true;
|
return true;
|
||||||
|
@ -1068,7 +1190,8 @@ void NimBLEDevice::setOwnAddrType(uint8_t own_addr_type, bool useNRPA) {
|
||||||
* @brief Add a device to the ignore list.
|
* @brief Add a device to the ignore list.
|
||||||
* @param [in] address The address of the device we want to ignore.
|
* @param [in] address The address of the device we want to ignore.
|
||||||
*/
|
*/
|
||||||
/*STATIC*/ void NimBLEDevice::addIgnored(const NimBLEAddress &address) {
|
/*STATIC*/
|
||||||
|
void NimBLEDevice::addIgnored(const NimBLEAddress &address) {
|
||||||
m_ignoreList.push_back(address);
|
m_ignoreList.push_back(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1077,7 +1200,8 @@ void NimBLEDevice::setOwnAddrType(uint8_t own_addr_type, bool useNRPA) {
|
||||||
* @brief Remove a device from the ignore list.
|
* @brief Remove a device from the ignore list.
|
||||||
* @param [in] address The address of the device we want to remove from the list.
|
* @param [in] address The address of the device we want to remove from the list.
|
||||||
*/
|
*/
|
||||||
/*STATIC*/void NimBLEDevice::removeIgnored(const NimBLEAddress &address) {
|
/*STATIC*/
|
||||||
|
void NimBLEDevice::removeIgnored(const NimBLEAddress &address) {
|
||||||
for(auto it = m_ignoreList.begin(); it != m_ignoreList.end(); ++it) {
|
for(auto it = m_ignoreList.begin(); it != m_ignoreList.end(); ++it) {
|
||||||
if((*it).equals(address)){
|
if((*it).equals(address)){
|
||||||
m_ignoreList.erase(it);
|
m_ignoreList.erase(it);
|
||||||
|
@ -1091,6 +1215,7 @@ void NimBLEDevice::setOwnAddrType(uint8_t own_addr_type, bool useNRPA) {
|
||||||
* @brief Set a custom callback for gap events.
|
* @brief Set a custom callback for gap events.
|
||||||
* @param [in] handler The function to call when gap events occur.
|
* @param [in] handler The function to call when gap events occur.
|
||||||
*/
|
*/
|
||||||
|
/*STATIC*/
|
||||||
void NimBLEDevice::setCustomGapHandler(gap_event_handler handler) {
|
void NimBLEDevice::setCustomGapHandler(gap_event_handler handler) {
|
||||||
m_customGapHandler = handler;
|
m_customGapHandler = handler;
|
||||||
int rc = ble_gap_event_listener_register(&m_listener, m_customGapHandler, NULL);
|
int rc = ble_gap_event_listener_register(&m_listener, m_customGapHandler, NULL);
|
||||||
|
@ -1102,5 +1227,4 @@ void NimBLEDevice::setCustomGapHandler(gap_event_handler handler) {
|
||||||
}
|
}
|
||||||
} // setCustomGapHandler
|
} // setCustomGapHandler
|
||||||
|
|
||||||
|
|
||||||
#endif // CONFIG_BT_ENABLED
|
#endif // CONFIG_BT_ENABLED
|
||||||
|
|
|
@ -14,18 +14,21 @@
|
||||||
|
|
||||||
#ifndef MAIN_NIMBLEDEVICE_H_
|
#ifndef MAIN_NIMBLEDEVICE_H_
|
||||||
#define MAIN_NIMBLEDEVICE_H_
|
#define MAIN_NIMBLEDEVICE_H_
|
||||||
#include "sdkconfig.h"
|
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
|
||||||
|
|
||||||
#include "nimconfig.h"
|
#include "nimconfig.h"
|
||||||
|
#if defined(CONFIG_BT_ENABLED)
|
||||||
|
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||||
#include "NimBLEScan.h"
|
#include "NimBLEScan.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||||
|
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||||
|
# include "NimBLEExtAdvertising.h"
|
||||||
|
# else
|
||||||
# include "NimBLEAdvertising.h"
|
# include "NimBLEAdvertising.h"
|
||||||
# endif
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
#if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||||
#include "NimBLEClient.h"
|
#include "NimBLEClient.h"
|
||||||
|
@ -41,7 +44,9 @@
|
||||||
#include "NimBLESecurity.h"
|
#include "NimBLESecurity.h"
|
||||||
#include "NimBLEAddress.h"
|
#include "NimBLEAddress.h"
|
||||||
|
|
||||||
|
#ifdef ESP_PLATFORM
|
||||||
# include "esp_bt.h"
|
# include "esp_bt.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -115,8 +120,17 @@ public:
|
||||||
static NimBLEMeshNode* createMeshNode(NimBLEUUID uuid, uint8_t type);
|
static NimBLEMeshNode* createMeshNode(NimBLEUUID uuid, uint8_t type);
|
||||||
static NimBLEMeshNode* getMeshNode();
|
static NimBLEMeshNode* getMeshNode();
|
||||||
|
|
||||||
|
#ifdef ESP_PLATFORM
|
||||||
static void setPower(esp_power_level_t powerLevel, esp_ble_power_type_t powerType=ESP_BLE_PWR_TYPE_DEFAULT);
|
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 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 setCustomGapHandler(gap_event_handler handler);
|
||||||
static void setSecurityAuth(bool bonding, bool mitm, bool sc);
|
static void setSecurityAuth(bool bonding, bool mitm, bool sc);
|
||||||
static void setSecurityAuth(uint8_t auth_req);
|
static void setSecurityAuth(uint8_t auth_req);
|
||||||
|
@ -126,20 +140,26 @@ public:
|
||||||
static void setSecurityPasskey(uint32_t pin);
|
static void setSecurityPasskey(uint32_t pin);
|
||||||
static uint32_t getSecurityPasskey();
|
static uint32_t getSecurityPasskey();
|
||||||
static void setSecurityCallbacks(NimBLESecurityCallbacks* pCallbacks);
|
static void setSecurityCallbacks(NimBLESecurityCallbacks* pCallbacks);
|
||||||
static void setOwnAddrType(uint8_t own_addr_type, bool useNRPA=false);
|
|
||||||
static int startSecurity(uint16_t conn_id);
|
static int startSecurity(uint16_t conn_id);
|
||||||
static int setMTU(uint16_t mtu);
|
static int setMTU(uint16_t mtu);
|
||||||
static uint16_t getMTU();
|
static uint16_t getMTU();
|
||||||
static bool isIgnored(const NimBLEAddress &address);
|
static bool isIgnored(const NimBLEAddress &address);
|
||||||
static void addIgnored(const NimBLEAddress &address);
|
static void addIgnored(const NimBLEAddress &address);
|
||||||
static void removeIgnored(const NimBLEAddress &address);
|
static void removeIgnored(const NimBLEAddress &address);
|
||||||
static void setScanDuplicateCacheSize(uint16_t cacheSize);
|
|
||||||
static void setScanFilterMode(uint8_t type);
|
|
||||||
|
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||||
|
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||||
|
static NimBLEExtAdvertising* getAdvertising();
|
||||||
|
static bool startAdvertising(uint8_t inst_id,
|
||||||
|
int duration = 0,
|
||||||
|
int max_events = 0);
|
||||||
|
static bool stopAdvertising(uint8_t inst_id);
|
||||||
|
static bool stopAdvertising();
|
||||||
|
# else
|
||||||
static NimBLEAdvertising* getAdvertising();
|
static NimBLEAdvertising* getAdvertising();
|
||||||
static void startAdvertising();
|
static bool startAdvertising();
|
||||||
static void stopAdvertising();
|
static bool stopAdvertising();
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||||
|
@ -176,6 +196,10 @@ private:
|
||||||
|
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||||
friend class NimBLEAdvertising;
|
friend class NimBLEAdvertising;
|
||||||
|
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||||
|
friend class NimBLEExtAdvertising;
|
||||||
|
friend class NimBLEExtAdvertisement;
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void onReset(int reason);
|
static void onReset(int reason);
|
||||||
|
@ -192,8 +216,12 @@ private:
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||||
|
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||||
|
static NimBLEExtAdvertising* m_bleAdvertising;
|
||||||
|
# else
|
||||||
static NimBLEAdvertising* m_bleAdvertising;
|
static NimBLEAdvertising* m_bleAdvertising;
|
||||||
# endif
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||||
static std::list <NimBLEClient*> m_cList;
|
static std::list <NimBLEClient*> m_cList;
|
||||||
|
@ -204,8 +232,10 @@ private:
|
||||||
static ble_gap_event_listener m_listener;
|
static ble_gap_event_listener m_listener;
|
||||||
static gap_event_handler m_customGapHandler;
|
static gap_event_handler m_customGapHandler;
|
||||||
static uint8_t m_own_addr_type;
|
static uint8_t m_own_addr_type;
|
||||||
|
#ifdef ESP_PLATFORM
|
||||||
static uint16_t m_scanDuplicateSize;
|
static uint16_t m_scanDuplicateSize;
|
||||||
static uint8_t m_scanFilterMode;
|
static uint8_t m_scanFilterMode;
|
||||||
|
#endif
|
||||||
static std::vector<NimBLEAddress> m_whiteList;
|
static std::vector<NimBLEAddress> m_whiteList;
|
||||||
static NimBLEMeshNode* m_pMeshNode;
|
static NimBLEMeshNode* m_pMeshNode;
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,12 +11,14 @@
|
||||||
* Created on: Mar 12, 2018
|
* Created on: Mar 12, 2018
|
||||||
* Author: pcbreflux
|
* Author: pcbreflux
|
||||||
*/
|
*/
|
||||||
#include "sdkconfig.h"
|
|
||||||
|
#include "nimconfig.h"
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
#if defined(CONFIG_BT_ENABLED)
|
||||||
|
|
||||||
#include "NimBLEEddystoneTLM.h"
|
#include "NimBLEEddystoneTLM.h"
|
||||||
#include "NimBLELog.h"
|
#include "NimBLELog.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
#define ENDIAN_CHANGE_U16(x) ((((x)&0xFF00)>>8) + (((x)&0xFF)<<8))
|
#define ENDIAN_CHANGE_U16(x) ((((x)&0xFF00)>>8) + (((x)&0xFF)<<8))
|
||||||
|
@ -124,30 +126,30 @@ std::string NimBLEEddystoneTLM::toString() {
|
||||||
out += " C\n";
|
out += " C\n";
|
||||||
|
|
||||||
out += "Adv. Count ";
|
out += "Adv. Count ";
|
||||||
snprintf(val, sizeof(val), "%d", ENDIAN_CHANGE_U32(m_eddystoneData.advCount));
|
snprintf(val, sizeof(val), "%" PRIu32, ENDIAN_CHANGE_U32(m_eddystoneData.advCount));
|
||||||
out += val;
|
out += val;
|
||||||
out += "\n";
|
out += "\n";
|
||||||
|
|
||||||
out += "Time in seconds ";
|
out += "Time in seconds ";
|
||||||
snprintf(val, sizeof(val), "%d", rawsec/10);
|
snprintf(val, sizeof(val), "%" PRIu32, rawsec/10);
|
||||||
out += val;
|
out += val;
|
||||||
out += "\n";
|
out += "\n";
|
||||||
|
|
||||||
out += "Time ";
|
out += "Time ";
|
||||||
|
|
||||||
snprintf(val, sizeof(val), "%04d", rawsec / 864000);
|
snprintf(val, sizeof(val), "%04" PRIu32, rawsec / 864000);
|
||||||
out += val;
|
out += val;
|
||||||
out += ".";
|
out += ".";
|
||||||
|
|
||||||
snprintf(val, sizeof(val), "%02d", (rawsec / 36000) % 24);
|
snprintf(val, sizeof(val), "%02" PRIu32, (rawsec / 36000) % 24);
|
||||||
out += val;
|
out += val;
|
||||||
out += ":";
|
out += ":";
|
||||||
|
|
||||||
snprintf(val, sizeof(val), "%02d", (rawsec / 600) % 60);
|
snprintf(val, sizeof(val), "%02" PRIu32, (rawsec / 600) % 60);
|
||||||
out += val;
|
out += val;
|
||||||
out += ":";
|
out += ":";
|
||||||
|
|
||||||
snprintf(val, sizeof(val), "%02d", (rawsec / 10) % 60);
|
snprintf(val, sizeof(val), "%02" PRIu32, (rawsec / 10) % 60);
|
||||||
out += val;
|
out += val;
|
||||||
out += "\n";
|
out += "\n";
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#ifndef _NimBLEEddystoneTLM_H_
|
#ifndef _NimBLEEddystoneTLM_H_
|
||||||
#define _NimBLEEddystoneTLM_H_
|
#define _NimBLEEddystoneTLM_H_
|
||||||
|
|
||||||
#include "NimBLEUUID.h"
|
#include "NimBLEUUID.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
* Created on: Mar 12, 2018
|
* Created on: Mar 12, 2018
|
||||||
* Author: pcbreflux
|
* Author: pcbreflux
|
||||||
*/
|
*/
|
||||||
#include "sdkconfig.h"
|
#include "nimconfig.h"
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
#if defined(CONFIG_BT_ENABLED)
|
||||||
|
|
||||||
#include "NimBLEEddystoneURL.h"
|
#include "NimBLEEddystoneURL.h"
|
||||||
|
|
870
src/NimBLEExtAdvertising.cpp
Normal file
870
src/NimBLEExtAdvertising.cpp
Normal file
|
@ -0,0 +1,870 @@
|
||||||
|
/*
|
||||||
|
* NimBLEExtAdvertising.cpp
|
||||||
|
*
|
||||||
|
* Created: on February 6, 2022
|
||||||
|
* Author H2zero
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "nimconfig.h"
|
||||||
|
#if defined(CONFIG_BT_ENABLED) && \
|
||||||
|
defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER) && \
|
||||||
|
CONFIG_BT_NIMBLE_EXT_ADV
|
||||||
|
|
||||||
|
#if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||||
|
#include "services/gap/ble_svc_gap.h"
|
||||||
|
#else
|
||||||
|
#include "nimble/nimble/host/services/gap/include/services/gap/ble_svc_gap.h"
|
||||||
|
#endif
|
||||||
|
#include "NimBLEExtAdvertising.h"
|
||||||
|
#include "NimBLEDevice.h"
|
||||||
|
#include "NimBLEServer.h"
|
||||||
|
#include "NimBLEUtils.h"
|
||||||
|
#include "NimBLELog.h"
|
||||||
|
|
||||||
|
static NimBLEExtAdvertisingCallbacks defaultCallbacks;
|
||||||
|
static const char* LOG_TAG = "NimBLEExtAdvertising";
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Destructor: deletes callback instances if requested.
|
||||||
|
*/
|
||||||
|
NimBLEExtAdvertising::~NimBLEExtAdvertising() {
|
||||||
|
if(m_deleteCallbacks && m_pCallbacks != &defaultCallbacks) {
|
||||||
|
delete m_pCallbacks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Register the extended advertisement data.
|
||||||
|
* @param [in] inst_id The extended advertisement instance ID to assign to this data.
|
||||||
|
* @param [in] adv The extended advertisement instance with the data to set.
|
||||||
|
* @return True if advertising started successfully.
|
||||||
|
*/
|
||||||
|
bool NimBLEExtAdvertising::setInstanceData(uint8_t inst_id, NimBLEExtAdvertisement& adv) {
|
||||||
|
adv.m_params.sid = inst_id;
|
||||||
|
|
||||||
|
// Legacy advertising as connectable requires the scannable flag also.
|
||||||
|
if (adv.m_params.legacy_pdu && adv.m_params.connectable) {
|
||||||
|
adv.m_params.scannable = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If connectable or not scannable disable the callback for scan response requests
|
||||||
|
if (adv.m_params.connectable || !adv.m_params.scannable) {
|
||||||
|
adv.m_params.scan_req_notif = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||||
|
NimBLEServer* pServer = NimBLEDevice::getServer();
|
||||||
|
if (pServer != nullptr) {
|
||||||
|
if (!pServer->m_gattsStarted) {
|
||||||
|
pServer->start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int rc = ble_gap_ext_adv_configure(inst_id,
|
||||||
|
&adv.m_params,
|
||||||
|
NULL,
|
||||||
|
(pServer != nullptr) ? NimBLEServer::handleGapEvent :
|
||||||
|
NimBLEExtAdvertising::handleGapEvent,
|
||||||
|
NULL);
|
||||||
|
#else
|
||||||
|
int rc = ble_gap_ext_adv_configure(inst_id,
|
||||||
|
&data.m_params,
|
||||||
|
NULL,
|
||||||
|
NimBLEExtAdvertising::handleGapEvent,
|
||||||
|
NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (rc != 0) {
|
||||||
|
NIMBLE_LOGE(LOG_TAG, "Advertising config error: rc = %d", rc);
|
||||||
|
} else {
|
||||||
|
os_mbuf *buf;
|
||||||
|
buf = os_msys_get_pkthdr(adv.m_payload.size(), 0);
|
||||||
|
if (!buf) {
|
||||||
|
NIMBLE_LOGE(LOG_TAG, "Data buffer allocation failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = os_mbuf_append(buf, &adv.m_payload[0], adv.m_payload.size());
|
||||||
|
if (rc != 0) {
|
||||||
|
NIMBLE_LOGE(LOG_TAG, "Unable to copy data: rc = %d", rc);
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
if (adv.m_params.scannable && !adv.m_params.legacy_pdu) {
|
||||||
|
rc = ble_gap_ext_adv_rsp_set_data(inst_id, buf);
|
||||||
|
} else {
|
||||||
|
rc = ble_gap_ext_adv_set_data(inst_id, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rc != 0) {
|
||||||
|
NIMBLE_LOGE(LOG_TAG, "Invalid advertisement data: rc = %d", rc);
|
||||||
|
} else {
|
||||||
|
if (adv.m_advAddress != NimBLEAddress("")) {
|
||||||
|
ble_addr_t addr;
|
||||||
|
memcpy(&addr.val, adv.m_advAddress.getNative(), 6);
|
||||||
|
// Custom advertising address must be random.
|
||||||
|
addr.type = BLE_OWN_ADDR_RANDOM;
|
||||||
|
rc = ble_gap_ext_adv_set_addr(inst_id, &addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rc != 0) {
|
||||||
|
NIMBLE_LOGE(LOG_TAG, "Error setting advertisement address: rc = %d", rc);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (rc == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the scan response data for a legacy advertisement.
|
||||||
|
* @param [in] inst_id The extended advertisement instance ID to assign to this data.
|
||||||
|
* @param [in] lsr A reference to a NimBLEExtAdvertisement that contains the data.
|
||||||
|
*/
|
||||||
|
bool NimBLEExtAdvertising::setScanResponseData(uint8_t inst_id, NimBLEExtAdvertisement & lsr) {
|
||||||
|
os_mbuf *buf = os_msys_get_pkthdr(lsr.m_payload.size(), 0);
|
||||||
|
if (!buf) {
|
||||||
|
NIMBLE_LOGE(LOG_TAG, "Data buffer allocation failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rc = os_mbuf_append(buf, &lsr.m_payload[0], lsr.m_payload.size());
|
||||||
|
|
||||||
|
if (rc != 0) {
|
||||||
|
NIMBLE_LOGE(LOG_TAG, "Unable to copy scan data: rc = %d", rc);
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
rc = ble_gap_ext_adv_rsp_set_data(inst_id, buf);
|
||||||
|
}
|
||||||
|
return (rc == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Start extended advertising.
|
||||||
|
* @param [in] inst_id The extended advertisement instance ID to start.
|
||||||
|
* @param [in] duration How long to advertise for in milliseconds, 0 = forever (default).
|
||||||
|
* @param [in] max_events Maximum number of advertisement events to send, 0 = no limit (default).
|
||||||
|
* @return True if advertising started successfully.
|
||||||
|
*/
|
||||||
|
bool NimBLEExtAdvertising::start(uint8_t inst_id, int duration, int max_events) {
|
||||||
|
NIMBLE_LOGD(LOG_TAG, ">> Extended Advertising start");
|
||||||
|
|
||||||
|
// If Host is not synced we cannot start advertising.
|
||||||
|
if(!NimBLEDevice::m_synced) {
|
||||||
|
NIMBLE_LOGE(LOG_TAG, "Host reset, wait for sync.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rc = ble_gap_ext_adv_start(inst_id, duration / 10, max_events);
|
||||||
|
|
||||||
|
switch (rc) {
|
||||||
|
case 0:
|
||||||
|
m_advStatus[inst_id] = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BLE_HS_EINVAL:
|
||||||
|
NIMBLE_LOGE(LOG_TAG, "Unable to advertise - Value Error");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BLE_HS_EALREADY:
|
||||||
|
NIMBLE_LOGI(LOG_TAG, "Advertisement Already active");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BLE_HS_ETIMEOUT_HCI:
|
||||||
|
case BLE_HS_EOS:
|
||||||
|
case BLE_HS_ECONTROLLER:
|
||||||
|
case BLE_HS_ENOTSYNCED:
|
||||||
|
NIMBLE_LOGE(LOG_TAG, "Unable to advertise - Host Reset");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
NIMBLE_LOGE(LOG_TAG, "Error enabling advertising; rc=%d, %s",
|
||||||
|
rc, NimBLEUtils::returnCodeToString(rc));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
NIMBLE_LOGD(LOG_TAG, "<< Extended Advertising start");
|
||||||
|
return (rc == 0 || rc == BLE_HS_EALREADY);
|
||||||
|
} // start
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stop and remove this instance data from the advertisement set.
|
||||||
|
* @param [in] inst_id The extended advertisement instance to stop advertising.
|
||||||
|
* @return True if successful.
|
||||||
|
*/
|
||||||
|
bool NimBLEExtAdvertising::removeInstance(uint8_t inst_id) {
|
||||||
|
if (stop(inst_id)) {
|
||||||
|
int rc = ble_gap_ext_adv_remove(inst_id);
|
||||||
|
if (rc != 0 && rc != BLE_HS_EALREADY) {
|
||||||
|
NIMBLE_LOGE(LOG_TAG, "ble_gap_ext_adv_remove rc = %d %s",
|
||||||
|
rc, NimBLEUtils::returnCodeToString(rc));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
} // removeInstance
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stop and remove all advertising instance data.
|
||||||
|
* @return True if successful.
|
||||||
|
*/
|
||||||
|
bool NimBLEExtAdvertising::removeAll() {
|
||||||
|
if (stop()) {
|
||||||
|
int rc = ble_gap_ext_adv_clear();
|
||||||
|
if (rc == 0 || rc == BLE_HS_EALREADY) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
NIMBLE_LOGE(LOG_TAG, "ble_gap_ext_adv_clear rc = %d %s",
|
||||||
|
rc, NimBLEUtils::returnCodeToString(rc));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
} // removeAll
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stop advertising this instance data.
|
||||||
|
* @param [in] inst_id The extended advertisement instance to stop advertising.
|
||||||
|
* @return True if successful.
|
||||||
|
*/
|
||||||
|
bool NimBLEExtAdvertising::stop(uint8_t inst_id) {
|
||||||
|
int rc = ble_gap_ext_adv_stop(inst_id);
|
||||||
|
if (rc != 0 && rc != BLE_HS_EALREADY) {
|
||||||
|
NIMBLE_LOGE(LOG_TAG, "ble_gap_ext_adv_stop rc = %d %s",
|
||||||
|
rc, NimBLEUtils::returnCodeToString(rc));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_advStatus[inst_id] = false;
|
||||||
|
return true;
|
||||||
|
} // stop
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stop all advertisements.
|
||||||
|
* @return True if successful.
|
||||||
|
*/
|
||||||
|
bool NimBLEExtAdvertising::stop() {
|
||||||
|
int rc = ble_gap_ext_adv_clear();
|
||||||
|
if (rc != 0 && rc != BLE_HS_EALREADY) {
|
||||||
|
NIMBLE_LOGE(LOG_TAG, "ble_gap_ext_adv_stop rc = %d %s",
|
||||||
|
rc, NimBLEUtils::returnCodeToString(rc));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto it : m_advStatus) {
|
||||||
|
it = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} // stop
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set a callback to call when the advertisement stops.
|
||||||
|
* @param [in] pCallbacks A pointer to a callback to be invoked when an advertisment stops.
|
||||||
|
* @param [in] deleteCallbacks if true callback class will be deleted when advertising is destructed.
|
||||||
|
*/
|
||||||
|
void NimBLEExtAdvertising::setCallbacks(NimBLEExtAdvertisingCallbacks* pCallbacks,
|
||||||
|
bool deleteCallbacks) {
|
||||||
|
if (pCallbacks != nullptr){
|
||||||
|
m_pCallbacks = pCallbacks;
|
||||||
|
m_deleteCallbacks = deleteCallbacks;
|
||||||
|
} else {
|
||||||
|
m_pCallbacks = &defaultCallbacks;
|
||||||
|
}
|
||||||
|
} // setCallbacks
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if currently advertising.
|
||||||
|
* @param [in] inst_id The instance ID of the advertised data to get the status of.
|
||||||
|
* @return True if advertising is active.
|
||||||
|
*/
|
||||||
|
bool NimBLEExtAdvertising::isActive(uint8_t inst_id) {
|
||||||
|
return m_advStatus[inst_id];
|
||||||
|
} // isAdvertising
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if any instances are currently advertising.
|
||||||
|
* @return True if any instance is active.
|
||||||
|
*/
|
||||||
|
bool NimBLEExtAdvertising::isAdvertising() {
|
||||||
|
for (auto it : m_advStatus) {
|
||||||
|
if (it) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} // isAdvertising
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Host reset seems to clear advertising data,
|
||||||
|
* we need clear the flag so it reloads it.
|
||||||
|
*/
|
||||||
|
void NimBLEExtAdvertising::onHostSync() {
|
||||||
|
NIMBLE_LOGD(LOG_TAG, "Host re-synced");
|
||||||
|
for(auto it : m_advStatus) {
|
||||||
|
it = false;
|
||||||
|
}
|
||||||
|
} // onHostSync
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handler for gap events when not using peripheral role.
|
||||||
|
* @param [in] event the event data.
|
||||||
|
* @param [in] arg pointer to the advertising instance.
|
||||||
|
*/
|
||||||
|
/*STATIC*/
|
||||||
|
int NimBLEExtAdvertising::handleGapEvent(struct ble_gap_event *event, void *arg) {
|
||||||
|
(void)arg;
|
||||||
|
NimBLEExtAdvertising* pAdv = NimBLEDevice::getAdvertising();
|
||||||
|
|
||||||
|
switch (event->type) {
|
||||||
|
case BLE_GAP_EVENT_ADV_COMPLETE: {
|
||||||
|
switch (event->adv_complete.reason) {
|
||||||
|
// Don't call the callback if host reset, we want to
|
||||||
|
// preserve the active flag until re-sync to restart advertising.
|
||||||
|
case BLE_HS_ETIMEOUT_HCI:
|
||||||
|
case BLE_HS_EOS:
|
||||||
|
case BLE_HS_ECONTROLLER:
|
||||||
|
case BLE_HS_ENOTSYNCED:
|
||||||
|
NIMBLE_LOGC(LOG_TAG, "host reset, rc = %d", event->adv_complete.reason);
|
||||||
|
NimBLEDevice::onReset(event->adv_complete.reason);
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pAdv->m_advStatus[event->adv_complete.instance] = false;
|
||||||
|
pAdv->m_pCallbacks->onStopped(pAdv, event->adv_complete.reason,
|
||||||
|
event->adv_complete.instance);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case BLE_GAP_EVENT_SCAN_REQ_RCVD: {
|
||||||
|
pAdv->m_pCallbacks->onScanRequest(pAdv, event->scan_req_rcvd.instance,
|
||||||
|
NimBLEAddress(event->scan_req_rcvd.scan_addr));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
} // handleGapEvent
|
||||||
|
|
||||||
|
|
||||||
|
/** Default callback handlers */
|
||||||
|
void NimBLEExtAdvertisingCallbacks::onStopped(NimBLEExtAdvertising *pAdv,
|
||||||
|
int reason, uint8_t inst_id) {
|
||||||
|
NIMBLE_LOGD("NimBLEExtAdvertisingCallbacks", "onStopped: Default");
|
||||||
|
} // onStopped
|
||||||
|
|
||||||
|
|
||||||
|
void NimBLEExtAdvertisingCallbacks::onScanRequest(NimBLEExtAdvertising *pAdv,
|
||||||
|
uint8_t inst_id, NimBLEAddress addr) {
|
||||||
|
NIMBLE_LOGD("NimBLEExtAdvertisingCallbacks", "onScanRequest: Default");
|
||||||
|
} // onScanRequest
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct a BLE extended advertisement.
|
||||||
|
* @param [in] priPhy The primary Phy to advertise on, can be one of:
|
||||||
|
* * BLE_HCI_LE_PHY_1M
|
||||||
|
* * BLE_HCI_LE_PHY_CODED
|
||||||
|
* @param [in] secPhy The secondary Phy to advertise on, can be one of:
|
||||||
|
* * BLE_HCI_LE_PHY_1M
|
||||||
|
* * BLE_HCI_LE_PHY_2M
|
||||||
|
* * BLE_HCI_LE_PHY_CODED
|
||||||
|
*/
|
||||||
|
NimBLEExtAdvertisement::NimBLEExtAdvertisement(uint8_t priPhy, uint8_t secPhy)
|
||||||
|
: m_advAddress("")
|
||||||
|
{
|
||||||
|
memset (&m_params, 0, sizeof(m_params));
|
||||||
|
m_params.own_addr_type = NimBLEDevice::m_own_addr_type;
|
||||||
|
m_params.primary_phy = priPhy;
|
||||||
|
m_params.secondary_phy = secPhy;
|
||||||
|
m_params.tx_power = 127;
|
||||||
|
} // NimBLEExtAdvertisement
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets wether the advertisement should use legacy (BLE 4.0, 31 bytes max) advertising.
|
||||||
|
* @param [in] val true = using legacy advertising.
|
||||||
|
*/
|
||||||
|
void NimBLEExtAdvertisement::setLegacyAdvertising(bool val) {
|
||||||
|
m_params.legacy_pdu = val;
|
||||||
|
} // setLegacyAdvertising
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets wether the advertisement has scan response data available.
|
||||||
|
* @param [in] val true = scan response is available.
|
||||||
|
*/
|
||||||
|
void NimBLEExtAdvertisement::setScannable(bool val) {
|
||||||
|
m_params.scannable = val;
|
||||||
|
} // setScannable
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the transmission power level for this advertisement.
|
||||||
|
* @param [in] dbm the transmission power to use in dbm.
|
||||||
|
* @details The allowable value range depends on device hardware. \n
|
||||||
|
* The ESP32C3 and ESP32S3 have a range of -27 to +18.
|
||||||
|
*/
|
||||||
|
void NimBLEExtAdvertisement::setTxPower(int8_t dbm) {
|
||||||
|
m_params.tx_power = dbm;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets wether this advertisement should advertise as a connectable device.
|
||||||
|
* @param [in] val True = connectable.
|
||||||
|
*/
|
||||||
|
void NimBLEExtAdvertisement::setConnectable(bool val) {
|
||||||
|
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||||
|
m_params.connectable = val;
|
||||||
|
#endif
|
||||||
|
} // setConnectable
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the address to use for this advertisement.
|
||||||
|
* @param [in] addr The address to use.
|
||||||
|
*/
|
||||||
|
void NimBLEExtAdvertisement::setAddress(const NimBLEAddress & addr) {
|
||||||
|
m_advAddress = addr;
|
||||||
|
// Must use random address type.
|
||||||
|
m_params.own_addr_type = BLE_OWN_ADDR_RANDOM;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets The primary channels to advertise on.
|
||||||
|
* @param [in] ch37 Advertise on channel 37.
|
||||||
|
* @param [in] ch38 Advertise on channel 38.
|
||||||
|
* @param [in] ch39 Advertise on channel 39.
|
||||||
|
* @details This will set a bitmask using the input parameters to allow different \n
|
||||||
|
* combinations. If all inputs are false then all 3 channels will be used.
|
||||||
|
*/
|
||||||
|
void NimBLEExtAdvertisement::setPrimaryChannels(bool ch37, bool ch38, bool ch39) {
|
||||||
|
m_params.channel_map = (ch37 | (ch38 << 1) | (ch39 << 2));
|
||||||
|
} // setPrimaryChannels
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the filtering for the scan filter.
|
||||||
|
* @param [in] scanRequestWhitelistOnly If true, only allow scan requests from those on the white list.
|
||||||
|
* @param [in] connectWhitelistOnly If true, only allow connections from those on the white list.
|
||||||
|
*/
|
||||||
|
void NimBLEExtAdvertisement::setScanFilter(bool scanRequestWhitelistOnly, bool connectWhitelistOnly) {
|
||||||
|
if (!scanRequestWhitelistOnly && !connectWhitelistOnly) {
|
||||||
|
m_params.filter_policy = BLE_HCI_ADV_FILT_NONE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (scanRequestWhitelistOnly && !connectWhitelistOnly) {
|
||||||
|
m_params.filter_policy = BLE_HCI_ADV_FILT_SCAN;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!scanRequestWhitelistOnly && connectWhitelistOnly) {
|
||||||
|
m_params.filter_policy = BLE_HCI_ADV_FILT_CONN;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (scanRequestWhitelistOnly && connectWhitelistOnly) {
|
||||||
|
m_params.filter_policy = BLE_HCI_ADV_FILT_BOTH;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} // setScanFilter
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the peer to directly advertise to.
|
||||||
|
* @param [in] addr The address of the peer to direct the advertisements.
|
||||||
|
*/
|
||||||
|
void NimBLEExtAdvertisement::setDirectedPeer(const NimBLEAddress & addr) {
|
||||||
|
ble_addr_t peerAddr;
|
||||||
|
memcpy(&peerAddr.val, addr.getNative(), 6);
|
||||||
|
peerAddr.type = addr.getType();
|
||||||
|
m_params.peer = peerAddr;
|
||||||
|
} // setDirectedPeer
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable or disable direct advertisements to the peer set with `NimBLEExtAdvertisement::setDirectedPeer`
|
||||||
|
* @param [in] val true = send directed advertisements to peer.
|
||||||
|
* @param [in] high_duty true = use fast advertising rate, default - true.
|
||||||
|
*/
|
||||||
|
void NimBLEExtAdvertisement::setDirected(bool val, bool high_duty) {
|
||||||
|
m_params.directed = val;
|
||||||
|
m_params.high_duty_directed = high_duty;
|
||||||
|
} // setDirected
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the minimum advertising interval.
|
||||||
|
* @param [in] mininterval Minimum value for advertising interval in 0.625ms units, 0 = use default.
|
||||||
|
*/
|
||||||
|
void NimBLEExtAdvertisement::setMinInterval(uint32_t mininterval) {
|
||||||
|
m_params.itvl_min = mininterval;
|
||||||
|
} // setMinInterval
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the maximum advertising interval.
|
||||||
|
* @param [in] maxinterval Maximum value for advertising interval in 0.625ms units, 0 = use default.
|
||||||
|
*/
|
||||||
|
void NimBLEExtAdvertisement::setMaxInterval(uint32_t maxinterval) {
|
||||||
|
m_params.itvl_max = maxinterval;
|
||||||
|
} // setMaxInterval
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the primary advertising PHY to use
|
||||||
|
* @param [in] phy Can be one of following constants:
|
||||||
|
* * BLE_HCI_LE_PHY_1M
|
||||||
|
* * BLE_HCI_LE_PHY_CODED
|
||||||
|
*/
|
||||||
|
void NimBLEExtAdvertisement::setPrimaryPhy(uint8_t phy) {
|
||||||
|
m_params.primary_phy = phy;
|
||||||
|
} // setPrimaryPhy
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the secondary advertising PHY to use
|
||||||
|
* @param [in] phy Can be one of following constants:
|
||||||
|
* * BLE_HCI_LE_PHY_1M
|
||||||
|
* * BLE_HCI_LE_PHY_2M
|
||||||
|
* * BLE_HCI_LE_PHY_CODED
|
||||||
|
*/
|
||||||
|
void NimBLEExtAdvertisement::setSecondaryPhy(uint8_t phy) {
|
||||||
|
m_params.secondary_phy = phy;
|
||||||
|
} // setSecondaryPhy
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets whether the advertisement should be anonymous.
|
||||||
|
* @param [in] val Set to true to enable anonymous advertising.
|
||||||
|
*
|
||||||
|
* @details Anonymous advertising omits the device's address from the advertisement.
|
||||||
|
*/
|
||||||
|
void NimBLEExtAdvertisement::setAnonymous(bool val) {
|
||||||
|
m_params.anonymous = val;
|
||||||
|
} // setAnonymous
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets whether the scan response request callback should be called.
|
||||||
|
* @param [in] enable If true the scan response request callback will be called for this advertisement.
|
||||||
|
*/
|
||||||
|
void NimBLEExtAdvertisement::enableScanRequestCallback(bool enable) {
|
||||||
|
m_params.scan_req_notif = enable;
|
||||||
|
} // enableScanRequestCallback
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clears the data stored in this instance, does not change settings.
|
||||||
|
* @details This will clear all data but preserves advertising parameter settings.
|
||||||
|
*/
|
||||||
|
void NimBLEExtAdvertisement::clearData() {
|
||||||
|
std::vector<uint8_t> swap;
|
||||||
|
std::swap(m_payload, swap);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the size of the current data.
|
||||||
|
*/
|
||||||
|
size_t NimBLEExtAdvertisement::getDataSize() {
|
||||||
|
return m_payload.size();
|
||||||
|
} // getDataSize
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the advertisement data.
|
||||||
|
* @param [in] data The data to be set as the payload.
|
||||||
|
* @param [in] length The size of data.
|
||||||
|
* @details This will completely replace any data that was previously set.
|
||||||
|
*/
|
||||||
|
void NimBLEExtAdvertisement::setData(const uint8_t * data, size_t length) {
|
||||||
|
m_payload.assign(data, data + length);
|
||||||
|
} // setData
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Add data to the payload to be advertised.
|
||||||
|
* @param [in] data The data to be added to the payload.
|
||||||
|
*/
|
||||||
|
void NimBLEExtAdvertisement::addData(const std::string &data) {
|
||||||
|
addData((uint8_t*)data.data(), data.length());
|
||||||
|
} // addData
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Add data to the payload to be advertised.
|
||||||
|
* @param [in] data The data to be added to the payload.
|
||||||
|
* @param [in] length The size of data to be added to the payload.
|
||||||
|
*/
|
||||||
|
void NimBLEExtAdvertisement::addData(const uint8_t * data, size_t length) {
|
||||||
|
m_payload.insert(m_payload.end(), data, data + length);
|
||||||
|
} // addData
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the appearance.
|
||||||
|
* @param [in] appearance The appearance code value.
|
||||||
|
*
|
||||||
|
* See also:
|
||||||
|
* https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.gap.appearance.xml
|
||||||
|
*/
|
||||||
|
void NimBLEExtAdvertisement::setAppearance(uint16_t appearance) {
|
||||||
|
char cdata[2];
|
||||||
|
cdata[0] = 3;
|
||||||
|
cdata[1] = BLE_HS_ADV_TYPE_APPEARANCE; // 0x19
|
||||||
|
addData(std::string(cdata, 2) + std::string((char*) &appearance, 2));
|
||||||
|
} // setAppearance
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the advertisement flags.
|
||||||
|
* @param [in] flag The flags to be set in the advertisement.
|
||||||
|
* * BLE_HS_ADV_F_DISC_LTD
|
||||||
|
* * BLE_HS_ADV_F_DISC_GEN
|
||||||
|
* * BLE_HS_ADV_F_BREDR_UNSUP - must always use with NimBLE
|
||||||
|
*/
|
||||||
|
void NimBLEExtAdvertisement::setFlags(uint8_t flag) {
|
||||||
|
char cdata[3];
|
||||||
|
cdata[0] = 2;
|
||||||
|
cdata[1] = BLE_HS_ADV_TYPE_FLAGS; // 0x01
|
||||||
|
cdata[2] = flag | BLE_HS_ADV_F_BREDR_UNSUP;
|
||||||
|
addData(std::string(cdata, 3));
|
||||||
|
} // setFlags
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set manufacturer specific data.
|
||||||
|
* @param [in] data The manufacturer data to advertise.
|
||||||
|
*/
|
||||||
|
void NimBLEExtAdvertisement::setManufacturerData(const std::string &data) {
|
||||||
|
char cdata[2];
|
||||||
|
cdata[0] = data.length() + 1;
|
||||||
|
cdata[1] = BLE_HS_ADV_TYPE_MFG_DATA ; // 0xff
|
||||||
|
addData(std::string(cdata, 2) + data);
|
||||||
|
} // setManufacturerData
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the URI to advertise.
|
||||||
|
* @param [in] uri The uri to advertise.
|
||||||
|
*/
|
||||||
|
void NimBLEExtAdvertisement::setURI(const std::string &uri) {
|
||||||
|
char cdata[2];
|
||||||
|
cdata[0] = uri.length() + 1;
|
||||||
|
cdata[1] = BLE_HS_ADV_TYPE_URI;
|
||||||
|
addData(std::string(cdata, 2) + uri);
|
||||||
|
} // setURI
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the complete name of this device.
|
||||||
|
* @param [in] name The name to advertise.
|
||||||
|
*/
|
||||||
|
void NimBLEExtAdvertisement::setName(const std::string &name) {
|
||||||
|
char cdata[2];
|
||||||
|
cdata[0] = name.length() + 1;
|
||||||
|
cdata[1] = BLE_HS_ADV_TYPE_COMP_NAME; // 0x09
|
||||||
|
addData(std::string(cdata, 2) + name);
|
||||||
|
} // setName
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set a single service to advertise as a complete list of services.
|
||||||
|
* @param [in] uuid The service to advertise.
|
||||||
|
*/
|
||||||
|
void NimBLEExtAdvertisement::setCompleteServices(const NimBLEUUID &uuid) {
|
||||||
|
setServices(true, uuid.bitSize(), {uuid});
|
||||||
|
} // setCompleteServices
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the complete list of 16 bit services to advertise.
|
||||||
|
* @param [in] v_uuid A vector of 16 bit UUID's to advertise.
|
||||||
|
*/
|
||||||
|
void NimBLEExtAdvertisement::setCompleteServices16(const std::vector<NimBLEUUID>& v_uuid) {
|
||||||
|
setServices(true, 16, v_uuid);
|
||||||
|
} // setCompleteServices16
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the complete list of 32 bit services to advertise.
|
||||||
|
* @param [in] v_uuid A vector of 32 bit UUID's to advertise.
|
||||||
|
*/
|
||||||
|
void NimBLEExtAdvertisement::setCompleteServices32(const std::vector<NimBLEUUID>& v_uuid) {
|
||||||
|
setServices(true, 32, v_uuid);
|
||||||
|
} // setCompleteServices32
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set a single service to advertise as a partial list of services.
|
||||||
|
* @param [in] uuid The service to advertise.
|
||||||
|
*/
|
||||||
|
void NimBLEExtAdvertisement::setPartialServices(const NimBLEUUID &uuid) {
|
||||||
|
setServices(false, uuid.bitSize(), {uuid});
|
||||||
|
} // setPartialServices
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the partial list of services to advertise.
|
||||||
|
* @param [in] v_uuid A vector of 16 bit UUID's to advertise.
|
||||||
|
*/
|
||||||
|
void NimBLEExtAdvertisement::setPartialServices16(const std::vector<NimBLEUUID>& v_uuid) {
|
||||||
|
setServices(false, 16, v_uuid);
|
||||||
|
} // setPartialServices16
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the partial list of services to advertise.
|
||||||
|
* @param [in] v_uuid A vector of 32 bit UUID's to advertise.
|
||||||
|
*/
|
||||||
|
void NimBLEExtAdvertisement::setPartialServices32(const std::vector<NimBLEUUID>& v_uuid) {
|
||||||
|
setServices(false, 32, v_uuid);
|
||||||
|
} // setPartialServices32
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Utility function to create the list of service UUID's from a vector.
|
||||||
|
* @param [in] complete If true the vector is the complete set of services.
|
||||||
|
* @param [in] size The bit size of the UUID's in the vector. (16, 32, or 128).
|
||||||
|
* @param [in] v_uuid The vector of service UUID's to advertise.
|
||||||
|
*/
|
||||||
|
void NimBLEExtAdvertisement::setServices(const bool complete, const uint8_t size,
|
||||||
|
const std::vector<NimBLEUUID> &v_uuid)
|
||||||
|
{
|
||||||
|
char cdata[2];
|
||||||
|
cdata[0] = (size / 8) * v_uuid.size() + 1;
|
||||||
|
switch(size) {
|
||||||
|
case 16:
|
||||||
|
cdata[1] = complete ? BLE_HS_ADV_TYPE_COMP_UUIDS16 : BLE_HS_ADV_TYPE_INCOMP_UUIDS16;
|
||||||
|
break;
|
||||||
|
case 32:
|
||||||
|
cdata[1] = complete ? BLE_HS_ADV_TYPE_COMP_UUIDS32 : BLE_HS_ADV_TYPE_INCOMP_UUIDS32;
|
||||||
|
break;
|
||||||
|
case 128:
|
||||||
|
cdata[1] = complete ? BLE_HS_ADV_TYPE_COMP_UUIDS128 : BLE_HS_ADV_TYPE_INCOMP_UUIDS128;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string uuids;
|
||||||
|
|
||||||
|
for(auto &it : v_uuid){
|
||||||
|
if(it.bitSize() != size) {
|
||||||
|
NIMBLE_LOGE(LOG_TAG, "Service UUID(%d) invalid", size);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
switch(size) {
|
||||||
|
case 16:
|
||||||
|
uuids += std::string((char*)&it.getNative()->u16.value, 2);
|
||||||
|
break;
|
||||||
|
case 32:
|
||||||
|
uuids += std::string((char*)&it.getNative()->u32.value, 4);
|
||||||
|
break;
|
||||||
|
case 128:
|
||||||
|
uuids += std::string((char*)&it.getNative()->u128.value, 16);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addData(std::string(cdata, 2) + uuids);
|
||||||
|
} // setServices
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the service data (UUID + data)
|
||||||
|
* @param [in] uuid The UUID to set with the service data.
|
||||||
|
* @param [in] data The data to be associated with the service data advertised.
|
||||||
|
*/
|
||||||
|
void NimBLEExtAdvertisement::setServiceData(const NimBLEUUID &uuid, const std::string &data) {
|
||||||
|
char cdata[2];
|
||||||
|
switch (uuid.bitSize()) {
|
||||||
|
case 16: {
|
||||||
|
// [Len] [0x16] [UUID16] data
|
||||||
|
cdata[0] = data.length() + 3;
|
||||||
|
cdata[1] = BLE_HS_ADV_TYPE_SVC_DATA_UUID16; // 0x16
|
||||||
|
addData(std::string(cdata, 2) + std::string((char*) &uuid.getNative()->u16.value, 2) + data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 32: {
|
||||||
|
// [Len] [0x20] [UUID32] data
|
||||||
|
cdata[0] = data.length() + 5;
|
||||||
|
cdata[1] = BLE_HS_ADV_TYPE_SVC_DATA_UUID32; // 0x20
|
||||||
|
addData(std::string(cdata, 2) + std::string((char*) &uuid.getNative()->u32.value, 4) + data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 128: {
|
||||||
|
// [Len] [0x21] [UUID128] data
|
||||||
|
cdata[0] = data.length() + 17;
|
||||||
|
cdata[1] = BLE_HS_ADV_TYPE_SVC_DATA_UUID128; // 0x21
|
||||||
|
addData(std::string(cdata, 2) + std::string((char*) &uuid.getNative()->u128.value, 16) + data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} // setServiceData
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the short name.
|
||||||
|
* @param [in] name The short name of the device.
|
||||||
|
*/
|
||||||
|
void NimBLEExtAdvertisement::setShortName(const std::string &name) {
|
||||||
|
char cdata[2];
|
||||||
|
cdata[0] = name.length() + 1;
|
||||||
|
cdata[1] = BLE_HS_ADV_TYPE_INCOMP_NAME; // 0x08
|
||||||
|
addData(std::string(cdata, 2) + name);
|
||||||
|
} // setShortName
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds Tx power level to the advertisement data.
|
||||||
|
*/
|
||||||
|
void NimBLEExtAdvertisement::addTxPower() {
|
||||||
|
m_params.include_tx_power = 1;
|
||||||
|
} // addTxPower
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the preferred connection interval parameters.
|
||||||
|
* @param [in] min The minimum interval desired.
|
||||||
|
* @param [in] max The maximum interval desired.
|
||||||
|
*/
|
||||||
|
void NimBLEExtAdvertisement::setPreferredParams(uint16_t min, uint16_t max) {
|
||||||
|
uint8_t data[6];
|
||||||
|
data[0] = BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN + 1;
|
||||||
|
data[1] = BLE_HS_ADV_TYPE_SLAVE_ITVL_RANGE;
|
||||||
|
data[2] = min;
|
||||||
|
data[3] = min >> 8;
|
||||||
|
data[4] = max;
|
||||||
|
data[5] = max >> 8;
|
||||||
|
addData(data, 6);
|
||||||
|
} // setPreferredParams
|
||||||
|
|
||||||
|
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER && CONFIG_BT_NIMBLE_EXT_ADV */
|
152
src/NimBLEExtAdvertising.h
Normal file
152
src/NimBLEExtAdvertising.h
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
/*
|
||||||
|
* NimBLEExtAdvertising.h
|
||||||
|
*
|
||||||
|
* Created: on February 6, 2022
|
||||||
|
* Author H2zero
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MAIN_BLEEXTADVERTISING_H_
|
||||||
|
#define MAIN_BLEEXTADVERTISING_H_
|
||||||
|
#include "nimconfig.h"
|
||||||
|
#if defined(CONFIG_BT_ENABLED) && \
|
||||||
|
defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER) && \
|
||||||
|
CONFIG_BT_NIMBLE_EXT_ADV
|
||||||
|
|
||||||
|
# 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 "NimBLEAddress.h"
|
||||||
|
#include "NimBLEUUID.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class NimBLEExtAdvertisingCallbacks;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Extended advertisement data
|
||||||
|
*/
|
||||||
|
class NimBLEExtAdvertisement {
|
||||||
|
public:
|
||||||
|
NimBLEExtAdvertisement(uint8_t priPhy = BLE_HCI_LE_PHY_1M,
|
||||||
|
uint8_t secPhy = BLE_HCI_LE_PHY_1M);
|
||||||
|
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 flag);
|
||||||
|
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 setData(const uint8_t * data, size_t length);
|
||||||
|
void addData(const std::string &data);
|
||||||
|
void addData(const uint8_t * data, size_t length);
|
||||||
|
void addTxPower();
|
||||||
|
void setPreferredParams(uint16_t min, uint16_t max);
|
||||||
|
void setLegacyAdvertising(bool val);
|
||||||
|
void setConnectable(bool val);
|
||||||
|
void setScannable(bool val);
|
||||||
|
void setMinInterval(uint32_t mininterval);
|
||||||
|
void setMaxInterval(uint32_t maxinterval);
|
||||||
|
void setPrimaryPhy(uint8_t phy);
|
||||||
|
void setSecondaryPhy(uint8_t phy);
|
||||||
|
void setScanFilter(bool scanRequestWhitelistOnly, bool connectWhitelistOnly);
|
||||||
|
void setDirectedPeer(const NimBLEAddress & addr);
|
||||||
|
void setDirected(bool val, bool high_duty = true);
|
||||||
|
void setAnonymous(bool val);
|
||||||
|
void setPrimaryChannels(bool ch37, bool ch38, bool ch39);
|
||||||
|
void setTxPower(int8_t dbm);
|
||||||
|
void setAddress(const NimBLEAddress & addr);
|
||||||
|
void enableScanRequestCallback(bool enable);
|
||||||
|
void clearData();
|
||||||
|
size_t getDataSize();
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class NimBLEExtAdvertising;
|
||||||
|
|
||||||
|
void setServices(const bool complete, const uint8_t size,
|
||||||
|
const std::vector<NimBLEUUID> &v_uuid);
|
||||||
|
|
||||||
|
std::vector<uint8_t> m_payload;
|
||||||
|
ble_gap_ext_adv_params m_params;
|
||||||
|
NimBLEAddress m_advAddress;
|
||||||
|
}; // NimBLEExtAdvertisement
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Extended advertising class.
|
||||||
|
*/
|
||||||
|
class NimBLEExtAdvertising {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct an extended advertising object.
|
||||||
|
*/
|
||||||
|
NimBLEExtAdvertising() :m_advStatus(CONFIG_BT_NIMBLE_MAX_EXT_ADV_INSTANCES + 1, false) {}
|
||||||
|
~NimBLEExtAdvertising();
|
||||||
|
bool start(uint8_t inst_id, int duration = 0, int max_events = 0);
|
||||||
|
bool setInstanceData(uint8_t inst_id, NimBLEExtAdvertisement& adv);
|
||||||
|
bool setScanResponseData(uint8_t inst_id, NimBLEExtAdvertisement & data);
|
||||||
|
bool removeInstance(uint8_t inst_id);
|
||||||
|
bool removeAll();
|
||||||
|
bool stop(uint8_t inst_id);
|
||||||
|
bool stop();
|
||||||
|
bool isActive(uint8_t inst_id);
|
||||||
|
bool isAdvertising();
|
||||||
|
void setCallbacks(NimBLEExtAdvertisingCallbacks* callbacks,
|
||||||
|
bool deleteCallbacks = true);
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class NimBLEDevice;
|
||||||
|
friend class NimBLEServer;
|
||||||
|
|
||||||
|
void onHostSync();
|
||||||
|
static int handleGapEvent(struct ble_gap_event *event, void *arg);
|
||||||
|
|
||||||
|
bool m_scanResp;
|
||||||
|
bool m_deleteCallbacks;
|
||||||
|
NimBLEExtAdvertisingCallbacks* m_pCallbacks;
|
||||||
|
ble_gap_ext_adv_params m_advParams;
|
||||||
|
std::vector<bool> m_advStatus;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Callbacks associated with NimBLEExtAdvertising class.
|
||||||
|
*/
|
||||||
|
class NimBLEExtAdvertisingCallbacks {
|
||||||
|
public:
|
||||||
|
virtual ~NimBLEExtAdvertisingCallbacks() {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handle an advertising stop event.
|
||||||
|
* @param [in] pAdv A convenience pointer to the extended advertising interface.
|
||||||
|
* @param [in] reason The reason code for stopping the advertising.
|
||||||
|
* @param [in] inst_id The instance ID of the advertisement that was stopped.
|
||||||
|
*/
|
||||||
|
virtual void onStopped(NimBLEExtAdvertising *pAdv, int reason, uint8_t inst_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handle a scan response request.
|
||||||
|
* This is called when a scanning device requests a scan response.
|
||||||
|
* @param [in] pAdv A convenience pointer to the extended advertising interface.
|
||||||
|
* @param [in] inst_id The instance ID of the advertisement that the scan response request was made.
|
||||||
|
* @param [in] addr The address of the device making the request.
|
||||||
|
*/
|
||||||
|
virtual void onScanRequest(NimBLEExtAdvertising *pAdv, uint8_t inst_id, NimBLEAddress addr);
|
||||||
|
}; // NimBLEExtAdvertisingCallbacks
|
||||||
|
|
||||||
|
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER && CONFIG_BT_NIMBLE_EXT_ADV */
|
||||||
|
#endif /* MAIN_BLEADVERTISING_H_ */
|
|
@ -11,11 +11,9 @@
|
||||||
* Created on: Jan 03, 2018
|
* Created on: Jan 03, 2018
|
||||||
* Author: chegewara
|
* Author: chegewara
|
||||||
*/
|
*/
|
||||||
#include "sdkconfig.h"
|
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
|
||||||
|
|
||||||
#include "nimconfig.h"
|
#include "nimconfig.h"
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||||
|
|
||||||
#include "NimBLEHIDDevice.h"
|
#include "NimBLEHIDDevice.h"
|
||||||
#include "NimBLE2904.h"
|
#include "NimBLE2904.h"
|
||||||
|
@ -29,7 +27,7 @@ NimBLEHIDDevice::NimBLEHIDDevice(NimBLEServer* server) {
|
||||||
* Here we create mandatory services described in bluetooth specification
|
* Here we create mandatory services described in bluetooth specification
|
||||||
*/
|
*/
|
||||||
m_deviceInfoService = server->createService(NimBLEUUID((uint16_t) 0x180a));
|
m_deviceInfoService = server->createService(NimBLEUUID((uint16_t) 0x180a));
|
||||||
m_hidService = server->createService(NimBLEUUID((uint16_t) 0x1812), 40);
|
m_hidService = server->createService(NimBLEUUID((uint16_t) 0x1812));
|
||||||
m_batteryService = server->createService(NimBLEUUID((uint16_t) 0x180f));
|
m_batteryService = server->createService(NimBLEUUID((uint16_t) 0x180f));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -247,5 +245,4 @@ NimBLEService* NimBLEHIDDevice::batteryService() {
|
||||||
return m_batteryService;
|
return m_batteryService;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||||
#endif // #if defined(CONFIG_BT_ENABLED)
|
|
||||||
|
|
|
@ -15,11 +15,8 @@
|
||||||
#ifndef _BLEHIDDEVICE_H_
|
#ifndef _BLEHIDDEVICE_H_
|
||||||
#define _BLEHIDDEVICE_H_
|
#define _BLEHIDDEVICE_H_
|
||||||
|
|
||||||
#include "sdkconfig.h"
|
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
|
||||||
|
|
||||||
#include "nimconfig.h"
|
#include "nimconfig.h"
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||||
|
|
||||||
#include "NimBLECharacteristic.h"
|
#include "NimBLECharacteristic.h"
|
||||||
#include "NimBLEService.h"
|
#include "NimBLEService.h"
|
||||||
|
@ -84,6 +81,6 @@ private:
|
||||||
NimBLECharacteristic* m_protocolModeCharacteristic; //0x2a4e
|
NimBLECharacteristic* m_protocolModeCharacteristic; //0x2a4e
|
||||||
NimBLECharacteristic* m_batteryLevelCharacteristic; //0x2a19
|
NimBLECharacteristic* m_batteryLevelCharacteristic; //0x2a19
|
||||||
};
|
};
|
||||||
#endif // CONFIG_BT_NIMBLE_ROLE_BROADCASTER
|
|
||||||
#endif // CONFIG_BT_ENABLED
|
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER */
|
||||||
#endif /* _BLEHIDDEVICE_H_ */
|
#endif /* _BLEHIDDEVICE_H_ */
|
||||||
|
|
|
@ -8,59 +8,73 @@
|
||||||
#ifndef MAIN_NIMBLELOG_H_
|
#ifndef MAIN_NIMBLELOG_H_
|
||||||
#define MAIN_NIMBLELOG_H_
|
#define MAIN_NIMBLELOG_H_
|
||||||
|
|
||||||
#include "sdkconfig.h"
|
#include "nimconfig.h"
|
||||||
|
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
#if defined(CONFIG_BT_ENABLED)
|
||||||
|
|
||||||
#ifdef ARDUINO_ARCH_ESP32
|
#if defined(CONFIG_NIMBLE_CPP_IDF) // using esp-idf
|
||||||
#include "syscfg/syscfg.h"
|
# include "esp_log.h"
|
||||||
#include "modlog/modlog.h"
|
# ifndef CONFIG_NIMBLE_CPP_LOG_LEVEL
|
||||||
|
# define CONFIG_NIMBLE_CPP_LOG_LEVEL 0
|
||||||
// If Arduino is being used, strip out the colors and ignore log printing below ui setting.
|
|
||||||
// Note: because CONFIG_LOG_DEFAULT_LEVEL is set at ERROR in Arduino we must use MODLOG_DFLT(ERROR
|
|
||||||
// otherwise no messages will be printed above that level.
|
|
||||||
|
|
||||||
#ifndef CORE_DEBUG_LEVEL
|
|
||||||
#define CORE_DEBUG_LEVEL CONFIG_ARDUHAL_LOG_DEFAULT_LEVEL
|
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
#if CORE_DEBUG_LEVEL >= 4
|
# define NIMBLE_CPP_LOG_PRINT(level, tag, format, ...) do { \
|
||||||
#define NIMBLE_LOGD( tag, format, ... ) MODLOG_DFLT(ERROR, "D %s: "#format"\n",tag,##__VA_ARGS__)
|
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
|
# else
|
||||||
# define NIMBLE_LOGD( tag, format, ... ) (void)tag
|
# define NIMBLE_LOGD( tag, format, ... ) (void)tag
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
#if CORE_DEBUG_LEVEL >= 3
|
# if CONFIG_NIMBLE_CPP_LOG_LEVEL >= 3
|
||||||
#define NIMBLE_LOGI( tag, format, ... ) MODLOG_DFLT(ERROR, "I %s: "#format"\n",tag,##__VA_ARGS__)
|
# define NIMBLE_LOGI( tag, format, ... ) console_printf("I %s: " format "\n", tag, ##__VA_ARGS__)
|
||||||
# else
|
# else
|
||||||
# define NIMBLE_LOGI( tag, format, ... ) (void)tag
|
# define NIMBLE_LOGI( tag, format, ... ) (void)tag
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
#if CORE_DEBUG_LEVEL >= 2
|
# if CONFIG_NIMBLE_CPP_LOG_LEVEL >= 2
|
||||||
#define NIMBLE_LOGW( tag, format, ... ) MODLOG_DFLT(ERROR, "W %s: "#format"\n",tag,##__VA_ARGS__)
|
# define NIMBLE_LOGW( tag, format, ... ) console_printf("W %s: " format "\n", tag, ##__VA_ARGS__)
|
||||||
# else
|
# else
|
||||||
# define NIMBLE_LOGW( tag, format, ... ) (void)tag
|
# define NIMBLE_LOGW( tag, format, ... ) (void)tag
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
#if CORE_DEBUG_LEVEL >= 1
|
# if CONFIG_NIMBLE_CPP_LOG_LEVEL >= 1
|
||||||
#define NIMBLE_LOGE( tag, format, ... ) MODLOG_DFLT(ERROR, "E %s: "#format"\n",tag,##__VA_ARGS__)
|
# 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
|
# else
|
||||||
# define NIMBLE_LOGE( tag, format, ... ) (void)tag
|
# define NIMBLE_LOGE( tag, format, ... ) (void)tag
|
||||||
|
# define NIMBLE_LOGC( tag, format, ... ) (void)tag
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
#define NIMBLE_LOGC( tag, format, ... ) MODLOG_DFLT(CRITICAL, "CRIT %s: "#format"\n",tag,##__VA_ARGS__)
|
#endif /* CONFIG_NIMBLE_CPP_IDF */
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#include "esp_log.h"
|
|
||||||
|
|
||||||
#define NIMBLE_LOGE(tag, format, ...) ESP_LOGE(tag, format, ##__VA_ARGS__)
|
|
||||||
#define NIMBLE_LOGW(tag, format, ...) ESP_LOGW(tag, format, ##__VA_ARGS__)
|
|
||||||
#define NIMBLE_LOGI(tag, format, ...) ESP_LOGI(tag, format, ##__VA_ARGS__)
|
|
||||||
#define NIMBLE_LOGD(tag, format, ...) ESP_LOGD(tag, format, ##__VA_ARGS__)
|
|
||||||
#define NIMBLE_LOGC(tag, format, ...) ESP_LOGE(tag, format, ##__VA_ARGS__)
|
|
||||||
|
|
||||||
#endif /*ARDUINO_ARCH_ESP32*/
|
|
||||||
|
|
||||||
#endif /* CONFIG_BT_ENABLED */
|
#endif /* CONFIG_BT_ENABLED */
|
||||||
#endif /* MAIN_NIMBLELOG_H_ */
|
#endif /* MAIN_NIMBLELOG_H_ */
|
|
@ -12,16 +12,15 @@
|
||||||
* Author: kolban
|
* Author: kolban
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "sdkconfig.h"
|
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
|
||||||
|
|
||||||
#include "nimconfig.h"
|
#include "nimconfig.h"
|
||||||
#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||||
|
|
||||||
#include "NimBLERemoteCharacteristic.h"
|
#include "NimBLERemoteCharacteristic.h"
|
||||||
#include "NimBLEUtils.h"
|
#include "NimBLEUtils.h"
|
||||||
#include "NimBLELog.h"
|
#include "NimBLELog.h"
|
||||||
|
|
||||||
|
#include <climits>
|
||||||
|
|
||||||
static const char* LOG_TAG = "NimBLERemoteCharacteristic";
|
static const char* LOG_TAG = "NimBLERemoteCharacteristic";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -59,8 +58,6 @@ static const char* LOG_TAG = "NimBLERemoteCharacteristic";
|
||||||
m_charProp = chr->properties;
|
m_charProp = chr->properties;
|
||||||
m_pRemoteService = pRemoteService;
|
m_pRemoteService = pRemoteService;
|
||||||
m_notifyCallback = nullptr;
|
m_notifyCallback = nullptr;
|
||||||
m_timestamp = 0;
|
|
||||||
m_valMux = portMUX_INITIALIZER_UNLOCKED;
|
|
||||||
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< NimBLERemoteCharacteristic(): %s", m_uuid.toString().c_str());
|
NIMBLE_LOGD(LOG_TAG, "<< NimBLERemoteCharacteristic(): %s", m_uuid.toString().c_str());
|
||||||
} // NimBLERemoteCharacteristic
|
} // NimBLERemoteCharacteristic
|
||||||
|
@ -241,7 +238,8 @@ bool NimBLERemoteCharacteristic::retrieveDescriptors(const NimBLEUUID *uuid_filt
|
||||||
}
|
}
|
||||||
|
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(), 0, nullptr};
|
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
|
// 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.
|
// The end handle is the next characteristic definition handle -1.
|
||||||
|
@ -256,6 +254,10 @@ bool NimBLERemoteCharacteristic::retrieveDescriptors(const NimBLEUUID *uuid_filt
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ulTaskNotifyValueClear
|
||||||
|
// Clear the task notification value to ensure we block
|
||||||
|
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
|
||||||
|
#endif
|
||||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||||
|
|
||||||
if (taskData.rc != 0) {
|
if (taskData.rc != 0) {
|
||||||
|
@ -264,6 +266,10 @@ bool NimBLERemoteCharacteristic::retrieveDescriptors(const NimBLEUUID *uuid_filt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_handle == m_endHandle) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
desc_filter_t filter = {uuid_filter, &taskData};
|
desc_filter_t filter = {uuid_filter, &taskData};
|
||||||
|
|
||||||
rc = ble_gattc_disc_all_dscs(getRemoteService()->getClient()->getConnId(),
|
rc = ble_gattc_disc_all_dscs(getRemoteService()->getClient()->getConnId(),
|
||||||
|
@ -277,6 +283,10 @@ bool NimBLERemoteCharacteristic::retrieveDescriptors(const NimBLEUUID *uuid_filt
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ulTaskNotifyValueClear
|
||||||
|
// Clear the task notification value to ensure we block
|
||||||
|
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
|
||||||
|
#endif
|
||||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||||
|
|
||||||
if (taskData.rc != 0) {
|
if (taskData.rc != 0) {
|
||||||
|
@ -310,14 +320,31 @@ NimBLERemoteDescriptor* NimBLERemoteCharacteristic::getDescriptor(const NimBLEUU
|
||||||
return m_descriptorVector.back();
|
return m_descriptorVector.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the request was successful but 16/32 bit descriptor not found
|
// If the request was successful but 16/32 bit uuid not found
|
||||||
// try again with the 128 bit uuid.
|
// try again with the 128 bit uuid.
|
||||||
if(uuid.bitSize() == BLE_UUID_TYPE_16 ||
|
if(uuid.bitSize() == BLE_UUID_TYPE_16 ||
|
||||||
uuid.bitSize() == BLE_UUID_TYPE_32)
|
uuid.bitSize() == BLE_UUID_TYPE_32)
|
||||||
{
|
{
|
||||||
NimBLEUUID uuid128(uuid);
|
NimBLEUUID uuid128(uuid);
|
||||||
uuid128.to128();
|
uuid128.to128();
|
||||||
return getDescriptor(uuid128);
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -407,15 +434,12 @@ NimBLEUUID NimBLERemoteCharacteristic::getUUID() {
|
||||||
* @param [in] timestamp A pointer to a time_t struct to store the time the value was read.
|
* @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.
|
* @return The value of the remote characteristic.
|
||||||
*/
|
*/
|
||||||
std::string NimBLERemoteCharacteristic::getValue(time_t *timestamp) {
|
NimBLEAttValue NimBLERemoteCharacteristic::getValue(time_t *timestamp) {
|
||||||
portENTER_CRITICAL(&m_valMux);
|
|
||||||
std::string value = m_value;
|
|
||||||
if(timestamp != nullptr) {
|
if(timestamp != nullptr) {
|
||||||
*timestamp = m_timestamp;
|
*timestamp = m_value.getTimeStamp();
|
||||||
}
|
}
|
||||||
portEXIT_CRITICAL(&m_valMux);
|
|
||||||
|
|
||||||
return value;
|
return m_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -463,12 +487,12 @@ float NimBLERemoteCharacteristic::readFloat() {
|
||||||
* @param [in] timestamp A pointer to a time_t struct to store the time the value was read.
|
* @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.
|
* @return The value of the remote characteristic.
|
||||||
*/
|
*/
|
||||||
std::string NimBLERemoteCharacteristic::readValue(time_t *timestamp) {
|
NimBLEAttValue NimBLERemoteCharacteristic::readValue(time_t *timestamp) {
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> readValue(): uuid: %s, handle: %d 0x%.2x",
|
NIMBLE_LOGD(LOG_TAG, ">> readValue(): uuid: %s, handle: %d 0x%.2x",
|
||||||
getUUID().toString().c_str(), getHandle(), getHandle());
|
getUUID().toString().c_str(), getHandle(), getHandle());
|
||||||
|
|
||||||
NimBLEClient* pClient = getRemoteService()->getClient();
|
NimBLEClient* pClient = getRemoteService()->getClient();
|
||||||
std::string value;
|
NimBLEAttValue value;
|
||||||
|
|
||||||
if (!pClient->isConnected()) {
|
if (!pClient->isConnected()) {
|
||||||
NIMBLE_LOGE(LOG_TAG, "Disconnected");
|
NIMBLE_LOGE(LOG_TAG, "Disconnected");
|
||||||
|
@ -477,7 +501,8 @@ std::string NimBLERemoteCharacteristic::readValue(time_t *timestamp) {
|
||||||
|
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
int retryCount = 1;
|
int retryCount = 1;
|
||||||
ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(),0, &value};
|
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
|
||||||
|
ble_task_data_t taskData = {this, cur_task, 0, &value};
|
||||||
|
|
||||||
do {
|
do {
|
||||||
rc = ble_gattc_read_long(pClient->getConnId(), m_handle, 0,
|
rc = ble_gattc_read_long(pClient->getConnId(), m_handle, 0,
|
||||||
|
@ -489,6 +514,10 @@ std::string NimBLERemoteCharacteristic::readValue(time_t *timestamp) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ulTaskNotifyValueClear
|
||||||
|
// Clear the task notification value to ensure we block
|
||||||
|
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
|
||||||
|
#endif
|
||||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||||
rc = taskData.rc;
|
rc = taskData.rc;
|
||||||
|
|
||||||
|
@ -514,14 +543,11 @@ std::string NimBLERemoteCharacteristic::readValue(time_t *timestamp) {
|
||||||
}
|
}
|
||||||
} while(rc != 0 && retryCount--);
|
} while(rc != 0 && retryCount--);
|
||||||
|
|
||||||
time_t t = time(nullptr);
|
value.setTimeStamp();
|
||||||
portENTER_CRITICAL(&m_valMux);
|
|
||||||
m_value = value;
|
m_value = value;
|
||||||
m_timestamp = t;
|
|
||||||
if(timestamp != nullptr) {
|
if(timestamp != nullptr) {
|
||||||
*timestamp = m_timestamp;
|
*timestamp = value.getTimeStamp();
|
||||||
}
|
}
|
||||||
portEXIT_CRITICAL(&m_valMux);
|
|
||||||
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< readValue length: %d rc=%d", value.length(), rc);
|
NIMBLE_LOGD(LOG_TAG, "<< readValue length: %d rc=%d", value.length(), rc);
|
||||||
return value;
|
return value;
|
||||||
|
@ -546,16 +572,17 @@ int NimBLERemoteCharacteristic::onReadCB(uint16_t conn_handle,
|
||||||
|
|
||||||
NIMBLE_LOGI(LOG_TAG, "Read complete; status=%d conn_handle=%d", error->status, conn_handle);
|
NIMBLE_LOGI(LOG_TAG, "Read complete; status=%d conn_handle=%d", error->status, conn_handle);
|
||||||
|
|
||||||
std::string *strBuf = (std::string*)pTaskData->buf;
|
NimBLEAttValue *valBuf = (NimBLEAttValue*)pTaskData->buf;
|
||||||
int rc = error->status;
|
int rc = error->status;
|
||||||
|
|
||||||
if(rc == 0) {
|
if(rc == 0) {
|
||||||
if(attr) {
|
if(attr) {
|
||||||
if(((*strBuf).length() + attr->om->om_len) > BLE_ATT_ATTR_MAX_LEN) {
|
uint16_t data_len = OS_MBUF_PKTLEN(attr->om);
|
||||||
|
if((valBuf->size() + data_len) > BLE_ATT_ATTR_MAX_LEN) {
|
||||||
rc = BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
rc = BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||||
} else {
|
} else {
|
||||||
NIMBLE_LOGD(LOG_TAG, "Got %d bytes", attr->om->om_len);
|
NIMBLE_LOGD(LOG_TAG, "Got %u bytes", data_len);
|
||||||
(*strBuf) += std::string((char*) attr->om->om_data, attr->om->om_len);
|
valBuf->append(attr->om->om_data, data_len);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -706,22 +733,33 @@ std::string NimBLERemoteCharacteristic::toString() {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Write the new value for the characteristic.
|
* @brief Write a new value to the remote characteristic from a std::vector<uint8_t>.
|
||||||
* @param [in] newValue The new value to write.
|
* @param [in] vec A std::vector<uint8_t> value to write to the remote characteristic.
|
||||||
* @param [in] response Do we expect a response?
|
* @param [in] response Whether we require a response from the write.
|
||||||
* @return false if not connected or cant perform write for some reason.
|
* @return false if not connected or otherwise cannot perform write.
|
||||||
*/
|
*/
|
||||||
bool NimBLERemoteCharacteristic::writeValue(const std::string &newValue, bool response) {
|
bool NimBLERemoteCharacteristic::writeValue(const std::vector<uint8_t>& vec, bool response) {
|
||||||
return writeValue((uint8_t*)newValue.c_str(), newValue.length(), response);
|
return writeValue((uint8_t*)&vec[0], vec.size(), response);
|
||||||
} // writeValue
|
} // writeValue
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Write the new value for the characteristic from a data buffer.
|
* @brief Write a new value to the remote characteristic from a const char*.
|
||||||
|
* @param [in] char_s A character string to write to the remote characteristic.
|
||||||
|
* @param [in] response Whether we require a response from the write.
|
||||||
|
* @return false if not connected or otherwise cannot perform write.
|
||||||
|
*/
|
||||||
|
bool NimBLERemoteCharacteristic::writeValue(const char* char_s, bool response) {
|
||||||
|
return writeValue((uint8_t*)char_s, strlen(char_s), response);
|
||||||
|
} // writeValue
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Write a new value to the remote characteristic from a data buffer.
|
||||||
* @param [in] data A pointer to 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] length The length of the data in the data buffer.
|
||||||
* @param [in] response Whether we require a response from the write.
|
* @param [in] response Whether we require a response from the write.
|
||||||
* @return false if not connected or cant perform write for some reason.
|
* @return false if not connected or otherwise cannot perform write.
|
||||||
*/
|
*/
|
||||||
bool NimBLERemoteCharacteristic::writeValue(const uint8_t* data, size_t length, bool response) {
|
bool NimBLERemoteCharacteristic::writeValue(const uint8_t* data, size_t length, bool response) {
|
||||||
|
|
||||||
|
@ -745,7 +783,8 @@ bool NimBLERemoteCharacteristic::writeValue(const uint8_t* data, size_t length,
|
||||||
return (rc==0);
|
return (rc==0);
|
||||||
}
|
}
|
||||||
|
|
||||||
ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(), 0, nullptr};
|
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
|
||||||
|
ble_task_data_t taskData = {this, cur_task, 0, nullptr};
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if(length > mtu) {
|
if(length > mtu) {
|
||||||
|
@ -765,6 +804,10 @@ bool NimBLERemoteCharacteristic::writeValue(const uint8_t* data, size_t length,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ulTaskNotifyValueClear
|
||||||
|
// Clear the task notification value to ensure we block
|
||||||
|
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
|
||||||
|
#endif
|
||||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||||
rc = taskData.rc;
|
rc = taskData.rc;
|
||||||
|
|
||||||
|
@ -819,6 +862,4 @@ int NimBLERemoteCharacteristic::onWriteCB(uint16_t conn_handle,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|
||||||
#endif // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
|
||||||
#endif /* CONFIG_BT_ENABLED */
|
|
||||||
|
|
|
@ -14,17 +14,16 @@
|
||||||
|
|
||||||
#ifndef COMPONENTS_NIMBLEREMOTECHARACTERISTIC_H_
|
#ifndef COMPONENTS_NIMBLEREMOTECHARACTERISTIC_H_
|
||||||
#define COMPONENTS_NIMBLEREMOTECHARACTERISTIC_H_
|
#define COMPONENTS_NIMBLEREMOTECHARACTERISTIC_H_
|
||||||
#include "sdkconfig.h"
|
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
|
||||||
|
|
||||||
#include "nimconfig.h"
|
#include "nimconfig.h"
|
||||||
#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||||
|
|
||||||
#include "NimBLERemoteService.h"
|
#include "NimBLERemoteService.h"
|
||||||
#include "NimBLERemoteDescriptor.h"
|
#include "NimBLERemoteDescriptor.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include "NimBLELog.h"
|
||||||
|
|
||||||
class NimBLERemoteService;
|
class NimBLERemoteService;
|
||||||
class NimBLERemoteDescriptor;
|
class NimBLERemoteDescriptor;
|
||||||
|
@ -62,47 +61,15 @@ public:
|
||||||
uint16_t getHandle();
|
uint16_t getHandle();
|
||||||
uint16_t getDefHandle();
|
uint16_t getDefHandle();
|
||||||
NimBLEUUID getUUID();
|
NimBLEUUID getUUID();
|
||||||
std::string readValue(time_t *timestamp = nullptr);
|
NimBLEAttValue readValue(time_t *timestamp = nullptr);
|
||||||
|
std::string toString();
|
||||||
/**
|
NimBLERemoteService* getRemoteService();
|
||||||
* @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>()")));
|
uint8_t readUInt8() __attribute__ ((deprecated("Use template readValue<uint8_t>()")));
|
||||||
uint16_t readUInt16() __attribute__ ((deprecated("Use template readValue<uint16_t>()")));
|
uint16_t readUInt16() __attribute__ ((deprecated("Use template readValue<uint16_t>()")));
|
||||||
uint32_t readUInt32() __attribute__ ((deprecated("Use template readValue<uint32_t>()")));
|
uint32_t readUInt32() __attribute__ ((deprecated("Use template readValue<uint32_t>()")));
|
||||||
float readFloat() __attribute__ ((deprecated("Use template readValue<float>()")));
|
float readFloat() __attribute__ ((deprecated("Use template readValue<float>()")));
|
||||||
std::string getValue(time_t *timestamp = nullptr);
|
NimBLEAttValue 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,
|
bool subscribe(bool notifications = true,
|
||||||
notify_callback notifyCallback = nullptr,
|
notify_callback notifyCallback = nullptr,
|
||||||
|
@ -115,20 +82,74 @@ public:
|
||||||
bool writeValue(const uint8_t* data,
|
bool writeValue(const uint8_t* data,
|
||||||
size_t length,
|
size_t length,
|
||||||
bool response = false);
|
bool response = false);
|
||||||
bool writeValue(const std::string &newValue,
|
bool writeValue(const std::vector<uint8_t>& v, bool response = false);
|
||||||
bool response = false);
|
bool writeValue(const char* s, bool response = false);
|
||||||
|
|
||||||
|
|
||||||
|
/*********************** Template Functions ************************/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Convenience template to set the remote characteristic value to <type\>val.
|
* @brief Template to set the remote characteristic value to <type\>val.
|
||||||
* @param [in] s The value to write.
|
* @param [in] s The value to write.
|
||||||
* @param [in] response True == request write response.
|
* @param [in] response True == request write response.
|
||||||
|
* @details Only used for non-arrays and types without a `c_str()` method.
|
||||||
*/
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
bool writeValue(const T &s, bool response = false) {
|
#ifdef _DOXYGEN_
|
||||||
|
bool
|
||||||
|
#else
|
||||||
|
typename std::enable_if<!std::is_array<T>::value && !Has_c_str_len<T>::value, bool>::type
|
||||||
|
#endif
|
||||||
|
writeValue(const T& s, bool response = false) {
|
||||||
return writeValue((uint8_t*)&s, sizeof(T), response);
|
return writeValue((uint8_t*)&s, sizeof(T), response);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string toString();
|
/**
|
||||||
NimBLERemoteService* getRemoteService();
|
* @brief Template to set the remote characteristic value to <type\>val.
|
||||||
|
* @param [in] s The value to write.
|
||||||
|
* @param [in] response True == request write response.
|
||||||
|
* @details Only used if the <type\> has a `c_str()` method.
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
#ifdef _DOXYGEN_
|
||||||
|
bool
|
||||||
|
#else
|
||||||
|
typename std::enable_if<Has_c_str_len<T>::value, bool>::type
|
||||||
|
#endif
|
||||||
|
writeValue(const T& s, bool response = false) {
|
||||||
|
return writeValue((uint8_t*)s.c_str(), s.length(), response);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 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) {
|
||||||
|
if(!skipSizeCheck && m_value.size() < sizeof(T)) return T();
|
||||||
|
return *((T *)m_value.getValue(timestamp));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 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) {
|
||||||
|
NimBLEAttValue value = readValue();
|
||||||
|
if(!skipSizeCheck && value.size() < sizeof(T)) return T();
|
||||||
|
return *((T *)value.getValue(timestamp));
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -158,15 +179,12 @@ private:
|
||||||
uint16_t m_defHandle;
|
uint16_t m_defHandle;
|
||||||
uint16_t m_endHandle;
|
uint16_t m_endHandle;
|
||||||
NimBLERemoteService* m_pRemoteService;
|
NimBLERemoteService* m_pRemoteService;
|
||||||
std::string m_value;
|
NimBLEAttValue m_value;
|
||||||
notify_callback m_notifyCallback;
|
notify_callback m_notifyCallback;
|
||||||
time_t m_timestamp;
|
|
||||||
portMUX_TYPE m_valMux;
|
|
||||||
|
|
||||||
// We maintain a vector of descriptors owned by this characteristic.
|
// We maintain a vector of descriptors owned by this characteristic.
|
||||||
std::vector<NimBLERemoteDescriptor*> m_descriptorVector;
|
std::vector<NimBLERemoteDescriptor*> m_descriptorVector;
|
||||||
}; // NimBLERemoteCharacteristic
|
}; // NimBLERemoteCharacteristic
|
||||||
|
|
||||||
#endif // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|
||||||
#endif /* CONFIG_BT_ENABLED */
|
|
||||||
#endif /* COMPONENTS_NIMBLEREMOTECHARACTERISTIC_H_ */
|
#endif /* COMPONENTS_NIMBLEREMOTECHARACTERISTIC_H_ */
|
||||||
|
|
|
@ -11,16 +11,16 @@
|
||||||
* Created on: Jul 8, 2017
|
* Created on: Jul 8, 2017
|
||||||
* Author: kolban
|
* Author: kolban
|
||||||
*/
|
*/
|
||||||
#include "sdkconfig.h"
|
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
|
||||||
|
|
||||||
#include "nimconfig.h"
|
#include "nimconfig.h"
|
||||||
#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||||
|
|
||||||
#include "NimBLERemoteDescriptor.h"
|
#include "NimBLERemoteDescriptor.h"
|
||||||
#include "NimBLEUtils.h"
|
#include "NimBLEUtils.h"
|
||||||
#include "NimBLELog.h"
|
#include "NimBLELog.h"
|
||||||
|
|
||||||
|
#include <climits>
|
||||||
|
|
||||||
static const char* LOG_TAG = "NimBLERemoteDescriptor";
|
static const char* LOG_TAG = "NimBLERemoteDescriptor";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -86,11 +86,7 @@ NimBLEUUID NimBLERemoteDescriptor::getUUID() {
|
||||||
* @deprecated Use readValue<uint8_t>().
|
* @deprecated Use readValue<uint8_t>().
|
||||||
*/
|
*/
|
||||||
uint8_t NimBLERemoteDescriptor::readUInt8() {
|
uint8_t NimBLERemoteDescriptor::readUInt8() {
|
||||||
std::string value = readValue();
|
return readValue<uint8_t>();
|
||||||
if (value.length() >= 1) {
|
|
||||||
return (uint8_t) value[0];
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
} // readUInt8
|
} // readUInt8
|
||||||
|
|
||||||
|
|
||||||
|
@ -100,11 +96,7 @@ uint8_t NimBLERemoteDescriptor::readUInt8() {
|
||||||
* @deprecated Use readValue<uint16_t>().
|
* @deprecated Use readValue<uint16_t>().
|
||||||
*/
|
*/
|
||||||
uint16_t NimBLERemoteDescriptor::readUInt16() {
|
uint16_t NimBLERemoteDescriptor::readUInt16() {
|
||||||
std::string value = readValue();
|
return readValue<uint16_t>();
|
||||||
if (value.length() >= 2) {
|
|
||||||
return *(uint16_t*) value.data();
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
} // readUInt16
|
} // readUInt16
|
||||||
|
|
||||||
|
|
||||||
|
@ -114,11 +106,7 @@ uint16_t NimBLERemoteDescriptor::readUInt16() {
|
||||||
* @deprecated Use readValue<uint32_t>().
|
* @deprecated Use readValue<uint32_t>().
|
||||||
*/
|
*/
|
||||||
uint32_t NimBLERemoteDescriptor::readUInt32() {
|
uint32_t NimBLERemoteDescriptor::readUInt32() {
|
||||||
std::string value = readValue();
|
return readValue<uint32_t>();
|
||||||
if (value.length() >= 4) {
|
|
||||||
return *(uint32_t*) value.data();
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
} // readUInt32
|
} // readUInt32
|
||||||
|
|
||||||
|
|
||||||
|
@ -126,11 +114,11 @@ uint32_t NimBLERemoteDescriptor::readUInt32() {
|
||||||
* @brief Read the value of the remote descriptor.
|
* @brief Read the value of the remote descriptor.
|
||||||
* @return The value of the remote descriptor.
|
* @return The value of the remote descriptor.
|
||||||
*/
|
*/
|
||||||
std::string NimBLERemoteDescriptor::readValue() {
|
NimBLEAttValue NimBLERemoteDescriptor::readValue() {
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> Descriptor readValue: %s", toString().c_str());
|
NIMBLE_LOGD(LOG_TAG, ">> Descriptor readValue: %s", toString().c_str());
|
||||||
|
|
||||||
NimBLEClient* pClient = getRemoteCharacteristic()->getRemoteService()->getClient();
|
NimBLEClient* pClient = getRemoteCharacteristic()->getRemoteService()->getClient();
|
||||||
std::string value;
|
NimBLEAttValue value;
|
||||||
|
|
||||||
if (!pClient->isConnected()) {
|
if (!pClient->isConnected()) {
|
||||||
NIMBLE_LOGE(LOG_TAG, "Disconnected");
|
NIMBLE_LOGE(LOG_TAG, "Disconnected");
|
||||||
|
@ -139,7 +127,8 @@ std::string NimBLERemoteDescriptor::readValue() {
|
||||||
|
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
int retryCount = 1;
|
int retryCount = 1;
|
||||||
ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(),0, &value};
|
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
|
||||||
|
ble_task_data_t taskData = {this, cur_task, 0, &value};
|
||||||
|
|
||||||
do {
|
do {
|
||||||
rc = ble_gattc_read_long(pClient->getConnId(), m_handle, 0,
|
rc = ble_gattc_read_long(pClient->getConnId(), m_handle, 0,
|
||||||
|
@ -151,6 +140,10 @@ std::string NimBLERemoteDescriptor::readValue() {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ulTaskNotifyValueClear
|
||||||
|
// Clear the task notification value to ensure we block
|
||||||
|
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
|
||||||
|
#endif
|
||||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||||
rc = taskData.rc;
|
rc = taskData.rc;
|
||||||
|
|
||||||
|
@ -175,7 +168,7 @@ std::string NimBLERemoteDescriptor::readValue() {
|
||||||
}
|
}
|
||||||
} while(rc != 0 && retryCount--);
|
} while(rc != 0 && retryCount--);
|
||||||
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< Descriptor readValue(): length: %d rc=%d", value.length(), rc);
|
NIMBLE_LOGD(LOG_TAG, "<< Descriptor readValue(): length: %u rc=%d", value.length(), rc);
|
||||||
return value;
|
return value;
|
||||||
} // readValue
|
} // readValue
|
||||||
|
|
||||||
|
@ -188,6 +181,7 @@ int NimBLERemoteDescriptor::onReadCB(uint16_t conn_handle,
|
||||||
const struct ble_gatt_error *error,
|
const struct ble_gatt_error *error,
|
||||||
struct ble_gatt_attr *attr, void *arg)
|
struct ble_gatt_attr *attr, void *arg)
|
||||||
{
|
{
|
||||||
|
(void)attr;
|
||||||
ble_task_data_t *pTaskData = (ble_task_data_t*)arg;
|
ble_task_data_t *pTaskData = (ble_task_data_t*)arg;
|
||||||
NimBLERemoteDescriptor* desc = (NimBLERemoteDescriptor*)pTaskData->pATT;
|
NimBLERemoteDescriptor* desc = (NimBLERemoteDescriptor*)pTaskData->pATT;
|
||||||
uint16_t conn_id = desc->getRemoteCharacteristic()->getRemoteService()->getClient()->getConnId();
|
uint16_t conn_id = desc->getRemoteCharacteristic()->getRemoteService()->getClient()->getConnId();
|
||||||
|
@ -198,16 +192,17 @@ int NimBLERemoteDescriptor::onReadCB(uint16_t conn_handle,
|
||||||
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "Read complete; status=%d conn_handle=%d", error->status, conn_handle);
|
NIMBLE_LOGD(LOG_TAG, "Read complete; status=%d conn_handle=%d", error->status, conn_handle);
|
||||||
|
|
||||||
std::string *strBuf = (std::string*)pTaskData->buf;
|
NimBLEAttValue *valBuf = (NimBLEAttValue*)pTaskData->buf;
|
||||||
int rc = error->status;
|
int rc = error->status;
|
||||||
|
|
||||||
if(rc == 0) {
|
if(rc == 0) {
|
||||||
if(attr) {
|
if(attr) {
|
||||||
if(((*strBuf).length() + attr->om->om_len) > BLE_ATT_ATTR_MAX_LEN) {
|
uint16_t data_len = OS_MBUF_PKTLEN(attr->om);
|
||||||
|
if((valBuf->size() + data_len) > BLE_ATT_ATTR_MAX_LEN) {
|
||||||
rc = BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
rc = BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||||
} else {
|
} else {
|
||||||
NIMBLE_LOGD(LOG_TAG, "Got %d bytes", attr->om->om_len);
|
NIMBLE_LOGD(LOG_TAG, "Got %u bytes", data_len);
|
||||||
(*strBuf) += std::string((char*) attr->om->om_data, attr->om->om_len);
|
valBuf->append(attr->om->om_data, data_len);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -260,11 +255,33 @@ int NimBLERemoteDescriptor::onWriteCB(uint16_t conn_handle,
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Write data to the BLE Remote Descriptor.
|
* @brief Write a new value to a remote descriptor from a std::vector<uint8_t>.
|
||||||
|
* @param [in] vec A std::vector<uint8_t> value to write to the remote descriptor.
|
||||||
|
* @param [in] response Whether we require a response from the write.
|
||||||
|
* @return false if not connected or otherwise cannot perform write.
|
||||||
|
*/
|
||||||
|
bool NimBLERemoteDescriptor::writeValue(const std::vector<uint8_t>& vec, bool response) {
|
||||||
|
return writeValue((uint8_t*)&vec[0], vec.size(), response);
|
||||||
|
} // writeValue
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Write a new value to the remote descriptor from a const char*.
|
||||||
|
* @param [in] char_s A character string to write to the remote descriptor.
|
||||||
|
* @param [in] response Whether we require a response from the write.
|
||||||
|
* @return false if not connected or otherwise cannot perform write.
|
||||||
|
*/
|
||||||
|
bool NimBLERemoteDescriptor::writeValue(const char* char_s, bool response) {
|
||||||
|
return writeValue((uint8_t*)char_s, strlen(char_s), response);
|
||||||
|
} // writeValue
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Write a new value to a remote descriptor.
|
||||||
* @param [in] data The data to send to the 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] length The length of the data to send.
|
||||||
* @param [in] response True if we expect a write response.
|
* @param [in] response True if we expect a write response.
|
||||||
* @return True if successful
|
* @return false if not connected or otherwise cannot perform write.
|
||||||
*/
|
*/
|
||||||
bool NimBLERemoteDescriptor::writeValue(const uint8_t* data, size_t length, bool response) {
|
bool NimBLERemoteDescriptor::writeValue(const uint8_t* data, size_t length, bool response) {
|
||||||
|
|
||||||
|
@ -289,7 +306,8 @@ bool NimBLERemoteDescriptor::writeValue(const uint8_t* data, size_t length, bool
|
||||||
return (rc == 0);
|
return (rc == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(), 0, nullptr};
|
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
|
||||||
|
ble_task_data_t taskData = {this, cur_task, 0, nullptr};
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if(length > mtu) {
|
if(length > mtu) {
|
||||||
|
@ -310,6 +328,10 @@ bool NimBLERemoteDescriptor::writeValue(const uint8_t* data, size_t length, bool
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ulTaskNotifyValueClear
|
||||||
|
// Clear the task notification value to ensure we block
|
||||||
|
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
|
||||||
|
#endif
|
||||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||||
rc = taskData.rc;
|
rc = taskData.rc;
|
||||||
|
|
||||||
|
@ -340,15 +362,4 @@ bool NimBLERemoteDescriptor::writeValue(const uint8_t* data, size_t length, bool
|
||||||
} // writeValue
|
} // writeValue
|
||||||
|
|
||||||
|
|
||||||
/**
|
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|
||||||
* @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 // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
|
||||||
#endif /* CONFIG_BT_ENABLED */
|
|
||||||
|
|
|
@ -14,11 +14,9 @@
|
||||||
|
|
||||||
#ifndef COMPONENTS_NIMBLEREMOTEDESCRIPTOR_H_
|
#ifndef COMPONENTS_NIMBLEREMOTEDESCRIPTOR_H_
|
||||||
#define COMPONENTS_NIMBLEREMOTEDESCRIPTOR_H_
|
#define COMPONENTS_NIMBLEREMOTEDESCRIPTOR_H_
|
||||||
#include "sdkconfig.h"
|
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
|
||||||
|
|
||||||
#include "nimconfig.h"
|
#include "nimconfig.h"
|
||||||
#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||||
|
|
||||||
#include "NimBLERemoteCharacteristic.h"
|
#include "NimBLERemoteCharacteristic.h"
|
||||||
|
|
||||||
|
@ -31,10 +29,53 @@ public:
|
||||||
uint16_t getHandle();
|
uint16_t getHandle();
|
||||||
NimBLERemoteCharacteristic* getRemoteCharacteristic();
|
NimBLERemoteCharacteristic* getRemoteCharacteristic();
|
||||||
NimBLEUUID getUUID();
|
NimBLEUUID getUUID();
|
||||||
std::string readValue();
|
NimBLEAttValue readValue();
|
||||||
|
|
||||||
|
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::vector<uint8_t>& v, bool response = false);
|
||||||
|
bool writeValue(const char* s, bool response = false);
|
||||||
|
|
||||||
|
|
||||||
|
/*********************** Template Functions ************************/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A template to convert the remote descriptor data to <type\>.
|
* @brief Template to set the remote descriptor value to <type\>val.
|
||||||
|
* @param [in] s The value to write.
|
||||||
|
* @param [in] response True == request write response.
|
||||||
|
* @details Only used for non-arrays and types without a `c_str()` method.
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
#ifdef _DOXYGEN_
|
||||||
|
bool
|
||||||
|
#else
|
||||||
|
typename std::enable_if<!std::is_array<T>::value && !Has_c_str_len<T>::value, bool>::type
|
||||||
|
#endif
|
||||||
|
writeValue(const T& s, bool response = false) {
|
||||||
|
return writeValue((uint8_t*)&s, sizeof(T), response);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Template to set the remote descriptor value to <type\>val.
|
||||||
|
* @param [in] s The value to write.
|
||||||
|
* @param [in] response True == request write response.
|
||||||
|
* @details Only used if the <type\> has a `c_str()` method.
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
#ifdef _DOXYGEN_
|
||||||
|
bool
|
||||||
|
#else
|
||||||
|
typename std::enable_if<Has_c_str_len<T>::value, bool>::type
|
||||||
|
#endif
|
||||||
|
writeValue(const T& s, bool response = false) {
|
||||||
|
return writeValue((uint8_t*)s.c_str(), s.length(), response);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Template to convert the remote descriptor data to <type\>.
|
||||||
* @tparam T The type to convert the data to.
|
* @tparam T The type to convert the data to.
|
||||||
* @param [in] skipSizeCheck If true it will skip checking if the data size is less than <tt>sizeof(<type\>)</tt>.
|
* @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
|
* @return The data converted to <type\> or NULL if skipSizeCheck is false and the data is
|
||||||
|
@ -43,27 +84,9 @@ public:
|
||||||
*/
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T readValue(bool skipSizeCheck = false) {
|
T readValue(bool skipSizeCheck = false) {
|
||||||
std::string value = readValue();
|
NimBLEAttValue value = readValue();
|
||||||
if(!skipSizeCheck && value.size() < sizeof(T)) return T();
|
if(!skipSizeCheck && value.size() < sizeof(T)) return T();
|
||||||
const char *pData = value.data();
|
return *((T *)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:
|
private:
|
||||||
|
@ -81,6 +104,5 @@ private:
|
||||||
NimBLERemoteCharacteristic* m_pRemoteCharacteristic;
|
NimBLERemoteCharacteristic* m_pRemoteCharacteristic;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|
||||||
#endif /* CONFIG_BT_ENABLED */
|
|
||||||
#endif /* COMPONENTS_NIMBLEREMOTEDESCRIPTOR_H_ */
|
#endif /* COMPONENTS_NIMBLEREMOTEDESCRIPTOR_H_ */
|
||||||
|
|
|
@ -11,17 +11,17 @@
|
||||||
* Created on: Jul 8, 2017
|
* Created on: Jul 8, 2017
|
||||||
* Author: kolban
|
* Author: kolban
|
||||||
*/
|
*/
|
||||||
#include "sdkconfig.h"
|
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
|
||||||
|
|
||||||
#include "nimconfig.h"
|
#include "nimconfig.h"
|
||||||
#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||||
|
|
||||||
#include "NimBLERemoteService.h"
|
#include "NimBLERemoteService.h"
|
||||||
#include "NimBLEUtils.h"
|
#include "NimBLEUtils.h"
|
||||||
#include "NimBLEDevice.h"
|
#include "NimBLEDevice.h"
|
||||||
#include "NimBLELog.h"
|
#include "NimBLELog.h"
|
||||||
|
|
||||||
|
#include <climits>
|
||||||
|
|
||||||
static const char* LOG_TAG = "NimBLERemoteService";
|
static const char* LOG_TAG = "NimBLERemoteService";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -109,14 +109,31 @@ NimBLERemoteCharacteristic* NimBLERemoteService::getCharacteristic(const NimBLEU
|
||||||
return m_characteristicVector.back();
|
return m_characteristicVector.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the request was successful but 16/32 bit characteristic not found
|
// If the request was successful but 16/32 bit uuid not found
|
||||||
// try again with the 128 bit uuid.
|
// try again with the 128 bit uuid.
|
||||||
if(uuid.bitSize() == BLE_UUID_TYPE_16 ||
|
if(uuid.bitSize() == BLE_UUID_TYPE_16 ||
|
||||||
uuid.bitSize() == BLE_UUID_TYPE_32)
|
uuid.bitSize() == BLE_UUID_TYPE_32)
|
||||||
{
|
{
|
||||||
NimBLEUUID uuid128(uuid);
|
NimBLEUUID uuid128(uuid);
|
||||||
uuid128.to128();
|
uuid128.to128();
|
||||||
return getCharacteristic(uuid128);
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,7 +215,8 @@ bool NimBLERemoteService::retrieveCharacteristics(const NimBLEUUID *uuid_filter)
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> retrieveCharacteristics() for service: %s", getUUID().toString().c_str());
|
NIMBLE_LOGD(LOG_TAG, ">> retrieveCharacteristics() for service: %s", getUUID().toString().c_str());
|
||||||
|
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(), 0, nullptr};
|
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
|
||||||
|
ble_task_data_t taskData = {this, cur_task, 0, nullptr};
|
||||||
|
|
||||||
if(uuid_filter == nullptr) {
|
if(uuid_filter == nullptr) {
|
||||||
rc = ble_gattc_disc_all_chrs(m_pClient->getConnId(),
|
rc = ble_gattc_disc_all_chrs(m_pClient->getConnId(),
|
||||||
|
@ -220,6 +238,10 @@ bool NimBLERemoteService::retrieveCharacteristics(const NimBLEUUID *uuid_filter)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ulTaskNotifyValueClear
|
||||||
|
// Clear the task notification value to ensure we block
|
||||||
|
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
|
||||||
|
#endif
|
||||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||||
|
|
||||||
if(taskData.rc == 0){
|
if(taskData.rc == 0){
|
||||||
|
@ -234,8 +256,10 @@ bool NimBLERemoteService::retrieveCharacteristics(const NimBLEUUID *uuid_filter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_characteristicVector.size() > 0) {
|
||||||
m_characteristicVector.back()->m_endHandle = getEndHandle();
|
m_characteristicVector.back()->m_endHandle = getEndHandle();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< retrieveCharacteristics()");
|
NIMBLE_LOGD(LOG_TAG, "<< retrieveCharacteristics()");
|
||||||
return true;
|
return true;
|
||||||
|
@ -386,6 +410,4 @@ std::string NimBLERemoteService::toString() {
|
||||||
return res;
|
return res;
|
||||||
} // toString
|
} // toString
|
||||||
|
|
||||||
|
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|
||||||
#endif // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
|
||||||
#endif /* CONFIG_BT_ENABLED */
|
|
||||||
|
|
|
@ -14,11 +14,9 @@
|
||||||
|
|
||||||
#ifndef COMPONENTS_NIMBLEREMOTESERVICE_H_
|
#ifndef COMPONENTS_NIMBLEREMOTESERVICE_H_
|
||||||
#define COMPONENTS_NIMBLEREMOTESERVICE_H_
|
#define COMPONENTS_NIMBLEREMOTESERVICE_H_
|
||||||
#include "sdkconfig.h"
|
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
|
||||||
|
|
||||||
#include "nimconfig.h"
|
#include "nimconfig.h"
|
||||||
#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||||
|
|
||||||
#include "NimBLEClient.h"
|
#include "NimBLEClient.h"
|
||||||
#include "NimBLEUUID.h"
|
#include "NimBLEUUID.h"
|
||||||
|
@ -83,6 +81,5 @@ private:
|
||||||
uint16_t m_endHandle;
|
uint16_t m_endHandle;
|
||||||
}; // NimBLERemoteService
|
}; // NimBLERemoteService
|
||||||
|
|
||||||
#endif // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|
||||||
#endif /* CONFIG_BT_ENABLED */
|
|
||||||
#endif /* COMPONENTS_NIMBLEREMOTESERVICE_H_ */
|
#endif /* COMPONENTS_NIMBLEREMOTESERVICE_H_ */
|
||||||
|
|
|
@ -11,17 +11,16 @@
|
||||||
* Created on: Jul 1, 2017
|
* Created on: Jul 1, 2017
|
||||||
* Author: kolban
|
* Author: kolban
|
||||||
*/
|
*/
|
||||||
#include "sdkconfig.h"
|
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
|
||||||
|
|
||||||
#include "nimconfig.h"
|
#include "nimconfig.h"
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||||
|
|
||||||
#include "NimBLEScan.h"
|
#include "NimBLEScan.h"
|
||||||
#include "NimBLEDevice.h"
|
#include "NimBLEDevice.h"
|
||||||
#include "NimBLELog.h"
|
#include "NimBLELog.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <climits>
|
||||||
|
|
||||||
static const char* LOG_TAG = "NimBLEScan";
|
static const char* LOG_TAG = "NimBLEScan";
|
||||||
|
|
||||||
|
@ -57,18 +56,27 @@ NimBLEScan::~NimBLEScan() {
|
||||||
* @param [in] param Parameter data for this event.
|
* @param [in] param Parameter data for this event.
|
||||||
*/
|
*/
|
||||||
/*STATIC*/int NimBLEScan::handleGapEvent(ble_gap_event* event, void* arg) {
|
/*STATIC*/int NimBLEScan::handleGapEvent(ble_gap_event* event, void* arg) {
|
||||||
|
(void)arg;
|
||||||
NimBLEScan* pScan = (NimBLEScan*)arg;
|
NimBLEScan* pScan = NimBLEDevice::getScan();
|
||||||
|
|
||||||
switch(event->type) {
|
switch(event->type) {
|
||||||
|
|
||||||
|
case BLE_GAP_EVENT_EXT_DISC:
|
||||||
case BLE_GAP_EVENT_DISC: {
|
case BLE_GAP_EVENT_DISC: {
|
||||||
if(pScan->m_ignoreResults) {
|
if(pScan->m_ignoreResults) {
|
||||||
NIMBLE_LOGI(LOG_TAG, "Scan op in progress - ignoring results");
|
NIMBLE_LOGI(LOG_TAG, "Scan op in progress - ignoring results");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#if CONFIG_BT_NIMBLE_EXT_ADV
|
||||||
NimBLEAddress advertisedAddress(event->disc.addr);
|
const auto& disc = event->ext_disc;
|
||||||
|
const bool isLegacyAdv = disc.props & BLE_HCI_ADV_LEGACY_MASK;
|
||||||
|
const auto event_type = isLegacyAdv ? disc.legacy_event_type : disc.props;
|
||||||
|
#else
|
||||||
|
const auto& disc = event->disc;
|
||||||
|
const bool isLegacyAdv = true;
|
||||||
|
const auto event_type = disc.event_type;
|
||||||
|
#endif
|
||||||
|
NimBLEAddress advertisedAddress(disc.addr);
|
||||||
|
|
||||||
// Examine our list of ignored addresses and stop processing if we don't want to see it or are already connected
|
// 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)) {
|
if(NimBLEDevice::isIgnored(advertisedAddress)) {
|
||||||
|
@ -80,7 +88,12 @@ NimBLEScan::~NimBLEScan() {
|
||||||
|
|
||||||
// If we've seen this device before get a pointer to it from the vector
|
// If we've seen this device before get a pointer to it from the vector
|
||||||
for(auto &it: pScan->m_scanResults.m_advertisedDevicesVector) {
|
for(auto &it: pScan->m_scanResults.m_advertisedDevicesVector) {
|
||||||
|
#if CONFIG_BT_NIMBLE_EXT_ADV
|
||||||
|
// Same address but different set ID should create a new advertised device.
|
||||||
|
if (it->getAddress() == advertisedAddress && it->getSetId() == disc.sid) {
|
||||||
|
#else
|
||||||
if (it->getAddress() == advertisedAddress) {
|
if (it->getAddress() == advertisedAddress) {
|
||||||
|
#endif
|
||||||
advertisedDevice = it;
|
advertisedDevice = it;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -88,17 +101,24 @@ NimBLEScan::~NimBLEScan() {
|
||||||
|
|
||||||
// If we haven't seen this device before; create a new instance and insert it in the vector.
|
// 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.
|
// 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){
|
if (advertisedDevice == nullptr &&
|
||||||
|
(!isLegacyAdv || event_type != BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP)) {
|
||||||
// Check if we have reach the scan results limit, ignore this one if so.
|
// 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
|
// 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 &&
|
if (pScan->m_maxResults > 0 && pScan->m_maxResults < 0xFF &&
|
||||||
(pScan->m_scanResults.m_advertisedDevicesVector.size() >= pScan->m_maxResults))
|
(pScan->m_scanResults.m_advertisedDevicesVector.size() >= pScan->m_maxResults)) {
|
||||||
{
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
advertisedDevice = new NimBLEAdvertisedDevice();
|
advertisedDevice = new NimBLEAdvertisedDevice();
|
||||||
advertisedDevice->setAddress(advertisedAddress);
|
advertisedDevice->setAddress(advertisedAddress);
|
||||||
advertisedDevice->setAdvType(event->disc.event_type);
|
advertisedDevice->setAdvType(event_type, isLegacyAdv);
|
||||||
|
#if CONFIG_BT_NIMBLE_EXT_ADV
|
||||||
|
advertisedDevice->setSetId(disc.sid);
|
||||||
|
advertisedDevice->setPrimaryPhy(disc.prim_phy);
|
||||||
|
advertisedDevice->setSecondaryPhy(disc.sec_phy);
|
||||||
|
advertisedDevice->setPeriodicInterval(disc.periodic_adv_itvl);
|
||||||
|
#endif
|
||||||
pScan->m_scanResults.m_advertisedDevicesVector.push_back(advertisedDevice);
|
pScan->m_scanResults.m_advertisedDevicesVector.push_back(advertisedDevice);
|
||||||
NIMBLE_LOGI(LOG_TAG, "New advertiser: %s", advertisedAddress.toString().c_str());
|
NIMBLE_LOGI(LOG_TAG, "New advertiser: %s", advertisedAddress.toString().c_str());
|
||||||
} else if (advertisedDevice != nullptr) {
|
} else if (advertisedDevice != nullptr) {
|
||||||
|
@ -109,14 +129,14 @@ NimBLEScan::~NimBLEScan() {
|
||||||
}
|
}
|
||||||
|
|
||||||
advertisedDevice->m_timestamp = time(nullptr);
|
advertisedDevice->m_timestamp = time(nullptr);
|
||||||
advertisedDevice->setRSSI(event->disc.rssi);
|
advertisedDevice->setRSSI(disc.rssi);
|
||||||
advertisedDevice->setPayload(event->disc.data, event->disc.length_data,
|
advertisedDevice->setPayload(disc.data, disc.length_data, (isLegacyAdv &&
|
||||||
event->disc.event_type == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP);
|
event_type == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP));
|
||||||
|
|
||||||
if (pScan->m_pAdvertisedDeviceCallbacks) {
|
if (pScan->m_pAdvertisedDeviceCallbacks) {
|
||||||
// If not active scanning or scan response is not available
|
// If not active scanning or scan response is not available
|
||||||
// report the result to the callback now.
|
// or extended advertisement scanning, report the result to the callback now.
|
||||||
if(pScan->m_scan_params.passive ||
|
if(pScan->m_scan_params.passive || !isLegacyAdv ||
|
||||||
(advertisedDevice->getAdvType() != BLE_HCI_ADV_TYPE_ADV_IND &&
|
(advertisedDevice->getAdvType() != BLE_HCI_ADV_TYPE_ADV_IND &&
|
||||||
advertisedDevice->getAdvType() != BLE_HCI_ADV_TYPE_ADV_SCAN_IND))
|
advertisedDevice->getAdvType() != BLE_HCI_ADV_TYPE_ADV_SCAN_IND))
|
||||||
{
|
{
|
||||||
|
@ -124,7 +144,7 @@ NimBLEScan::~NimBLEScan() {
|
||||||
pScan->m_pAdvertisedDeviceCallbacks->onResult(advertisedDevice);
|
pScan->m_pAdvertisedDeviceCallbacks->onResult(advertisedDevice);
|
||||||
|
|
||||||
// Otherwise, wait for the scan response so we can report the complete data.
|
// 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) {
|
} else if (isLegacyAdv && event_type == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP) {
|
||||||
advertisedDevice->m_callbackSent = true;
|
advertisedDevice->m_callbackSent = true;
|
||||||
pScan->m_pAdvertisedDeviceCallbacks->onResult(advertisedDevice);
|
pScan->m_pAdvertisedDeviceCallbacks->onResult(advertisedDevice);
|
||||||
}
|
}
|
||||||
|
@ -284,7 +304,7 @@ bool NimBLEScan::isScanning() {
|
||||||
* @return True if scan started or false if there was an error.
|
* @return True if scan started or false if there was an error.
|
||||||
*/
|
*/
|
||||||
bool NimBLEScan::start(uint32_t duration, void (*scanCompleteCB)(NimBLEScanResults), bool is_continue) {
|
bool NimBLEScan::start(uint32_t duration, void (*scanCompleteCB)(NimBLEScanResults), bool is_continue) {
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> start(duration=%d)", duration);
|
NIMBLE_LOGD(LOG_TAG, ">> start: duration=%" PRIu32, duration);
|
||||||
|
|
||||||
// Save the callback to be invoked when the scan completes.
|
// Save the callback to be invoked when the scan completes.
|
||||||
m_scanCompleteCB = scanCompleteCB;
|
m_scanCompleteCB = scanCompleteCB;
|
||||||
|
@ -305,9 +325,28 @@ bool NimBLEScan::start(uint32_t duration, void (*scanCompleteCB)(NimBLEScanResul
|
||||||
m_ignoreResults = true;
|
m_ignoreResults = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rc = ble_gap_disc(NimBLEDevice::m_own_addr_type, duration, &m_scan_params,
|
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||||
NimBLEScan::handleGapEvent, this);
|
ble_gap_ext_disc_params scan_params;
|
||||||
|
scan_params.passive = m_scan_params.passive;
|
||||||
|
scan_params.itvl = m_scan_params.itvl;
|
||||||
|
scan_params.window = m_scan_params.window;
|
||||||
|
int rc = ble_gap_ext_disc(NimBLEDevice::m_own_addr_type,
|
||||||
|
duration/10,
|
||||||
|
0,
|
||||||
|
m_scan_params.filter_duplicates,
|
||||||
|
m_scan_params.filter_policy,
|
||||||
|
m_scan_params.limited,
|
||||||
|
&scan_params,
|
||||||
|
&scan_params,
|
||||||
|
NimBLEScan::handleGapEvent,
|
||||||
|
NULL);
|
||||||
|
#else
|
||||||
|
int rc = ble_gap_disc(NimBLEDevice::m_own_addr_type,
|
||||||
|
duration,
|
||||||
|
&m_scan_params,
|
||||||
|
NimBLEScan::handleGapEvent,
|
||||||
|
NULL);
|
||||||
|
#endif
|
||||||
switch(rc) {
|
switch(rc) {
|
||||||
case 0:
|
case 0:
|
||||||
if(!is_continue) {
|
if(!is_continue) {
|
||||||
|
@ -358,10 +397,15 @@ NimBLEScanResults NimBLEScan::start(uint32_t duration, bool is_continue) {
|
||||||
NIMBLE_LOGW(LOG_TAG, "Blocking scan called with duration = forever");
|
NIMBLE_LOGW(LOG_TAG, "Blocking scan called with duration = forever");
|
||||||
}
|
}
|
||||||
|
|
||||||
ble_task_data_t taskData = {nullptr, xTaskGetCurrentTaskHandle(),0, nullptr};
|
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
|
||||||
|
ble_task_data_t taskData = {nullptr, cur_task, 0, nullptr};
|
||||||
m_pTaskData = &taskData;
|
m_pTaskData = &taskData;
|
||||||
|
|
||||||
if(start(duration, nullptr, is_continue)) {
|
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);
|
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -534,5 +578,4 @@ NimBLEAdvertisedDevice *NimBLEScanResults::getDevice(const NimBLEAddress &addres
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_OBSERVER */
|
||||||
#endif /* CONFIG_BT_ENABLED */
|
|
||||||
|
|
|
@ -13,16 +13,18 @@
|
||||||
*/
|
*/
|
||||||
#ifndef COMPONENTS_NIMBLE_SCAN_H_
|
#ifndef COMPONENTS_NIMBLE_SCAN_H_
|
||||||
#define COMPONENTS_NIMBLE_SCAN_H_
|
#define COMPONENTS_NIMBLE_SCAN_H_
|
||||||
#include "sdkconfig.h"
|
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
|
||||||
|
|
||||||
#include "nimconfig.h"
|
#include "nimconfig.h"
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||||
|
|
||||||
#include "NimBLEAdvertisedDevice.h"
|
#include "NimBLEAdvertisedDevice.h"
|
||||||
#include "NimBLEUtils.h"
|
#include "NimBLEUtils.h"
|
||||||
|
|
||||||
|
#if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||||
#include "host/ble_gap.h"
|
#include "host/ble_gap.h"
|
||||||
|
#else
|
||||||
|
#include "nimble/nimble/host/include/host/ble_gap.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
@ -97,6 +99,5 @@ private:
|
||||||
uint8_t m_maxResults;
|
uint8_t m_maxResults;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
#endif /* CONFIG_BT_ENABLED CONFIG_BT_NIMBLE_ROLE_OBSERVER */
|
||||||
#endif /* CONFIG_BT_ENABLED */
|
|
||||||
#endif /* COMPONENTS_NIMBLE_SCAN_H_ */
|
#endif /* COMPONENTS_NIMBLE_SCAN_H_ */
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
* Author: chegewara
|
* Author: chegewara
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "sdkconfig.h"
|
#include "nimconfig.h"
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
#if defined(CONFIG_BT_ENABLED)
|
||||||
|
|
||||||
#include "NimBLESecurity.h"
|
#include "NimBLESecurity.h"
|
||||||
|
|
|
@ -14,10 +14,16 @@
|
||||||
|
|
||||||
#ifndef COMPONENTS_NIMBLESECURITY_H_
|
#ifndef COMPONENTS_NIMBLESECURITY_H_
|
||||||
#define COMPONENTS_NIMBLESECURITY_H_
|
#define COMPONENTS_NIMBLESECURITY_H_
|
||||||
#include "sdkconfig.h"
|
|
||||||
|
#include "nimconfig.h"
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
#if defined(CONFIG_BT_ENABLED)
|
||||||
|
|
||||||
|
#if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||||
#include "host/ble_gap.h"
|
#include "host/ble_gap.h"
|
||||||
|
#else
|
||||||
|
#include "nimble/nimble/host/include/host/ble_gap.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
/**** FIX COMPILATION ****/
|
/**** FIX COMPILATION ****/
|
||||||
#undef min
|
#undef min
|
||||||
#undef max
|
#undef max
|
||||||
|
|
|
@ -12,19 +12,20 @@
|
||||||
* Author: kolban
|
* Author: kolban
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "sdkconfig.h"
|
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
|
||||||
|
|
||||||
#include "nimconfig.h"
|
#include "nimconfig.h"
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||||
|
|
||||||
#include "NimBLEServer.h"
|
#include "NimBLEServer.h"
|
||||||
#include "NimBLEDevice.h"
|
#include "NimBLEDevice.h"
|
||||||
#include "NimBLELog.h"
|
#include "NimBLELog.h"
|
||||||
|
|
||||||
|
#if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||||
#include "services/gap/ble_svc_gap.h"
|
#include "services/gap/ble_svc_gap.h"
|
||||||
#include "services/gatt/ble_svc_gatt.h"
|
#include "services/gatt/ble_svc_gatt.h"
|
||||||
|
#else
|
||||||
|
#include "nimble/nimble/host/services/gap/include/services/gap/ble_svc_gap.h"
|
||||||
|
#include "nimble/nimble/host/services/gatt/include/services/gatt/ble_svc_gatt.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
static const char* LOG_TAG = "NimBLEServer";
|
static const char* LOG_TAG = "NimBLEServer";
|
||||||
static NimBLEServerCallbacks defaultCallbacks;
|
static NimBLEServerCallbacks defaultCallbacks;
|
||||||
|
@ -41,7 +42,9 @@ NimBLEServer::NimBLEServer() {
|
||||||
// m_svcChgChrHdl = 0xffff; // Future Use
|
// m_svcChgChrHdl = 0xffff; // Future Use
|
||||||
m_pServerCallbacks = &defaultCallbacks;
|
m_pServerCallbacks = &defaultCallbacks;
|
||||||
m_gattsStarted = false;
|
m_gattsStarted = false;
|
||||||
|
#if !CONFIG_BT_NIMBLE_EXT_ADV
|
||||||
m_advertiseOnDisconnect = true;
|
m_advertiseOnDisconnect = true;
|
||||||
|
#endif
|
||||||
m_svcChanged = false;
|
m_svcChanged = false;
|
||||||
m_deleteCallbacks = true;
|
m_deleteCallbacks = true;
|
||||||
} // NimBLEServer
|
} // NimBLEServer
|
||||||
|
@ -74,23 +77,19 @@ NimBLEService* NimBLEServer::createService(const char* uuid) {
|
||||||
/**
|
/**
|
||||||
* @brief Create a %BLE Service.
|
* @brief Create a %BLE Service.
|
||||||
* @param [in] uuid The UUID of the new service.
|
* @param [in] uuid The UUID of the new service.
|
||||||
* @param [in] numHandles The maximum number of handles associated with this service.
|
|
||||||
* @param [in] inst_id if we have multiple services with the same UUID we need
|
|
||||||
* to provide inst_id value different for each service.
|
|
||||||
* @return A reference to the new service object.
|
* @return A reference to the new service object.
|
||||||
*/
|
*/
|
||||||
NimBLEService* NimBLEServer::createService(const NimBLEUUID &uuid, uint32_t numHandles, uint8_t inst_id) {
|
NimBLEService* NimBLEServer::createService(const NimBLEUUID &uuid) {
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> createService - %s", uuid.toString().c_str());
|
NIMBLE_LOGD(LOG_TAG, ">> createService - %s", uuid.toString().c_str());
|
||||||
// TODO: add functionality to use inst_id for multiple services with same uuid
|
|
||||||
(void)inst_id;
|
|
||||||
// Check that a service with the supplied UUID does not already exist.
|
// Check that a service with the supplied UUID does not already exist.
|
||||||
if(getServiceByUUID(uuid) != nullptr) {
|
if(getServiceByUUID(uuid) != nullptr) {
|
||||||
NIMBLE_LOGW(LOG_TAG, "Warning creating a duplicate service UUID: %s",
|
NIMBLE_LOGW(LOG_TAG, "Warning creating a duplicate service UUID: %s",
|
||||||
std::string(uuid).c_str());
|
std::string(uuid).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
NimBLEService* pService = new NimBLEService(uuid, numHandles, this);
|
NimBLEService* pService = new NimBLEService(uuid);
|
||||||
m_svcVec.push_back(pService); // Save a reference to this service being on this server.
|
m_svcVec.push_back(pService);
|
||||||
serviceChanged();
|
serviceChanged();
|
||||||
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< createService");
|
NIMBLE_LOGD(LOG_TAG, "<< createService");
|
||||||
|
@ -142,15 +141,26 @@ NimBLEService *NimBLEServer::getServiceByHandle(uint16_t handle) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if CONFIG_BT_NIMBLE_EXT_ADV
|
||||||
|
/**
|
||||||
|
* @brief Retrieve the advertising object that can be used to advertise the existence of the server.
|
||||||
|
* @return An advertising object.
|
||||||
|
*/
|
||||||
|
NimBLEExtAdvertising* NimBLEServer::getAdvertising() {
|
||||||
|
return NimBLEDevice::getAdvertising();
|
||||||
|
} // getAdvertising
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_)
|
||||||
/**
|
/**
|
||||||
* @brief Retrieve the advertising object that can be used to advertise the existence of the server.
|
* @brief Retrieve the advertising object that can be used to advertise the existence of the server.
|
||||||
*
|
|
||||||
* @return An advertising object.
|
* @return An advertising object.
|
||||||
*/
|
*/
|
||||||
NimBLEAdvertising* NimBLEServer::getAdvertising() {
|
NimBLEAdvertising* NimBLEServer::getAdvertising() {
|
||||||
return NimBLEDevice::getAdvertising();
|
return NimBLEDevice::getAdvertising();
|
||||||
} // getAdvertising
|
} // getAdvertising
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sends a service changed notification and resets the GATT server.
|
* @brief Sends a service changed notification and resets the GATT server.
|
||||||
|
@ -181,7 +191,7 @@ void NimBLEServer::start() {
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if CONFIG_LOG_DEFAULT_LEVEL > 3 || (ARDUINO_ARCH_ESP32 && CORE_DEBUG_LEVEL >= 4)
|
#if CONFIG_NIMBLE_CPP_LOG_LEVEL >= 4
|
||||||
ble_gatts_show_local();
|
ble_gatts_show_local();
|
||||||
#endif
|
#endif
|
||||||
/*** Future use ***
|
/*** Future use ***
|
||||||
|
@ -243,6 +253,7 @@ int NimBLEServer::disconnect(uint16_t connId, uint8_t reason) {
|
||||||
} // disconnect
|
} // disconnect
|
||||||
|
|
||||||
|
|
||||||
|
#if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_)
|
||||||
/**
|
/**
|
||||||
* @brief Set the server to automatically start advertising when a client disconnects.
|
* @brief Set the server to automatically start advertising when a client disconnects.
|
||||||
* @param [in] aod true == advertise, false == don't advertise.
|
* @param [in] aod true == advertise, false == don't advertise.
|
||||||
|
@ -250,7 +261,7 @@ int NimBLEServer::disconnect(uint16_t connId, uint8_t reason) {
|
||||||
void NimBLEServer::advertiseOnDisconnect(bool aod) {
|
void NimBLEServer::advertiseOnDisconnect(bool aod) {
|
||||||
m_advertiseOnDisconnect = aod;
|
m_advertiseOnDisconnect = aod;
|
||||||
} // advertiseOnDisconnect
|
} // advertiseOnDisconnect
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return the number of connected clients.
|
* @brief Return the number of connected clients.
|
||||||
|
@ -326,8 +337,9 @@ NimBLEConnInfo NimBLEServer::getPeerIDInfo(uint16_t id) {
|
||||||
* @param [in] param
|
* @param [in] param
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
/*STATIC*/int NimBLEServer::handleGapEvent(struct ble_gap_event *event, void *arg) {
|
/*STATIC*/
|
||||||
NimBLEServer* server = (NimBLEServer*)arg;
|
int NimBLEServer::handleGapEvent(struct ble_gap_event *event, void *arg) {
|
||||||
|
NimBLEServer* server = NimBLEDevice::getServer();
|
||||||
NIMBLE_LOGD(LOG_TAG, ">> handleGapEvent: %s",
|
NIMBLE_LOGD(LOG_TAG, ">> handleGapEvent: %s",
|
||||||
NimBLEUtils::gapEventToString(event->type));
|
NimBLEUtils::gapEventToString(event->type));
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
@ -339,7 +351,9 @@ NimBLEConnInfo NimBLEServer::getPeerIDInfo(uint16_t id) {
|
||||||
if (event->connect.status != 0) {
|
if (event->connect.status != 0) {
|
||||||
/* Connection failed; resume advertising */
|
/* Connection failed; resume advertising */
|
||||||
NIMBLE_LOGE(LOG_TAG, "Connection failed");
|
NIMBLE_LOGE(LOG_TAG, "Connection failed");
|
||||||
|
#if !CONFIG_BT_NIMBLE_EXT_ADV
|
||||||
NimBLEDevice::startAdvertising();
|
NimBLEDevice::startAdvertising();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
server->m_connectedPeersVec.push_back(event->connect.conn_handle);
|
server->m_connectedPeersVec.push_back(event->connect.conn_handle);
|
||||||
|
@ -384,9 +398,11 @@ NimBLEConnInfo NimBLEServer::getPeerIDInfo(uint16_t id) {
|
||||||
server->m_pServerCallbacks->onDisconnect(server);
|
server->m_pServerCallbacks->onDisconnect(server);
|
||||||
server->m_pServerCallbacks->onDisconnect(server, &event->disconnect.conn);
|
server->m_pServerCallbacks->onDisconnect(server, &event->disconnect.conn);
|
||||||
|
|
||||||
|
#if !CONFIG_BT_NIMBLE_EXT_ADV
|
||||||
if(server->m_advertiseOnDisconnect) {
|
if(server->m_advertiseOnDisconnect) {
|
||||||
server->startAdvertising();
|
server->startAdvertising();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
} // BLE_GAP_EVENT_DISCONNECT
|
} // BLE_GAP_EVENT_DISCONNECT
|
||||||
|
|
||||||
|
@ -474,11 +490,15 @@ NimBLEConnInfo NimBLEServer::getPeerIDInfo(uint16_t id) {
|
||||||
return 0;
|
return 0;
|
||||||
} // BLE_GAP_EVENT_NOTIFY_TX
|
} // BLE_GAP_EVENT_NOTIFY_TX
|
||||||
|
|
||||||
case BLE_GAP_EVENT_ADV_COMPLETE: {
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "Advertising Complete");
|
case BLE_GAP_EVENT_ADV_COMPLETE:
|
||||||
NimBLEDevice::getAdvertising()->advCompleteCB();
|
#if CONFIG_BT_NIMBLE_EXT_ADV
|
||||||
return 0;
|
case BLE_GAP_EVENT_SCAN_REQ_RCVD:
|
||||||
}
|
return NimBLEExtAdvertising::handleGapEvent(event, arg);
|
||||||
|
#else
|
||||||
|
return NimBLEAdvertising::handleGapEvent(event, arg);
|
||||||
|
#endif
|
||||||
|
// BLE_GAP_EVENT_ADV_COMPLETE | BLE_GAP_EVENT_SCAN_REQ_RCVD
|
||||||
|
|
||||||
case BLE_GAP_EVENT_CONN_UPDATE: {
|
case BLE_GAP_EVENT_CONN_UPDATE: {
|
||||||
NIMBLE_LOGD(LOG_TAG, "Connection parameters updated.");
|
NIMBLE_LOGD(LOG_TAG, "Connection parameters updated.");
|
||||||
|
@ -537,7 +557,7 @@ NimBLEConnInfo NimBLEServer::getPeerIDInfo(uint16_t id) {
|
||||||
NIMBLE_LOGD(LOG_TAG, "BLE_SM_IOACT_DISP; ble_sm_inject_io result: %d", rc);
|
NIMBLE_LOGD(LOG_TAG, "BLE_SM_IOACT_DISP; ble_sm_inject_io result: %d", rc);
|
||||||
|
|
||||||
} else if (event->passkey.params.action == BLE_SM_IOACT_NUMCMP) {
|
} else if (event->passkey.params.action == BLE_SM_IOACT_NUMCMP) {
|
||||||
NIMBLE_LOGD(LOG_TAG, "Passkey on device's display: %d", event->passkey.params.numcmp);
|
NIMBLE_LOGD(LOG_TAG, "Passkey on device's display: %" PRIu32, event->passkey.params.numcmp);
|
||||||
pkey.action = event->passkey.params.action;
|
pkey.action = event->passkey.params.action;
|
||||||
// Compatibility only - Do not use, should be removed the in future
|
// Compatibility only - Do not use, should be removed the in future
|
||||||
if(NimBLEDevice::m_securityCallbacks != nullptr) {
|
if(NimBLEDevice::m_securityCallbacks != nullptr) {
|
||||||
|
@ -655,7 +675,9 @@ void NimBLEServer::removeService(NimBLEService* service, bool deleteSvc) {
|
||||||
|
|
||||||
service->m_removed = deleteSvc ? NIMBLE_ATT_REMOVE_DELETE : NIMBLE_ATT_REMOVE_HIDE;
|
service->m_removed = deleteSvc ? NIMBLE_ATT_REMOVE_DELETE : NIMBLE_ATT_REMOVE_HIDE;
|
||||||
serviceChanged();
|
serviceChanged();
|
||||||
|
#if !CONFIG_BT_NIMBLE_EXT_ADV
|
||||||
NimBLEDevice::getAdvertising()->removeServiceUUID(service->getUUID());
|
NimBLEDevice::getAdvertising()->removeServiceUUID(service->getUUID());
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -718,23 +740,53 @@ void NimBLEServer::resetGATT() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if CONFIG_BT_NIMBLE_EXT_ADV
|
||||||
/**
|
/**
|
||||||
* @brief Start advertising.
|
* @brief Start advertising.
|
||||||
*
|
* @param [in] inst_id The extended advertisement instance ID to start.
|
||||||
* Start the server advertising its existence. This is a convenience function and is equivalent to
|
* @param [in] duration How long to advertise for in milliseconds, 0 = forever (default).
|
||||||
|
* @param [in] max_events Maximum number of advertisement events to send, 0 = no limit (default).
|
||||||
|
* @return True if advertising started successfully.
|
||||||
|
* @details Start the server advertising its existence. This is a convenience function and is equivalent to
|
||||||
* retrieving the advertising object and invoking start upon it.
|
* retrieving the advertising object and invoking start upon it.
|
||||||
*/
|
*/
|
||||||
void NimBLEServer::startAdvertising() {
|
bool NimBLEServer::startAdvertising(uint8_t inst_id,
|
||||||
NimBLEDevice::startAdvertising();
|
int duration,
|
||||||
|
int max_events) {
|
||||||
|
return getAdvertising()->start(inst_id, duration, max_events);
|
||||||
} // startAdvertising
|
} // startAdvertising
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Convenience function to stop advertising a data set.
|
||||||
|
* @param [in] inst_id The extended advertisement instance ID to stop advertising.
|
||||||
|
* @return True if advertising stopped successfully.
|
||||||
|
*/
|
||||||
|
bool NimBLEServer::stopAdvertising(uint8_t inst_id) {
|
||||||
|
return getAdvertising()->stop(inst_id);
|
||||||
|
} // stopAdvertising
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !CONFIG_BT_NIMBLE_EXT_ADV|| defined(_DOXYGEN_)
|
||||||
|
/**
|
||||||
|
* @brief Start advertising.
|
||||||
|
* @return True if advertising started successfully.
|
||||||
|
* @details Start the server advertising its existence. This is a convenience function and is equivalent to
|
||||||
|
* retrieving the advertising object and invoking start upon it.
|
||||||
|
*/
|
||||||
|
bool NimBLEServer::startAdvertising() {
|
||||||
|
return getAdvertising()->start();
|
||||||
|
} // startAdvertising
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Stop advertising.
|
* @brief Stop advertising.
|
||||||
|
* @return True if advertising stopped successfully.
|
||||||
*/
|
*/
|
||||||
void NimBLEServer::stopAdvertising() {
|
bool NimBLEServer::stopAdvertising() {
|
||||||
NimBLEDevice::stopAdvertising();
|
return getAdvertising()->stop();
|
||||||
} // startAdvertising
|
} // stopAdvertising
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -775,6 +827,30 @@ void NimBLEServer::updateConnParams(uint16_t conn_handle,
|
||||||
} // updateConnParams
|
} // updateConnParams
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Request an update of the data packet length.
|
||||||
|
* * Can only be used after a connection has been established.
|
||||||
|
* @details Sends a data length update request to the peer.
|
||||||
|
* The Data Length Extension (DLE) allows to increase the Data Channel Payload from 27 bytes to up to 251 bytes.
|
||||||
|
* The peer needs to support the Bluetooth 4.2 specifications, to be capable of DLE.
|
||||||
|
* @param [in] conn_handle The connection handle of the peer to send the request to.
|
||||||
|
* @param [in] tx_octets The preferred number of payload octets to use (Range 0x001B-0x00FB).
|
||||||
|
*/
|
||||||
|
void NimBLEServer::setDataLen(uint16_t conn_handle, uint16_t tx_octets) {
|
||||||
|
#if defined(CONFIG_NIMBLE_CPP_IDF) && !defined(ESP_IDF_VERSION) || \
|
||||||
|
(ESP_IDF_VERSION_MAJOR * 100 + ESP_IDF_VERSION_MINOR * 10 + ESP_IDF_VERSION_PATCH) < 432
|
||||||
|
return;
|
||||||
|
#else
|
||||||
|
uint16_t tx_time = (tx_octets + 14) * 8;
|
||||||
|
|
||||||
|
int rc = ble_gap_set_data_len(conn_handle, tx_octets, tx_time);
|
||||||
|
if(rc != 0) {
|
||||||
|
NIMBLE_LOGE(LOG_TAG, "Set data length error: %d, %s", rc, NimBLEUtils::returnCodeToString(rc));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} // setDataLen
|
||||||
|
|
||||||
|
|
||||||
bool NimBLEServer::setIndicateWait(uint16_t conn_handle) {
|
bool NimBLEServer::setIndicateWait(uint16_t conn_handle) {
|
||||||
for(auto i = 0; i < CONFIG_BT_NIMBLE_MAX_CONNECTIONS; i++) {
|
for(auto i = 0; i < CONFIG_BT_NIMBLE_MAX_CONNECTIONS; i++) {
|
||||||
if(m_indWait[i] == conn_handle) {
|
if(m_indWait[i] == conn_handle) {
|
||||||
|
@ -842,6 +918,4 @@ bool NimBLEServerCallbacks::onConfirmPIN(uint32_t pin){
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
|
||||||
#endif // CONFIG_BT_ENABLED
|
|
||||||
|
|
|
@ -14,18 +14,22 @@
|
||||||
|
|
||||||
#ifndef MAIN_NIMBLESERVER_H_
|
#ifndef MAIN_NIMBLESERVER_H_
|
||||||
#define MAIN_NIMBLESERVER_H_
|
#define MAIN_NIMBLESERVER_H_
|
||||||
#include "sdkconfig.h"
|
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
|
||||||
|
|
||||||
#include "nimconfig.h"
|
#include "nimconfig.h"
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||||
|
|
||||||
#define NIMBLE_ATT_REMOVE_HIDE 1
|
#define NIMBLE_ATT_REMOVE_HIDE 1
|
||||||
#define NIMBLE_ATT_REMOVE_DELETE 2
|
#define NIMBLE_ATT_REMOVE_DELETE 2
|
||||||
|
|
||||||
|
#define onMtuChanged onMTUChange
|
||||||
|
|
||||||
#include "NimBLEUtils.h"
|
#include "NimBLEUtils.h"
|
||||||
#include "NimBLEAddress.h"
|
#include "NimBLEAddress.h"
|
||||||
|
#if CONFIG_BT_NIMBLE_EXT_ADV
|
||||||
|
#include "NimBLEExtAdvertising.h"
|
||||||
|
#else
|
||||||
#include "NimBLEAdvertising.h"
|
#include "NimBLEAdvertising.h"
|
||||||
|
#endif
|
||||||
#include "NimBLEService.h"
|
#include "NimBLEService.h"
|
||||||
#include "NimBLESecurity.h"
|
#include "NimBLESecurity.h"
|
||||||
#include "NimBLEConnInfo.h"
|
#include "NimBLEConnInfo.h"
|
||||||
|
@ -43,15 +47,22 @@ class NimBLEServer {
|
||||||
public:
|
public:
|
||||||
size_t getConnectedCount();
|
size_t getConnectedCount();
|
||||||
NimBLEService* createService(const char* uuid);
|
NimBLEService* createService(const char* uuid);
|
||||||
NimBLEService* createService(const NimBLEUUID &uuid, uint32_t numHandles=15,
|
NimBLEService* createService(const NimBLEUUID &uuid);
|
||||||
uint8_t inst_id=0);
|
|
||||||
void removeService(NimBLEService* service, bool deleteSvc = false);
|
void removeService(NimBLEService* service, bool deleteSvc = false);
|
||||||
void addService(NimBLEService* service);
|
void addService(NimBLEService* service);
|
||||||
NimBLEAdvertising* getAdvertising();
|
|
||||||
void setCallbacks(NimBLEServerCallbacks* pCallbacks,
|
void setCallbacks(NimBLEServerCallbacks* pCallbacks,
|
||||||
bool deleteCallbacks = true);
|
bool deleteCallbacks = true);
|
||||||
void startAdvertising();
|
#if CONFIG_BT_NIMBLE_EXT_ADV
|
||||||
void stopAdvertising();
|
NimBLEExtAdvertising* getAdvertising();
|
||||||
|
bool startAdvertising(uint8_t inst_id,
|
||||||
|
int duration = 0,
|
||||||
|
int max_events = 0);
|
||||||
|
bool stopAdvertising(uint8_t inst_id);
|
||||||
|
#else
|
||||||
|
NimBLEAdvertising* getAdvertising();
|
||||||
|
bool startAdvertising();
|
||||||
|
#endif
|
||||||
|
bool stopAdvertising();
|
||||||
void start();
|
void start();
|
||||||
NimBLEService* getServiceByUUID(const char* uuid, uint16_t instanceId = 0);
|
NimBLEService* getServiceByUUID(const char* uuid, uint16_t instanceId = 0);
|
||||||
NimBLEService* getServiceByUUID(const NimBLEUUID &uuid, uint16_t instanceId = 0);
|
NimBLEService* getServiceByUUID(const NimBLEUUID &uuid, uint16_t instanceId = 0);
|
||||||
|
@ -61,12 +72,15 @@ public:
|
||||||
void updateConnParams(uint16_t conn_handle,
|
void updateConnParams(uint16_t conn_handle,
|
||||||
uint16_t minInterval, uint16_t maxInterval,
|
uint16_t minInterval, uint16_t maxInterval,
|
||||||
uint16_t latency, uint16_t timeout);
|
uint16_t latency, uint16_t timeout);
|
||||||
|
void setDataLen(uint16_t conn_handle, uint16_t tx_octets);
|
||||||
uint16_t getPeerMTU(uint16_t conn_id);
|
uint16_t getPeerMTU(uint16_t conn_id);
|
||||||
std::vector<uint16_t> getPeerDevices();
|
std::vector<uint16_t> getPeerDevices();
|
||||||
NimBLEConnInfo getPeerInfo(size_t index);
|
NimBLEConnInfo getPeerInfo(size_t index);
|
||||||
NimBLEConnInfo getPeerInfo(const NimBLEAddress& address);
|
NimBLEConnInfo getPeerInfo(const NimBLEAddress& address);
|
||||||
NimBLEConnInfo getPeerIDInfo(uint16_t id);
|
NimBLEConnInfo getPeerIDInfo(uint16_t id);
|
||||||
|
#if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_)
|
||||||
void advertiseOnDisconnect(bool);
|
void advertiseOnDisconnect(bool);
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NimBLEServer();
|
NimBLEServer();
|
||||||
|
@ -75,9 +89,15 @@ private:
|
||||||
friend class NimBLEService;
|
friend class NimBLEService;
|
||||||
friend class NimBLEDevice;
|
friend class NimBLEDevice;
|
||||||
friend class NimBLEAdvertising;
|
friend class NimBLEAdvertising;
|
||||||
|
#if CONFIG_BT_NIMBLE_EXT_ADV
|
||||||
|
friend class NimBLEExtAdvertising;
|
||||||
|
friend class NimBLEExtAdvertisementData;
|
||||||
|
#endif
|
||||||
|
|
||||||
bool m_gattsStarted;
|
bool m_gattsStarted;
|
||||||
|
#if !CONFIG_BT_NIMBLE_EXT_ADV
|
||||||
bool m_advertiseOnDisconnect;
|
bool m_advertiseOnDisconnect;
|
||||||
|
#endif
|
||||||
bool m_svcChanged;
|
bool m_svcChanged;
|
||||||
NimBLEServerCallbacks* m_pServerCallbacks;
|
NimBLEServerCallbacks* m_pServerCallbacks;
|
||||||
bool m_deleteCallbacks;
|
bool m_deleteCallbacks;
|
||||||
|
@ -168,7 +188,5 @@ public:
|
||||||
virtual bool onConfirmPIN(uint32_t pin);
|
virtual bool onConfirmPIN(uint32_t pin);
|
||||||
}; // NimBLEServerCallbacks
|
}; // NimBLEServerCallbacks
|
||||||
|
|
||||||
|
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
|
||||||
#endif /* CONFIG_BT_ENABLED */
|
|
||||||
#endif /* MAIN_NIMBLESERVER_H_ */
|
#endif /* MAIN_NIMBLESERVER_H_ */
|
||||||
|
|
|
@ -14,12 +14,10 @@
|
||||||
|
|
||||||
// A service is identified by a UUID. A service is also the container for one or more characteristics.
|
// A service is identified by a UUID. A service is also the container for one or more characteristics.
|
||||||
|
|
||||||
#include "sdkconfig.h"
|
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
|
||||||
|
|
||||||
#include "nimconfig.h"
|
#include "nimconfig.h"
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||||
|
|
||||||
|
#include "NimBLEDevice.h"
|
||||||
#include "NimBLEService.h"
|
#include "NimBLEService.h"
|
||||||
#include "NimBLEUtils.h"
|
#include "NimBLEUtils.h"
|
||||||
#include "NimBLELog.h"
|
#include "NimBLELog.h"
|
||||||
|
@ -34,25 +32,19 @@ static const char* LOG_TAG = "NimBLEService"; // Tag for logging.
|
||||||
/**
|
/**
|
||||||
* @brief Construct an instance of the NimBLEService
|
* @brief Construct an instance of the NimBLEService
|
||||||
* @param [in] uuid The UUID of the service.
|
* @param [in] uuid The UUID of the service.
|
||||||
* @param [in] numHandles The maximum number of handles associated with the service.
|
|
||||||
* @param [in] pServer A pointer to the server instance that this service belongs to.
|
|
||||||
*/
|
*/
|
||||||
NimBLEService::NimBLEService(const char* uuid, uint16_t numHandles, NimBLEServer* pServer)
|
NimBLEService::NimBLEService(const char* uuid)
|
||||||
: NimBLEService(NimBLEUUID(uuid), numHandles, pServer) {
|
: NimBLEService(NimBLEUUID(uuid)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Construct an instance of the BLEService
|
* @brief Construct an instance of the BLEService
|
||||||
* @param [in] uuid The UUID of the service.
|
* @param [in] uuid The UUID of the service.
|
||||||
* @param [in] numHandles The maximum number of handles associated with the service.
|
|
||||||
* @param [in] pServer A pointer to the server instance that this service belongs to.
|
|
||||||
*/
|
*/
|
||||||
NimBLEService::NimBLEService(const NimBLEUUID &uuid, uint16_t numHandles, NimBLEServer* pServer) {
|
NimBLEService::NimBLEService(const NimBLEUUID &uuid) {
|
||||||
m_uuid = uuid;
|
m_uuid = uuid;
|
||||||
m_handle = NULL_HANDLE;
|
m_handle = NULL_HANDLE;
|
||||||
m_pServer = pServer;
|
|
||||||
m_numHandles = numHandles;
|
|
||||||
m_pSvcDef = nullptr;
|
m_pSvcDef = nullptr;
|
||||||
m_removed = 0;
|
m_removed = 0;
|
||||||
|
|
||||||
|
@ -121,6 +113,12 @@ bool NimBLEService::start() {
|
||||||
|
|
||||||
// Rebuild the service definition if the server attributes have changed.
|
// Rebuild the service definition if the server attributes have changed.
|
||||||
if(getServer()->m_svcChanged && m_pSvcDef != nullptr) {
|
if(getServer()->m_svcChanged && m_pSvcDef != nullptr) {
|
||||||
|
if(m_pSvcDef[0].characteristics) {
|
||||||
|
if(m_pSvcDef[0].characteristics[0].descriptors) {
|
||||||
|
delete(m_pSvcDef[0].characteristics[0].descriptors);
|
||||||
|
}
|
||||||
|
delete(m_pSvcDef[0].characteristics);
|
||||||
|
}
|
||||||
delete(m_pSvcDef);
|
delete(m_pSvcDef);
|
||||||
m_pSvcDef = nullptr;
|
m_pSvcDef = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -258,10 +256,11 @@ uint16_t NimBLEService::getHandle() {
|
||||||
* @brief Create a new BLE Characteristic associated with this service.
|
* @brief Create a new BLE Characteristic associated with this service.
|
||||||
* @param [in] uuid - The UUID of the characteristic.
|
* @param [in] uuid - The UUID of the characteristic.
|
||||||
* @param [in] properties - The properties of the characteristic.
|
* @param [in] properties - The properties of the characteristic.
|
||||||
|
* @param [in] max_len - The maximum length in bytes that the characteristic value can hold.
|
||||||
* @return The new BLE characteristic.
|
* @return The new BLE characteristic.
|
||||||
*/
|
*/
|
||||||
NimBLECharacteristic* NimBLEService::createCharacteristic(const char* uuid, uint32_t properties) {
|
NimBLECharacteristic* NimBLEService::createCharacteristic(const char* uuid, uint32_t properties, uint16_t max_len) {
|
||||||
return createCharacteristic(NimBLEUUID(uuid), properties);
|
return createCharacteristic(NimBLEUUID(uuid), properties, max_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -269,10 +268,11 @@ NimBLECharacteristic* NimBLEService::createCharacteristic(const char* uuid, uint
|
||||||
* @brief Create a new BLE Characteristic associated with this service.
|
* @brief Create a new BLE Characteristic associated with this service.
|
||||||
* @param [in] uuid - The UUID of the characteristic.
|
* @param [in] uuid - The UUID of the characteristic.
|
||||||
* @param [in] properties - The properties of the characteristic.
|
* @param [in] properties - The properties of the characteristic.
|
||||||
|
* @param [in] max_len - The maximum length in bytes that the characteristic value can hold.
|
||||||
* @return The new BLE characteristic.
|
* @return The new BLE characteristic.
|
||||||
*/
|
*/
|
||||||
NimBLECharacteristic* NimBLEService::createCharacteristic(const NimBLEUUID &uuid, uint32_t properties) {
|
NimBLECharacteristic* NimBLEService::createCharacteristic(const NimBLEUUID &uuid, uint32_t properties, uint16_t max_len) {
|
||||||
NimBLECharacteristic* pCharacteristic = new NimBLECharacteristic(uuid, properties, this);
|
NimBLECharacteristic* pCharacteristic = new NimBLECharacteristic(uuid, properties, max_len, this);
|
||||||
|
|
||||||
if (getCharacteristic(uuid) != nullptr) {
|
if (getCharacteristic(uuid) != nullptr) {
|
||||||
NIMBLE_LOGD(LOG_TAG, "<< Adding a duplicate characteristic with UUID: %s",
|
NIMBLE_LOGD(LOG_TAG, "<< Adding a duplicate characteristic with UUID: %s",
|
||||||
|
@ -429,8 +429,7 @@ std::string NimBLEService::toString() {
|
||||||
* @return The BLEServer associated with this service.
|
* @return The BLEServer associated with this service.
|
||||||
*/
|
*/
|
||||||
NimBLEServer* NimBLEService::getServer() {
|
NimBLEServer* NimBLEService::getServer() {
|
||||||
return m_pServer;
|
return NimBLEDevice::getServer();
|
||||||
}// getServer
|
}// getServer
|
||||||
|
|
||||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||||
#endif // CONFIG_BT_ENABLED
|
|
||||||
|
|
|
@ -14,11 +14,9 @@
|
||||||
|
|
||||||
#ifndef MAIN_NIMBLESERVICE_H_
|
#ifndef MAIN_NIMBLESERVICE_H_
|
||||||
#define MAIN_NIMBLESERVICE_H_
|
#define MAIN_NIMBLESERVICE_H_
|
||||||
#include "sdkconfig.h"
|
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
|
||||||
|
|
||||||
#include "nimconfig.h"
|
#include "nimconfig.h"
|
||||||
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||||
|
|
||||||
#include "NimBLEServer.h"
|
#include "NimBLEServer.h"
|
||||||
#include "NimBLECharacteristic.h"
|
#include "NimBLECharacteristic.h"
|
||||||
|
@ -36,8 +34,8 @@ class NimBLECharacteristic;
|
||||||
class NimBLEService {
|
class NimBLEService {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
NimBLEService(const char* uuid, uint16_t numHandles, NimBLEServer* pServer);
|
NimBLEService(const char* uuid);
|
||||||
NimBLEService(const NimBLEUUID &uuid, uint16_t numHandles, NimBLEServer* pServer);
|
NimBLEService(const NimBLEUUID &uuid);
|
||||||
~NimBLEService();
|
~NimBLEService();
|
||||||
|
|
||||||
NimBLEServer* getServer();
|
NimBLEServer* getServer();
|
||||||
|
@ -52,12 +50,14 @@ public:
|
||||||
NimBLECharacteristic* createCharacteristic(const char* uuid,
|
NimBLECharacteristic* createCharacteristic(const char* uuid,
|
||||||
uint32_t properties =
|
uint32_t properties =
|
||||||
NIMBLE_PROPERTY::READ |
|
NIMBLE_PROPERTY::READ |
|
||||||
NIMBLE_PROPERTY::WRITE);
|
NIMBLE_PROPERTY::WRITE,
|
||||||
|
uint16_t max_len = BLE_ATT_ATTR_MAX_LEN);
|
||||||
|
|
||||||
NimBLECharacteristic* createCharacteristic(const NimBLEUUID &uuid,
|
NimBLECharacteristic* createCharacteristic(const NimBLEUUID &uuid,
|
||||||
uint32_t properties =
|
uint32_t properties =
|
||||||
NIMBLE_PROPERTY::READ |
|
NIMBLE_PROPERTY::READ |
|
||||||
NIMBLE_PROPERTY::WRITE);
|
NIMBLE_PROPERTY::WRITE,
|
||||||
|
uint16_t max_len = BLE_ATT_ATTR_MAX_LEN);
|
||||||
|
|
||||||
void addCharacteristic(NimBLECharacteristic* pCharacteristic);
|
void addCharacteristic(NimBLECharacteristic* pCharacteristic);
|
||||||
void removeCharacteristic(NimBLECharacteristic* pCharacteristic, bool deleteChr = false);
|
void removeCharacteristic(NimBLECharacteristic* pCharacteristic, bool deleteChr = false);
|
||||||
|
@ -76,16 +76,12 @@ private:
|
||||||
friend class NimBLEDevice;
|
friend class NimBLEDevice;
|
||||||
|
|
||||||
uint16_t m_handle;
|
uint16_t m_handle;
|
||||||
NimBLEServer* m_pServer;
|
|
||||||
NimBLEUUID m_uuid;
|
NimBLEUUID m_uuid;
|
||||||
uint16_t m_numHandles;
|
|
||||||
ble_gatt_svc_def* m_pSvcDef;
|
ble_gatt_svc_def* m_pSvcDef;
|
||||||
uint8_t m_removed;
|
uint8_t m_removed;
|
||||||
std::vector<NimBLECharacteristic*> m_chrVec;
|
std::vector<NimBLECharacteristic*> m_chrVec;
|
||||||
|
|
||||||
}; // NimBLEService
|
}; // NimBLEService
|
||||||
|
|
||||||
|
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
|
||||||
#endif // CONFIG_BT_ENABLED
|
|
||||||
#endif /* MAIN_NIMBLESERVICE_H_ */
|
#endif /* MAIN_NIMBLESERVICE_H_ */
|
||||||
|
|
|
@ -11,7 +11,8 @@
|
||||||
* Created on: Jun 21, 2017
|
* Created on: Jun 21, 2017
|
||||||
* Author: kolban
|
* Author: kolban
|
||||||
*/
|
*/
|
||||||
#include "sdkconfig.h"
|
|
||||||
|
#include "nimconfig.h"
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
#if defined(CONFIG_BT_ENABLED)
|
||||||
|
|
||||||
#include "NimBLEUtils.h"
|
#include "NimBLEUtils.h"
|
||||||
|
@ -234,8 +235,8 @@ const ble_uuid_any_t* NimBLEUUID::getNative() const {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Convert a UUID to its 128 bit representation.
|
* @brief Convert a UUID to its 128 bit representation.
|
||||||
* @details A UUID can be internally represented as 16bit, 32bit or the full 128bit. This method
|
* @details A UUID can be internally represented as 16bit, 32bit or the full 128bit.
|
||||||
* will convert 16 or 32 bit representations to the full 128bit.
|
* This method will convert 16 or 32bit representations to the full 128bit.
|
||||||
* @return The NimBLEUUID converted to 128bit.
|
* @return The NimBLEUUID converted to 128bit.
|
||||||
*/
|
*/
|
||||||
const NimBLEUUID &NimBLEUUID::to128() {
|
const NimBLEUUID &NimBLEUUID::to128() {
|
||||||
|
@ -256,6 +257,29 @@ const NimBLEUUID &NimBLEUUID::to128() {
|
||||||
} // to128
|
} // to128
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Convert 128 bit UUID to its 16 bit representation.
|
||||||
|
* @details A UUID can be internally represented as 16bit, 32bit or the full 128bit.
|
||||||
|
* This method will convert a 128bit uuid to 16bit if it contains the ble base uuid.
|
||||||
|
* @return The NimBLEUUID converted to 16bit if successful, otherwise the original uuid.
|
||||||
|
*/
|
||||||
|
const NimBLEUUID& NimBLEUUID::to16() {
|
||||||
|
if (!m_valueSet || m_uuid.u.type == BLE_UUID_TYPE_16) {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_uuid.u.type == BLE_UUID_TYPE_128) {
|
||||||
|
uint8_t base128[] = {0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00,
|
||||||
|
0x00, 0x80, 0x00, 0x10, 0x00, 0x00};
|
||||||
|
if (memcmp(m_uuid.u128.value, base128, sizeof(base128)) == 0 ) {
|
||||||
|
*this = NimBLEUUID(*(uint16_t*)(m_uuid.u128.value + 12));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get a string representation of the UUID.
|
* @brief Get a string representation of the UUID.
|
||||||
* @details
|
* @details
|
||||||
|
|
|
@ -14,10 +14,16 @@
|
||||||
|
|
||||||
#ifndef COMPONENTS_NIMBLEUUID_H_
|
#ifndef COMPONENTS_NIMBLEUUID_H_
|
||||||
#define COMPONENTS_NIMBLEUUID_H_
|
#define COMPONENTS_NIMBLEUUID_H_
|
||||||
#include "sdkconfig.h"
|
|
||||||
|
#include "nimconfig.h"
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
#if defined(CONFIG_BT_ENABLED)
|
||||||
|
|
||||||
|
#if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||||
#include "host/ble_uuid.h"
|
#include "host/ble_uuid.h"
|
||||||
|
#else
|
||||||
|
#include "nimble/nimble/host/include/host/ble_uuid.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
/**** FIX COMPILATION ****/
|
/**** FIX COMPILATION ****/
|
||||||
#undef min
|
#undef min
|
||||||
#undef max
|
#undef max
|
||||||
|
@ -42,6 +48,7 @@ public:
|
||||||
bool equals(const NimBLEUUID &uuid) const;
|
bool equals(const NimBLEUUID &uuid) const;
|
||||||
const ble_uuid_any_t* getNative() const;
|
const ble_uuid_any_t* getNative() const;
|
||||||
const NimBLEUUID & to128();
|
const NimBLEUUID & to128();
|
||||||
|
const NimBLEUUID& to16();
|
||||||
std::string toString() const;
|
std::string toString() const;
|
||||||
static NimBLEUUID fromString(const std::string &uuid);
|
static NimBLEUUID fromString(const std::string &uuid);
|
||||||
|
|
||||||
|
|
|
@ -6,12 +6,13 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "sdkconfig.h"
|
#include "nimconfig.h"
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
#if defined(CONFIG_BT_ENABLED)
|
||||||
|
|
||||||
#include "NimBLEUtils.h"
|
#include "NimBLEUtils.h"
|
||||||
#include "NimBLELog.h"
|
#include "NimBLELog.h"
|
||||||
#include "nimconfig.h"
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
static const char* LOG_TAG = "NimBLEUtils";
|
static const char* LOG_TAG = "NimBLEUtils";
|
||||||
|
|
||||||
|
@ -358,6 +359,7 @@ const char* NimBLEUtils::returnCodeToString(int rc) {
|
||||||
return "Unknown";
|
return "Unknown";
|
||||||
}
|
}
|
||||||
#else // #if defined(CONFIG_NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT)
|
#else // #if defined(CONFIG_NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT)
|
||||||
|
(void)rc;
|
||||||
return "";
|
return "";
|
||||||
#endif // #if defined(CONFIG_NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT)
|
#endif // #if defined(CONFIG_NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT)
|
||||||
}
|
}
|
||||||
|
@ -385,6 +387,7 @@ const char* NimBLEUtils::advTypeToString(uint8_t advType) {
|
||||||
return "Unknown flag";
|
return "Unknown flag";
|
||||||
}
|
}
|
||||||
#else // #if defined(CONFIG_NIMBLE_CPP_ENABLE_ADVERTISMENT_TYPE_TEXT)
|
#else // #if defined(CONFIG_NIMBLE_CPP_ENABLE_ADVERTISMENT_TYPE_TEXT)
|
||||||
|
(void)advType;
|
||||||
return "";
|
return "";
|
||||||
#endif // #if defined(CONFIG_NIMBLE_CPP_ENABLE_ADVERTISMENT_TYPE_TEXT)
|
#endif // #if defined(CONFIG_NIMBLE_CPP_ENABLE_ADVERTISMENT_TYPE_TEXT)
|
||||||
} // adFlagsToString
|
} // adFlagsToString
|
||||||
|
@ -432,8 +435,11 @@ char* NimBLEUtils::buildHexData(uint8_t* target, const uint8_t* source, uint8_t
|
||||||
* @param [in] arg Unused.
|
* @param [in] arg Unused.
|
||||||
*/
|
*/
|
||||||
void NimBLEUtils::dumpGapEvent(ble_gap_event *event, void *arg){
|
void NimBLEUtils::dumpGapEvent(ble_gap_event *event, void *arg){
|
||||||
|
(void)arg;
|
||||||
#if defined(CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT)
|
#if defined(CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT)
|
||||||
NIMBLE_LOGD(LOG_TAG, "Received a GAP event: %s", gapEventToString(event->type));
|
NIMBLE_LOGD(LOG_TAG, "Received a GAP event: %s", gapEventToString(event->type));
|
||||||
|
#else
|
||||||
|
(void)event;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -520,6 +526,7 @@ const char* NimBLEUtils::gapEventToString(uint8_t eventType) {
|
||||||
return "Unknown event type";
|
return "Unknown event type";
|
||||||
}
|
}
|
||||||
#else // #if defined(CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT)
|
#else // #if defined(CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT)
|
||||||
|
(void)eventType;
|
||||||
return "";
|
return "";
|
||||||
#endif // #if defined(CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT)
|
#endif // #if defined(CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT)
|
||||||
} // gapEventToString
|
} // gapEventToString
|
||||||
|
|
|
@ -8,10 +8,15 @@
|
||||||
|
|
||||||
#ifndef COMPONENTS_NIMBLEUTILS_H_
|
#ifndef COMPONENTS_NIMBLEUTILS_H_
|
||||||
#define COMPONENTS_NIMBLEUTILS_H_
|
#define COMPONENTS_NIMBLEUTILS_H_
|
||||||
#include "sdkconfig.h"
|
|
||||||
|
#include "nimconfig.h"
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
#if defined(CONFIG_BT_ENABLED)
|
||||||
|
|
||||||
|
#if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||||
#include "host/ble_gap.h"
|
#include "host/ble_gap.h"
|
||||||
|
#else
|
||||||
|
#include "nimble/nimble/host/include/host/ble_gap.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
/**** FIX COMPILATION ****/
|
/**** FIX COMPILATION ****/
|
||||||
#undef min
|
#undef min
|
||||||
|
@ -24,7 +29,7 @@ typedef struct {
|
||||||
void *pATT;
|
void *pATT;
|
||||||
TaskHandle_t task;
|
TaskHandle_t task;
|
||||||
int rc;
|
int rc;
|
||||||
std::string *buf;
|
void *buf;
|
||||||
} ble_task_data_t;
|
} ble_task_data_t;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -10,21 +10,68 @@
|
||||||
#include "sdkconfig.h"
|
#include "sdkconfig.h"
|
||||||
#include "nimconfig_rename.h"
|
#include "nimconfig_rename.h"
|
||||||
|
|
||||||
|
#if defined(CONFIG_BT_ENABLED)
|
||||||
|
|
||||||
|
// Allows cpp wrapper to select the correct include paths when using esp-idf
|
||||||
|
#define CONFIG_NIMBLE_CPP_IDF
|
||||||
|
|
||||||
|
/* Cannot use client without scan */
|
||||||
|
#if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL) && !defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||||
|
#define CONFIG_BT_NIMBLE_ROLE_OBSERVER
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Cannot use server without advertise */
|
||||||
|
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) && !defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||||
|
#define CONFIG_BT_NIMBLE_ROLE_BROADCASTER
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Enables the use of Arduino String class for attribute values */
|
||||||
|
#if defined __has_include
|
||||||
|
# if __has_include (<Arduino.h>)
|
||||||
|
# define NIMBLE_CPP_ARDUINO_STRING_AVAILABLE
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* CONFIG_BT_ENABLED */
|
||||||
|
|
||||||
#ifdef _DOXYGEN_
|
#ifdef _DOXYGEN_
|
||||||
|
|
||||||
/** @brief Un-comment to change the number of simultaneous connections (esp controller max is 9) */
|
/** @brief Un-comment to change the number of simultaneous connections (esp controller max is 9) */
|
||||||
#define CONFIG_BT_NIMBLE_MAX_CONNECTIONS 3
|
#define CONFIG_BT_NIMBLE_MAX_CONNECTIONS 3
|
||||||
|
|
||||||
|
/** @brief Un-comment to enable storing the timestamp when an attribute value is updated\n
|
||||||
|
* This allows for checking the last update time using getTimeStamp() or getValue(time_t*)\n
|
||||||
|
* If disabled, the timestamp returned from these functions will be 0.\n
|
||||||
|
* Disabling timestamps will reduce the memory used for each value.\n
|
||||||
|
* 1 = Enabled, 0 = Disabled; Default = Disabled
|
||||||
|
*/
|
||||||
|
#define CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED 0
|
||||||
|
|
||||||
|
/** @brief Uncomment to set the default allocation size (bytes) for each attribute if\n
|
||||||
|
* not specified when the constructor is called. This is also the size used when a remote\n
|
||||||
|
* characteristic or descriptor is constructed before a value is read/notifed.\n
|
||||||
|
* Increasing this will reduce reallocations but increase memory footprint.\n
|
||||||
|
* Default value is 20. Range: 1 : 512 (BLE_ATT_ATTR_MAX_LEN)
|
||||||
|
*/
|
||||||
|
#define CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH 20
|
||||||
|
|
||||||
/** @brief Un-comment to change the default MTU size */
|
/** @brief Un-comment to change the default MTU size */
|
||||||
#define CONFIG_BT_NIMBLE_ATT_PREFERRED_MTU 255
|
#define CONFIG_BT_NIMBLE_ATT_PREFERRED_MTU 255
|
||||||
|
|
||||||
/** @brief Un-comment to change default device name */
|
/** @brief Un-comment to change default device name */
|
||||||
#define CONFIG_BT_NIMBLE_SVC_GAP_DEVICE_NAME "nimble"
|
#define CONFIG_BT_NIMBLE_SVC_GAP_DEVICE_NAME "nimble"
|
||||||
|
|
||||||
/** @brief Un-comment to see debug log messages from the NimBLE host
|
/** @brief Un-comment to set the debug log messages level from the NimBLE host stack.\n
|
||||||
|
* Values: 0 = DEBUG, 1 = INFO, 2 = WARNING, 3 = ERROR, 4 = CRITICAL, 5+ = NONE\n
|
||||||
* Uses approx. 32kB of flash memory.
|
* Uses approx. 32kB of flash memory.
|
||||||
*/
|
*/
|
||||||
#define CONFIG_BT_NIMBLE_DEBUG
|
#define CONFIG_BT_NIMBLE_LOG_LEVEL 5
|
||||||
|
|
||||||
|
/** @brief Un-comment to set the debug log messages level from the NimBLE CPP Wrapper.\n
|
||||||
|
* Values: 0 = NONE, 1 = ERROR, 2 = WARNING, 3 = INFO, 4+ = DEBUG\n
|
||||||
|
* Uses approx. 32kB of flash memory.
|
||||||
|
*/
|
||||||
|
#define CONFIG_NIMBLE_CPP_LOG_LEVEL 0
|
||||||
|
|
||||||
/** @brief Un-comment to see NimBLE host return codes as text debug log messages.
|
/** @brief Un-comment to see NimBLE host return codes as text debug log messages.
|
||||||
* Uses approx. 7kB of flash memory.
|
* Uses approx. 7kB of flash memory.
|
||||||
|
|
Loading…
Reference in a new issue