mirror of
https://github.com/h2zero/esp-nimble-cpp.git
synced 2025-12-23 15:18:16 +01:00
Compare commits
108 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bbed8d1d4b | ||
|
|
099e7cc326 | ||
|
|
830c4cc39e | ||
|
|
ea6e2101e3 | ||
|
|
d47cf59ba9 | ||
|
|
ea02eb9452 | ||
|
|
798726c05d | ||
|
|
9824bdfe73 | ||
|
|
fac16f2428 | ||
|
|
0957d7f6ad | ||
|
|
5facd89a00 | ||
|
|
f2ade345f4 | ||
|
|
7a82067177 | ||
|
|
d041a089e6 | ||
|
|
9debfcd226 | ||
|
|
8620092c90 | ||
|
|
96459073a4 | ||
|
|
a4403fe6b8 | ||
|
|
f841f030ae | ||
|
|
d793b1251e | ||
|
|
5925782a65 | ||
|
|
ccea428b9e | ||
|
|
e238a18a80 | ||
|
|
7b40829e77 | ||
|
|
b24597ac56 | ||
|
|
9961c5605c | ||
|
|
d4e4074f5a | ||
|
|
e5edc9d59e | ||
|
|
2e1d78ff78 | ||
|
|
6be6a111d0 | ||
|
|
0a2714c169 | ||
|
|
7d01fa595d | ||
|
|
2decc0682a | ||
|
|
6ff1a49dd5 | ||
|
|
09adf86036 | ||
|
|
d3a0f95aaf | ||
|
|
d9d794ae40 | ||
|
|
30d6c399b8 | ||
|
|
7815d89dbf | ||
|
|
9fa9531e50 | ||
|
|
946b971750 | ||
|
|
b62358a520 | ||
|
|
e45fb8616a | ||
|
|
d38865e022 | ||
|
|
62d1f67d8b | ||
|
|
4f8342e275 | ||
|
|
05080abad4 | ||
|
|
f5eab87a87 | ||
|
|
3c33129600 | ||
|
|
3227681476 | ||
|
|
cf3227503b | ||
|
|
ef049ddf19 | ||
|
|
7bec9c240a | ||
|
|
1210772332 | ||
|
|
7dd4d68806 | ||
|
|
28d6492ea4 | ||
|
|
dff5122ce2 | ||
|
|
6e104dfb45 | ||
|
|
b290ca9077 | ||
|
|
ae2ff3a638 | ||
|
|
43c9d96373 | ||
|
|
af24cd7720 | ||
|
|
82524c80e3 | ||
|
|
9527c41486 | ||
|
|
51c49ba9fc | ||
|
|
4e24a06645 | ||
|
|
310c5f7c84 | ||
|
|
026864e031 | ||
|
|
cf64169bc0 | ||
|
|
559a6e6970 | ||
|
|
a4e085f71a | ||
|
|
26ab9760da | ||
|
|
c089eab595 | ||
|
|
c157680575 | ||
|
|
6ee1cc236a | ||
|
|
6487225563 | ||
|
|
5629f4d3e9 | ||
|
|
b064cc65d4 | ||
|
|
f61bd5c2df | ||
|
|
57ba0e583d | ||
|
|
372c79a6b8 | ||
|
|
28573f5abe | ||
|
|
b807321d1b | ||
|
|
4f4883d6ba | ||
|
|
765d5b1be7 | ||
|
|
09ff0c3472 | ||
|
|
740f280664 | ||
|
|
28717c300a | ||
|
|
8fe2766e01 | ||
|
|
a5ad7ff43e | ||
|
|
39a3a63f80 | ||
|
|
27fc792952 | ||
|
|
ebd7598c49 | ||
|
|
36317e18db | ||
|
|
22d5564d04 | ||
|
|
d29ad95dfe | ||
|
|
de59693f0f | ||
|
|
77f477f428 | ||
|
|
7ed962d963 | ||
|
|
a85ac6ad5a | ||
|
|
3e9a63a514 | ||
|
|
8d550a6905 | ||
|
|
8e7fcafa9e | ||
|
|
22103af037 | ||
|
|
a331cb05e9 | ||
|
|
d9e11ee630 | ||
|
|
91b5916cf4 | ||
|
|
1a52245012 |
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.8.19.src.tar.gz
|
||||
- tar -xzvf doxygen-1.8.19.src.tar.gz
|
||||
- mkdir doxygen_build
|
||||
- cd doxygen_build
|
||||
- cmake ../doxygen-1.8.19/
|
||||
- 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
|
||||
217
CHANGELOG.md
217
CHANGELOG.md
@@ -1,6 +1,221 @@
|
||||
# Changelog
|
||||
|
||||
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.2] - 2022-01-15
|
||||
|
||||
### Fixed
|
||||
- Initialize advertising complete callback in NimBLEAdvertising constructor.
|
||||
- Clear client disconnect timer in constructor before initializing.
|
||||
- Fix missing data when reading large values.
|
||||
- Fix missing data in notifications when using a large MTU size and more than 270 bytes of data are sent.
|
||||
- Workaround fix added for cases when the task notification value is not cleared, causing various functions that should block not to block.
|
||||
|
||||
### Added
|
||||
- `NimBLEClient::getLastError` : Gets the error code of the last function call that produces a return code from the stack.
|
||||
- `NimBLECharacteristic::notify` : Overload method to send notifications/indications with custom values.
|
||||
- Added conditional checks for ESP32 specific functions/values to support use of the library on non-esp32 devices.
|
||||
- Added an alias to use the callback name from the original library `onMtuChanged`.
|
||||
- `NimBLEClient::setDataLen` and `NimBLEServer::setDataLen`: Data length extension support (IDF version >= 4.3.2 only)
|
||||
- Config option to set logging level for esp-nimble-cpp
|
||||
|
||||
### Changed
|
||||
- Critical section calls now use the NimBLE API instead of FreeRTOS directly. This removes the need for a `portMUX_TYPE` variable in the class definitions.
|
||||
- Removed unnecessary variables in `NimBLEService` and changed the constructor no no longer accept `numHandles` and `inst_id` parameters.
|
||||
|
||||
## [1.3.1] - 2021-08-04
|
||||
|
||||
### Fixed
|
||||
- Corrected a compiler/linker error when an application or a library uses bluetooth classic due to the redefinition of `btInUse`.
|
||||
|
||||
## [1.3.0] - 2021-08-02
|
||||
|
||||
### Added
|
||||
- `NimBLECharacteristic::removeDescriptor`: Dynamically remove a descriptor from a characterisic. Takes effect after all connections are closed and sends a service changed indication.
|
||||
- `NimBLEService::removeCharacteristic`: Dynamically remove a characteristic from a service. Takes effect after all connections are closed and sends a service changed indication
|
||||
- `NimBLEServerCallbacks::onMTUChange`: This is callback is called when the MTU is updated after connection with a client.
|
||||
- ESP32C3 support
|
||||
|
||||
- Whitelist API:
|
||||
- `NimBLEDevice::whiteListAdd`: Add a device to the whitelist.
|
||||
- `NimBLEDevice::whiteListRemove`: Remove a device from the whitelist.
|
||||
- `NimBLEDevice::onWhiteList`: Check if the device is on the whitelist.
|
||||
- `NimBLEDevice::getWhiteListCount`: Gets the size of the whitelist
|
||||
- `NimBLEDevice::getWhiteListAddress`: Get the address of a device on the whitelist by index value.
|
||||
|
||||
- Bond management API:
|
||||
- `NimBLEDevice::getNumBonds`: Gets the number of bonds stored.
|
||||
- `NimBLEDevice::isBonded`: Checks if the device is bonded.
|
||||
- `NimBLEDevice::deleteAllBonds`: Deletes all bonds.
|
||||
- `NimBLEDevice::getBondedAddress`: Gets the address of a bonded device by the index value.
|
||||
|
||||
- `NimBLECharacteristic::getCallbacks` to retrieve the current callback handler.
|
||||
- Connection Information class: `NimBLEConnInfo`.
|
||||
- `NimBLEScan::clearDuplicateCache`: This can be used to reset the cache of advertised devices so they will be immediately discovered again.
|
||||
|
||||
### Changed
|
||||
- FreeRTOS files have been removed as they are not used by the library.
|
||||
- Services, characteristics and descriptors can now be created statically and added after.
|
||||
- Excess logging and some asserts removed.
|
||||
- Use ESP_LOGx macros to enable using local log level filtering.
|
||||
|
||||
### Fixed
|
||||
- `NimBLECharacteristicCallbacks::onSubscribe` Is now called after the connection is added to the vector.
|
||||
- Corrected bonding failure when reinitializing the BLE stack.
|
||||
- Writing to a characterisic with a std::string value now correctly writes values with null characters.
|
||||
- Retrieving remote descriptors now uses the characterisic end handle correctly.
|
||||
- Missing data in long writes to remote descriptors.
|
||||
- Hanging on task notification when sending an indication from the characteristic callback.
|
||||
- BLE controller memory could be released when using Arduino as a component.
|
||||
- Complile errors with NimBLE release 1.3.0.
|
||||
|
||||
## [1.2.0] - 2021-02-08
|
||||
|
||||
### Added
|
||||
- `NimBLECharacteristic::getDescriptorByHandle`: Return the BLE Descriptor for the given handle.
|
||||
|
||||
- `NimBLEDescriptor::getStringValue`: Get the value of this descriptor as a string.
|
||||
|
||||
- `NimBLEServer::getServiceByHandle`: Get a service by its handle.
|
||||
|
||||
- `NimBLEService::getCharacteristicByHandle`: Get a pointer to the characteristic object with the specified handle.
|
||||
|
||||
- `NimBLEService::getCharacteristics`: Get the vector containing pointers to each characteristic associated with this service.
|
||||
Overloads to get a vector containing pointers to all the characteristics in a service with the UUID. (supports multiple same UUID's in a service)
|
||||
- `NimBLEService::getCharacteristics(const char *uuid)`
|
||||
- `NimBLEService::getCharacteristics(const NimBLEUUID &uuid)`
|
||||
|
||||
- `NimBLEAdvertisementData` New methods:
|
||||
- `NimBLEAdvertisementData::addTxPower`: Adds transmission power to the advertisement.
|
||||
- `NimBLEAdvertisementData::setPreferredParams`: Adds connection parameters to the advertisement.
|
||||
- `NimBLEAdvertisementData::setURI`: Adds URI data to the advertisement.
|
||||
|
||||
- `NimBLEAdvertising` New methods:
|
||||
- `NimBLEAdvertising::setName`: Set the name advertised.
|
||||
- `NimBLEAdvertising::setManufacturerData`: Adds manufacturer data to the advertisement.
|
||||
- `NimBLEAdvertising::setURI`: Adds URI data to the advertisement.
|
||||
- `NimBLEAdvertising::setServiceData`: Adds service data to the advertisement.
|
||||
- `NimBLEAdvertising::addTxPower`: Adds transmission power to the advertisement.
|
||||
- `NimBLEAdvertising::reset`: Stops the current advertising and resets the advertising data to the default values.
|
||||
|
||||
- `NimBLEDevice::setScanFilterMode`: Set the controller duplicate filter mode for filtering scanned devices.
|
||||
|
||||
- `NimBLEDevice::setScanDuplicateCacheSize`: Sets the number of advertisements filtered before the cache is reset.
|
||||
|
||||
- `NimBLEScan::setMaxResults`: This allows for setting a maximum number of advertised devices stored in the results vector.
|
||||
|
||||
- `NimBLEAdvertisedDevice` New data retrieval methods added:
|
||||
- `haveAdvInterval/getAdvInterval`: checks if the interval is advertised / gets the advertisement interval value.
|
||||
|
||||
- `haveConnParams/getMinInterval/getMaxInterval`: checks if the parameters are advertised / get min value / get max value.
|
||||
|
||||
- `haveURI/getURI`: checks if a URI is advertised / gets the URI data.
|
||||
|
||||
- `haveTargetAddress/getTargetAddressCount/getTargetAddress(index)`: checks if a target address is present / gets a count of the addresses targeted / gets the address of the target at index.
|
||||
|
||||
### Changed
|
||||
- `nimconfig.h` (Arduino) is now easier to use.
|
||||
|
||||
- `NimBLEServer::getServiceByUUID` Now takes an extra parameter of instanceID to support multiple services with the same UUID.
|
||||
|
||||
- `NimBLEService::getCharacteristic` Now takes an extra parameter of instanceID to support multiple characteristics with the same UUID.
|
||||
|
||||
- `NimBLEAdvertising` Transmission power is no longer advertised by default and can be added to the advertisement by calling `NimBLEAdvertising::addTxPower`
|
||||
|
||||
- `NimBLEAdvertising` Custom scan response data can now be used without custom advertisment.
|
||||
|
||||
- `NimBLEScan` Now uses the controller duplicate filter.
|
||||
|
||||
- `NimBLEAdvertisedDevice` Has been refactored to store the complete advertisement payload and no longer parses the data from each advertisement.
|
||||
Instead the data will be parsed on-demand when the user application asks for specific data.
|
||||
|
||||
### Fixed
|
||||
- `NimBLEHIDDevice` Characteristics now use encryption, this resolves an issue with communicating with devices requiring encryption for HID devices.
|
||||
|
||||
|
||||
## [1.1.0] - 2021-01-20
|
||||
|
||||
### Added
|
||||
- `NimBLEDevice::setOwnAddrType` added to enable the use of random and random-resolvable addresses, by asukiaaa
|
||||
|
||||
- New examples for securing and authenticating client/server connections, by mblasee.
|
||||
|
||||
- `NimBLEAdvertising::SetMinPreferred` and `NimBLEAdvertising::SetMinPreferred` re-added.
|
||||
|
||||
- Conditional checks added for command line config options in `nimconfig.h` to support custom configuration in platformio.
|
||||
|
||||
- `NimBLEClient::setValue` Now takes an extra bool parameter `response` to enable the use of write with response (default = false).
|
||||
|
||||
- `NimBLEClient::getCharacteristic(uint16_t handle)` Enabling the use of the characteristic handle to be used to find
|
||||
the NimBLERemoteCharacteristic object.
|
||||
|
||||
- `NimBLEHIDDevice` class added by wakwak-koba.
|
||||
|
||||
- `NimBLEServerCallbacks::onDisconnect` overloaded callback added to provide a ble_gap_conn_desc parameter for the application
|
||||
to obtain information about the disconnected client.
|
||||
|
||||
- Conditional checks in `nimconfig.h` for command line defined macros to support platformio config settings.
|
||||
|
||||
### Changed
|
||||
- `NimBLEAdvertising::start` now returns a bool value to indicate success/failure.
|
||||
|
||||
- Some asserts were removed in `NimBLEAdvertising::start` and replaced with better return code handling and logging.
|
||||
|
||||
- If a host reset event occurs, scanning and advertising will now only be restarted if their previous duration was indefinite.
|
||||
|
||||
- `NimBLERemoteCharacteristic::subscribe` and `NimBLERemoteCharacteristic::registerForNotify` will now set the callback
|
||||
regardless of the existance of the CCCD and return true unless the descriptor write operation failed.
|
||||
|
||||
- Advertising tx power level is now sent in the advertisement packet instead of scan response.
|
||||
|
||||
- `NimBLEScan` When the scan ends the scan stopped flag is now set before calling the scan complete callback (if used)
|
||||
this allows the starting of a new scan from the callback function.
|
||||
|
||||
### Fixed
|
||||
- Sometimes `NimBLEClient::connect` would hang on the task block if no event arrived to unblock.
|
||||
A time limit has been added to timeout appropriately.
|
||||
|
||||
- When getting descriptors for a characterisic the end handle of the service was used as a proxy for the characteristic end
|
||||
handle. This would be rejected by some devices and has been changed to use the next characteristic handle as the end when possible.
|
||||
|
||||
- An exception could occur when deleting a client instance if a notification arrived while the attribute vectors were being
|
||||
deleted. A flag has been added to prevent this.
|
||||
|
||||
- An exception could occur after a host reset event when the host re-synced if the tasks that were stopped during the event did
|
||||
not finish processing. A yield has been added after re-syncing to allow tasks to finish before proceeding.
|
||||
|
||||
- Occasionally the controller would fail to send a disconnected event causing the client to indicate it is connected
|
||||
and would be unable to reconnect. A timer has been added to reset the host/controller if it expires.
|
||||
|
||||
- Occasionally the call to start scanning would get stuck in a loop on BLE_HS_EBUSY, this loop has been removed.
|
||||
|
||||
- 16bit and 32bit UUID's in some cases were not discovered or compared correctly if the device
|
||||
advertised them as 16/32bit but resolved them to 128bits. Both are now checked.
|
||||
|
||||
- `FreeRTOS` compile errors resolved in latest Ardruino core and IDF v3.3.
|
||||
|
||||
- Multiple instances of `time()` called inside critical sections caused sporadic crashes, these have been moved out of critical regions.
|
||||
|
||||
- Advertisement type now correctly set when using non-connectable (advertiser only) mode.
|
||||
|
||||
- Advertising payload length correction, now accounts for appearance.
|
||||
|
||||
- (Arduino) Ensure controller mode is set to BLE Only.
|
||||
|
||||
|
||||
## [1.0.2] - 2020-09-13
|
||||
|
||||
### Changed
|
||||
|
||||
- `NimBLEAdvertising::start` Now takes 2 optional parameters, the first is the duration to advertise for (in seconds), the second is a
|
||||
callback that is invoked when advertsing ends and takes a pointer to a `NimBLEAdvertising` object (similar to the `NimBLEScan::start` API).
|
||||
|
||||
- (Arduino) Maximum BLE connections can now be altered by only changing the value of `CONFIG_BT_NIMBLE_MAX_CONNECTIONS` in `nimconfig.h`.
|
||||
Any changes to the controller max connection settings in `sdkconfig.h` will now have no effect when using this library.
|
||||
|
||||
- (Arduino) Revert the previous change to fix the advertising start delay. Instead a replacement fix that routes all BLE controller commands from
|
||||
a task running on core 0 (same as the controller) has been implemented. This improves response times and reliability for all BLE functions.
|
||||
|
||||
|
||||
## [1.0.1] - 2020-09-02
|
||||
|
||||
|
||||
@@ -2,28 +2,57 @@
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
set(SUPPORTED_TARGETS esp32)
|
||||
idf_build_get_property(__hack_component_targets __COMPONENT_TARGETS)
|
||||
|
||||
if("esp-nimble-component" IN_LIST BUILD_COMPONENTS OR "__esp-nimble-component" IN_LIST __hack_component_targets)
|
||||
list(APPEND ESP_NIMBLE_PRIV_REQUIRES
|
||||
esp-nimble-component
|
||||
)
|
||||
elseif("nimble" IN_LIST BUILD_COMPONENTS OR "__nimble" IN_LIST __hack_component_targets)
|
||||
list(APPEND ESP_NIMBLE_PRIV_REQUIRES
|
||||
nimble
|
||||
)
|
||||
endif()
|
||||
|
||||
if("arduino" IN_LIST BUILD_COMPONENTS OR __hack_component_targets MATCHES "__idf_arduino")
|
||||
list(APPEND ESP_NIMBLE_PRIV_REQUIRES
|
||||
arduino
|
||||
)
|
||||
endif()
|
||||
|
||||
idf_component_register(
|
||||
REQUIRED_IDF_TARGETS
|
||||
"esp32"
|
||||
"esp32s3"
|
||||
"esp32c3"
|
||||
INCLUDE_DIRS
|
||||
"src"
|
||||
SRCS
|
||||
"src/NimBLE2904.cpp"
|
||||
"src/NimBLEAddress.cpp"
|
||||
"src/NimBLEAdvertisedDevice.cpp"
|
||||
"src/NimBLEAdvertising.cpp"
|
||||
"src/NimBLEBeacon.cpp"
|
||||
"src/NimBLECharacteristic.cpp"
|
||||
"src/NimBLEClient.cpp"
|
||||
"src/NimBLEDescriptor.cpp"
|
||||
"src/NimBLEDevice.cpp"
|
||||
"src/NimBLEEddystoneTLM.cpp"
|
||||
"src/NimBLEEddystoneURL.cpp"
|
||||
"src/NimBLEHIDDevice.cpp"
|
||||
"src/NimBLERemoteCharacteristic.cpp"
|
||||
"src/NimBLERemoteDescriptor.cpp"
|
||||
"src/NimBLERemoteService.cpp"
|
||||
"src/NimBLEScan.cpp"
|
||||
"src/NimBLESecurity.cpp"
|
||||
"src/NimBLEServer.cpp"
|
||||
"src/NimBLEService.cpp"
|
||||
"src/NimBLEUtils.cpp"
|
||||
"src/NimBLEUUID.cpp"
|
||||
REQUIRES
|
||||
bt
|
||||
nvs_flash
|
||||
PRIV_REQUIRES
|
||||
${ESP_NIMBLE_PRIV_REQUIRES}
|
||||
)
|
||||
|
||||
idf_component_register(SRCS "src/FreeRTOS.cpp"
|
||||
"src/NimBLE2904.cpp"
|
||||
"src/NimBLEAddress.cpp"
|
||||
"src/NimBLEAdvertisedDevice.cpp"
|
||||
"src/NimBLEAdvertising.cpp"
|
||||
"src/NimBLEBeacon.cpp"
|
||||
"src/NimBLECharacteristic.cpp"
|
||||
"src/NimBLEClient.cpp"
|
||||
"src/NimBLEDescriptor.cpp"
|
||||
"src/NimBLEDevice.cpp"
|
||||
"src/NimBLEEddystoneTLM.cpp"
|
||||
"src/NimBLEEddystoneURL.cpp"
|
||||
"src/NimBLERemoteCharacteristic.cpp"
|
||||
"src/NimBLERemoteDescriptor.cpp"
|
||||
"src/NimBLERemoteService.cpp"
|
||||
"src/NimBLEScan.cpp"
|
||||
"src/NimBLESecurity.cpp"
|
||||
"src/NimBLEServer.cpp"
|
||||
"src/NimBLEService.cpp"
|
||||
"src/NimBLEUtils.cpp"
|
||||
"src/NimBLEUUID.cpp"
|
||||
INCLUDE_DIRS "src"
|
||||
REQUIRES bt)
|
||||
|
||||
56
CMakeLists.txt_idf3
Normal file
56
CMakeLists.txt_idf3
Normal file
@@ -0,0 +1,56 @@
|
||||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
set(SUPPORTED_TARGETS esp32)
|
||||
|
||||
set(COMPONENT_SRCS
|
||||
"src/NimBLE2904.cpp"
|
||||
"src/NimBLEAddress.cpp"
|
||||
"src/NimBLEAdvertisedDevice.cpp"
|
||||
"src/NimBLEAdvertising.cpp"
|
||||
"src/NimBLEBeacon.cpp"
|
||||
"src/NimBLECharacteristic.cpp"
|
||||
"src/NimBLEClient.cpp"
|
||||
"src/NimBLEDescriptor.cpp"
|
||||
"src/NimBLEDevice.cpp"
|
||||
"src/NimBLEEddystoneTLM.cpp"
|
||||
"src/NimBLEEddystoneURL.cpp"
|
||||
"src/NimBLEHIDDevice.cpp"
|
||||
"src/NimBLERemoteCharacteristic.cpp"
|
||||
"src/NimBLERemoteDescriptor.cpp"
|
||||
"src/NimBLERemoteService.cpp"
|
||||
"src/NimBLEScan.cpp"
|
||||
"src/NimBLESecurity.cpp"
|
||||
"src/NimBLEServer.cpp"
|
||||
"src/NimBLEService.cpp"
|
||||
"src/NimBLEUtils.cpp"
|
||||
"src/NimBLEUUID.cpp"
|
||||
)
|
||||
|
||||
set(COMPONENT_ADD_INCLUDEDIRS
|
||||
src
|
||||
)
|
||||
|
||||
set(COMPONENT_PRIV_REQUIRES
|
||||
nvs_flash
|
||||
bt
|
||||
)
|
||||
|
||||
if(COMPONENTS MATCHES "esp-nimble-component")
|
||||
list(APPEND COMPONENT_PRIV_REQUIRES
|
||||
esp-nimble-component
|
||||
)
|
||||
elseif(COMPONENTS MATCHES "nimble")
|
||||
list(APPEND COMPONENT_PRIV_REQUIRES
|
||||
nimble
|
||||
)
|
||||
endif()
|
||||
|
||||
if(COMPONENTS MATCHES "arduino")
|
||||
list(APPEND COMPONENT_PRIV_REQUIRES
|
||||
arduino
|
||||
)
|
||||
endif()
|
||||
|
||||
register_component()
|
||||
26
Kconfig
26
Kconfig
@@ -1,5 +1,31 @@
|
||||
menu "ESP-NimBLE-CPP configuration"
|
||||
|
||||
choice NIMBLE_CPP_LOG_LEVEL
|
||||
prompt "NimBLE CPP log verbosity"
|
||||
default NIMBLE_CPP_LOG_LEVEL_NONE
|
||||
help
|
||||
Select NimBLE CPP log verbosity level.
|
||||
|
||||
config NIMBLE_CPP_LOG_LEVEL_NONE
|
||||
bool "No logs"
|
||||
config NIMBLE_CPP_LOG_LEVEL_ERROR
|
||||
bool "Error logs"
|
||||
config NIMBLE_CPP_LOG_LEVEL_WARNING
|
||||
bool "Warning logs"
|
||||
config NIMBLE_CPP_LOG_LEVEL_INFO
|
||||
bool "Info logs"
|
||||
config NIMBLE_CPP_LOG_LEVEL_DEBUG
|
||||
bool "Debug logs"
|
||||
endchoice #NIMBLE_CPP_LOG_LEVEL
|
||||
|
||||
config NIMBLE_CPP_LOG_LEVEL
|
||||
int
|
||||
default 0 if NIMBLE_CPP_LOG_LEVEL_NONE
|
||||
default 1 if NIMBLE_CPP_LOG_LEVEL_ERROR
|
||||
default 2 if NIMBLE_CPP_LOG_LEVEL_WARNING
|
||||
default 3 if NIMBLE_CPP_LOG_LEVEL_INFO
|
||||
default 4 if NIMBLE_CPP_LOG_LEVEL_DEBUG
|
||||
|
||||
config NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT
|
||||
bool "Show NimBLE return codes as text in debug log."
|
||||
default "n"
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
menu "ESP-NimBLE-CPP configuration"
|
||||
|
||||
config NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT
|
||||
bool "Show NimBLE return codes as text in debug log."
|
||||
default "n"
|
||||
help
|
||||
Enabling this option will display return code values as text
|
||||
messages in the debug log. This will use approximately 8kB
|
||||
of flash memory.
|
||||
|
||||
config NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT
|
||||
bool "Show NimBLE gap events as text in debug log."
|
||||
default "n"
|
||||
help
|
||||
Enabling this option will display gap event codes as text
|
||||
messages in the debug log. This will use approximately 1kB
|
||||
of flash memory.
|
||||
|
||||
config NIMBLE_CPP_ENABLE_ADVERTISMENT_TYPE_TEXT
|
||||
bool "Show advertisment types as text in debug log."
|
||||
default "n"
|
||||
help
|
||||
Enabling this option will display advertisment types recieved
|
||||
while scanning as text messages in the debug log.
|
||||
This will use approximately 250 bytes of flash memory.
|
||||
|
||||
endmenu
|
||||
17
README.md
17
README.md
@@ -1,5 +1,7 @@
|
||||
[Latest release 
|
||||
](https://github.com/h2zero/esp-nimble-cpp/releases/latest/)
|
||||
|
||||
Need help? Have questions or suggestions? Join the [](https://gitter.im/NimBLE-Arduino/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||
<br/>
|
||||
|
||||
# esp-nimble-cpp
|
||||
@@ -17,7 +19,7 @@ to provide improved capabilites and stability over the original.
|
||||
*Your results may vary*
|
||||
<br/>
|
||||
|
||||
### What is NimBLE?
|
||||
# What is NimBLE?
|
||||
NimBLE is a completely open source Bluetooth Low Energy stack produced by [Apache](https://github.com/apache/mynewt-nimble).
|
||||
It is more suited to resource constrained devices than bluedroid and has now been ported to the ESP32 by Espressif.
|
||||
<br/>
|
||||
@@ -34,7 +36,7 @@ Call `NimBLEDevice::init("");` in `app_main`.
|
||||
<br/>
|
||||
|
||||
### ESP-IDF v3.2 & v3.3
|
||||
The NimBLE component does not come with these versions of IDF.
|
||||
The NimBLE component does not come with these versions of IDF (now included in 3.3.2 and above).
|
||||
A backport that works in these versions has been created and is [available here](https://github.com/h2zero/esp-nimble-component).
|
||||
Download or clone that repo into your project/components folder and run menuconfig.
|
||||
Configure settings in `main menu -> NimBLE Options`.
|
||||
@@ -55,15 +57,14 @@ Also see [Improvements_and_updates](docs/Improvements_and_updates.md) for inform
|
||||
[Full API documentation and class list can be found here.](https://h2zero.github.io/esp-nimble-cpp/)
|
||||
<br/>
|
||||
|
||||
## Using with Arduino as an IDF component and CMake
|
||||
When using this library along with Arduino and compiling with *CMake* you must add `add_compile_definitions(ARDUINO_ARCH_ESP32=1)`
|
||||
in your project/CMakeLists.txt after the line `include($ENV{IDF_PATH}/tools/cmake/project.cmake)` to prevent Arduino from releasing BLE memory.
|
||||
<br>
|
||||
|
||||
# Acknowledgments
|
||||
* [nkolban](https://github.com/nkolban) and [chegewara](https://github.com/chegewara) for the [original esp32 BLE library](https://github.com/nkolban/esp32-snippets/tree/master/cpp_utils) this project was derived from.
|
||||
* [beegee-tokyo](https://github.com/beegee-tokyo) for contributing your time to test/debug and contributing the beacon examples.
|
||||
* [Jeroen88](https://github.com/Jeroen88) for the amazing help debugging and improving the client code.
|
||||
<br/>
|
||||
|
||||
# Todo
|
||||
- Improve host reset handler
|
||||
- Implement random address handling
|
||||
- Implement bond management
|
||||
- Add Bluetooth Mesh
|
||||
<br/>
|
||||
|
||||
117
docs/Command_line_config.md
Normal file
117
docs/Command_line_config.md
Normal file
@@ -0,0 +1,117 @@
|
||||
# Arduino command line and platformio config options
|
||||
|
||||
`CONFIG_BT_NIMBLE_MAX_CONNECTIONS`
|
||||
|
||||
Sets the number of simultaneous connections (esp controller max is 9)
|
||||
- Default value is 3
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_ATT_PREFERRED_MTU`
|
||||
|
||||
Sets the default MTU size.
|
||||
- Default value is 255
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_SVC_GAP_DEVICE_NAME`
|
||||
|
||||
Set the default device name
|
||||
- Default value is "nimble"
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_DEBUG`
|
||||
|
||||
If defined, enables debug log messages from the NimBLE host
|
||||
- Uses approx. 32kB of flash memory.
|
||||
<br/>
|
||||
|
||||
`CONFIG_NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT`
|
||||
|
||||
If defined, NimBLE host return codes will be printed as text in debug log messages.
|
||||
- Uses approx. 7kB of flash memory.
|
||||
<br/>
|
||||
|
||||
`CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT`
|
||||
|
||||
If defined, GAP event codes will be printed as text in debug log messages.
|
||||
- Uses approx. 1kB of flash memory.
|
||||
<br/>
|
||||
|
||||
`CONFIG_NIMBLE_CPP_ENABLE_ADVERTISMENT_TYPE_TEXT`
|
||||
|
||||
If defined, advertisment types will be printed as text while scanning in debug log messages.
|
||||
- Uses approx. 250 bytes of flash memory.
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_SVC_GAP_APPEARANCE`
|
||||
|
||||
Set the default appearance.
|
||||
- Default value is 0x00
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_ROLE_CENTRAL_DISABLED`
|
||||
|
||||
If defined, NimBLE Client functions will not be included.
|
||||
- Reduces flash size by approx. 7kB.
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_ROLE_OBSERVER_DISABLED`
|
||||
|
||||
If defined, NimBLE Scan functions will not be included.
|
||||
- Reduces flash size by approx. 26kB.
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_ROLE_PERIPHERAL_DISABLED`
|
||||
|
||||
If defined NimBLE Server functions will not be included.
|
||||
- Reduces flash size by approx. 16kB.
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_ROLE_BROADCASTER_DISABLED`
|
||||
|
||||
If defined, NimBLE Advertising functions will not be included.
|
||||
- Reduces flash size by approx. 5kB.
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_MAX_BONDS`
|
||||
|
||||
Sets the number of devices allowed to store/bond with
|
||||
- Default value is 3
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_MAX_CCCDS`
|
||||
|
||||
Sets the maximum number of CCCD subscriptions to store
|
||||
- Default value is 8
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_RPA_TIMEOUT`
|
||||
|
||||
Sets the random address refresh time in seconds.
|
||||
- Default value is 900
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_MSYS1_BLOCK_COUNT`
|
||||
|
||||
Set the number of msys blocks For prepare write & prepare responses. This may need to be increased if
|
||||
you are sending large blocks of data with a low MTU. E.g: 512 bytes with 23 MTU will fail.
|
||||
- Default value is 12
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL`
|
||||
|
||||
Sets the NimBLE stack to use external PSRAM will be loaded
|
||||
- Must be defined with a value of 1; Default is CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_INTERNAL 1
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_PINNED_TO_CORE`
|
||||
|
||||
Sets the core the NimBLE host stack will run on
|
||||
- Options: 0 or 1
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_TASK_STACK_SIZE`
|
||||
|
||||
Set the task stack size for the NimBLE core.
|
||||
- Default is 4096
|
||||
<br/>
|
||||
|
||||
@@ -38,7 +38,7 @@ PROJECT_NAME = "esp-nimble-cpp / NimBLE-Arduino"
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER = 1.0.0
|
||||
PROJECT_NUMBER = 1.3.1
|
||||
|
||||
# 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
|
||||
@@ -2179,8 +2179,12 @@ INCLUDE_FILE_PATTERNS =
|
||||
# recursively expanded use the := operator instead of the = operator.
|
||||
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
|
||||
|
||||
PREDEFINED = CONFIG_BT_ENABLED \
|
||||
_DOXYGEN_
|
||||
PREDEFINED = _DOXYGEN_ \
|
||||
CONFIG_BT_ENABLED \
|
||||
CONFIG_BT_NIMBLE_ROLE_CENTRAL \
|
||||
CONFIG_BT_NIMBLE_ROLE_OBSERVER \
|
||||
CONFIG_BT_NIMBLE_ROLE_PERIPHERAL \
|
||||
CONFIG_BT_NIMBLE_ROLE_BROADCASTER
|
||||
|
||||
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
|
||||
# tag can be used to specify a list of macro names that should be expanded. The
|
||||
|
||||
@@ -4,6 +4,7 @@ Many improvements have been made to this library vs the original, this is a brie
|
||||
Refer to the [class documentation](https://h2zero.github.io/esp-nimble-cpp/annotated.html) for futher information on class specifics.
|
||||
|
||||
* [Server](#server)
|
||||
* [Advertising](#advertising)
|
||||
* [Client](#client)
|
||||
* [General](#general)
|
||||
<br/>
|
||||
@@ -60,6 +61,18 @@ it's characteristics / descriptors will remain valid and the service can be re-a
|
||||
using `NimBLEServer::addService`.
|
||||
<br/>
|
||||
|
||||
<a name="advertising"></a>
|
||||
# Advertising
|
||||
`NimBLEAdvertising::start`
|
||||
|
||||
Now takes 2 optional parameters, the first is the duration to advertise for (in seconds), the second is a callback
|
||||
that is invoked when advertsing ends and takes a pointer to a `NimBLEAdvertising` object (similar to the `NimBLEScan::start` API).
|
||||
|
||||
This provides an opportunity to update the advertisment data if desired.
|
||||
|
||||
Also now returns a bool value to indicate if advertising successfully started or not.
|
||||
<br/>
|
||||
|
||||
<a name="client"></a>
|
||||
# Client
|
||||
|
||||
@@ -89,8 +102,18 @@ Has been **deprecated** as now the internally stored characteristic value is upd
|
||||
`NimBLERemoteCharacteristic::subscribe` and `NimBLERemoteCharacteristic::unsubscribe` have been implemented to replace it.
|
||||
A callback is no longer requred to get the most recent value unless timing is important. Instead, the application can call `NimBLERemoteCharacteristic::getValue` to
|
||||
get the last updated value any time.
|
||||
<br/>
|
||||
|
||||
In addition `NimBLERemoteCharacteristic::readValue` and `NimBLERemoteCharacteristic::getValue` take an optional timestamp parameter which will update it's value with
|
||||
The `notifiy_callback` function is now defined as a `std::function` to take advantage of using `std::bind` to specifiy a class member function for the callback.
|
||||
|
||||
Example:
|
||||
```
|
||||
using namespace std::placeholders;
|
||||
notify_callback callback = std::bind(&<ClassName>::<memberFunctionCallbackName>, this, _1, _2, _3, _4);
|
||||
<remoteCharacteristicInstance>->subscribe(true, callback);
|
||||
```
|
||||
|
||||
`NimBLERemoteCharacteristic::readValue` and `NimBLERemoteCharacteristic::getValue` take an optional timestamp parameter which will update it's value with
|
||||
the time the last value was recieved.
|
||||
|
||||
> NimBLEClient::getService
|
||||
|
||||
@@ -209,12 +209,28 @@ This can be changed to use passkey authentication or numeric comparison. See [Se
|
||||
|
||||
<a name="advertising-api"></a>
|
||||
## Advertising API
|
||||
Advertising works the same as the original API except with the removal of:
|
||||
Advertising works the same as the original API except:
|
||||
> BLEAdvertising::setMinPreferred
|
||||
> BLEAdvertising::setMaxPreferred
|
||||
|
||||
These methods were found to not provide useful functionality and consumed valuable advertising space (6 bytes of 31) if used unknowingly.
|
||||
If you wish to advertise these parameters you can still do so manually via `NimBLEAdvertisementData::addData`.
|
||||
If you wish to advertise these parameters you can still do so manually via `BLEAdvertisementData::addData` (`NimBLEAdvertisementData::addData`).
|
||||
<br/>
|
||||
|
||||
Calling `NimBLEAdvertising::setAdvertisementData` will entirely replace any data set with `NimBLEAdvertising::addServiceUUID`, or
|
||||
`NimBLEAdvertising::setAppearance` or similar methods. You should set all the data you wish to advertise within the `NimBLEAdvertisementData` instead.
|
||||
|
||||
~~Calling `NimBLEAdvertising::setScanResponseData` without also calling `NimBLEAdvertising::setAdvertisementData` will have no effect.
|
||||
When using custom scan response data you must also use custom advertisement data.~~
|
||||
No longer true as of release 1.2.0 and above, custom scan response is now supported without custom advertisement data.
|
||||
<br/>
|
||||
|
||||
> BLEAdvertising::start (NimBLEAdvertising::start)
|
||||
|
||||
Now takes 2 optional parameters, the first is the duration to advertise for (in seconds), the second is a callback
|
||||
that is invoked when advertsing ends and takes a pointer to a `NimBLEAdvertising` object (similar to the `NimBLEScan::start` API).
|
||||
|
||||
This provides an opportunity to update the advertisment data if desired.
|
||||
<br/>
|
||||
|
||||
<a name="client-api"></a>
|
||||
|
||||
41
docs/Usage_tips.md
Normal file
41
docs/Usage_tips.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# Usage Tips
|
||||
|
||||
## Put BLE functions in a task running on the NimBLE stack core
|
||||
|
||||
When commands are sent to the stack from a differnt core they can experience delays in execution.
|
||||
This library detects this and invokes the esp32 IPC to reroute these commands through the correct core but this also increases overhead.
|
||||
Therefore it is highly recommended to create tasks for BLE to run on the same core, the macro `CONFIG_BT_NIMBLE_PINNED_TO_CORE` can be used to set the core.
|
||||
<br/>
|
||||
|
||||
## Do not delete client instances unless necessary or unused
|
||||
|
||||
When a client instance has been created and has connected to a peer device and it has retrieved service/characteristic information it will store that data for the life of the client instance.
|
||||
If you are periodically connecting to the same devices and you have deleted the client instance or the services when connecting again it will cause a retrieval of that information from the peer again.
|
||||
This results in significant energy drain on the battery of the devices, fragments heap, and reduces connection performance.
|
||||
|
||||
Client instances in this library use approximately 20% of the original bluedroid library, deleteing them will provide much less gain than it did before.
|
||||
|
||||
It is recommended to retain the client instance in cases where the time between connecting to the same device is less than 5 minutes.
|
||||
<br/>
|
||||
|
||||
## Only retrieve the services and characteriscs needed
|
||||
|
||||
As a client the use of `NimBLEClient::getServices` or `NimBLERemoteService::getCharacteristics` and using `true` for the parameter should be limited to devices that are not known.
|
||||
Instead `NimBLEClient::getService(NimBLEUUID)` or `NimBLERemoteService::getCharacteristic(NimBLEUUID)` should be used to access certain attributes that are useful to the application.
|
||||
This reduces energy consumed, heap allocated, connection time and improves overall efficiency.
|
||||
<br/>
|
||||
|
||||
## Check return values
|
||||
|
||||
Many user issues can be avoided by checking if a function returned successfully, by either testing for true/false such as when calling `NimBLEClient::connect`,
|
||||
or nullptr such as when calling `NimBLEClient::getService`. The latter being a must, as calling a method on a nullptr will surely result in a crash.
|
||||
Most of the functions in this library return something that should be checked before proceeding.
|
||||
<br/>
|
||||
|
||||
## There will be bugs - please report them
|
||||
|
||||
No code is bug free and unit testing will not find them all on it's own. If you encounter a bug, please report it along with any logs and decoded backtrace if applicable.
|
||||
Best efforts will be made to correct any errors ASAP.
|
||||
|
||||
Bug reports can be made at https://github.com/h2zero/NimBLE-Arduino/issues or https://github.com/h2zero/esp-nimble-cpp/issues.
|
||||
Questions and suggestions will be happily accepted there as well.
|
||||
@@ -1,24 +1,28 @@
|
||||
# Overview
|
||||
|
||||
This is a C++ BLE library for the ESP32 that uses the NimBLE host stack instead of bluedroid.
|
||||
The aim is to maintain, as much as reasonable, the original bluedroid C++ API while adding new features
|
||||
and making improvements in performance, resource use and stability.
|
||||
The aim is to maintain, as much as reasonable, the original bluedroid C++ & Arduino BLE API by while adding new features
|
||||
and making improvements in performance, resource use, and stability.
|
||||
|
||||
**Testing shows a nearly 50% reduction in flash use and approx. 100kB less ram consumed vs the original!**
|
||||
*Your results may vary*
|
||||
<br/>
|
||||
*Your results may vary*
|
||||
<br/>
|
||||
|
||||
### What is NimBLE?
|
||||
# What is NimBLE?
|
||||
NimBLE is a completely open source Bluetooth Low Energy stack produced by [Apache](https://github.com/apache/mynewt-nimble).
|
||||
It is more suited to resource constrained devices than bluedroid and has now been ported to the ESP32 by Espressif.
|
||||
<br/>
|
||||
|
||||
# Arduino Installation
|
||||
Download as .zip and extract to Arduino/libraries folder, or in Arduino IDE from Sketch menu -> Include library -> Add .Zip library.
|
||||
**Arduino Library manager:** Go to `sketch` -> `Include Library` -> `Manage Libraries` and search for NimBLE and install.
|
||||
|
||||
`#include "NimBLEDevice.h"` at the beginning of your sketch.
|
||||
**Alternatively:** Download as .zip and extract to Arduino/libraries folder, or in Arduino IDE from Sketch menu -> Include library -> Add .Zip library.
|
||||
|
||||
Tested and working with esp32-arduino Arduino IDE and platform IO.
|
||||
`#include "NimBLEDevice.h"` at the beginning of your sketch.
|
||||
|
||||
Call `NimBLEDevice::init` in `setup`.
|
||||
|
||||
Tested and working with esp32-arduino in Arduino IDE and platform IO.
|
||||
<br/>
|
||||
|
||||
# ESP-IDF Installation
|
||||
@@ -28,17 +32,17 @@ Download as .zip and extract or clone into the components folder in your esp-idf
|
||||
Run menuconfig, go to `Component config->Bluetooth` enable Bluetooth and in `Bluetooth host` NimBLE.
|
||||
Configure settings in `NimBLE Options`.
|
||||
`#include "NimBLEDevice.h"` in main.cpp.
|
||||
Call `NimBLEDevice::init("");` in `app_main`.
|
||||
Call `NimBLEDevice::init` in `app_main`.
|
||||
<br/>
|
||||
|
||||
### v3.2 & v3.3
|
||||
The NimBLE component does not come with these versions of IDF.
|
||||
The NimBLE component does not come with these versions of IDF (now included in 3.3.2 and above).
|
||||
A backport that works in these versions has been created and is [available here](https://github.com/h2zero/esp-nimble-component).
|
||||
Download or clone that repo into your project/components folder and run menuconfig.
|
||||
Configure settings in `main menu -> NimBLE Options`.
|
||||
|
||||
`#include "NimBLEDevice.h"` in main.cpp.
|
||||
Call `NimBLEDevice::init("");` in `app_main`.
|
||||
Call `NimBLEDevice::init` in `app_main`.
|
||||
<br/>
|
||||
|
||||
# Using
|
||||
@@ -48,33 +52,30 @@ If you have not used the original Bluedroid library please refer to the [New use
|
||||
|
||||
If you are familiar with the original library, see: [The migration guide](Migration_guide.md) for details.
|
||||
|
||||
Also see [Improvements_and_updates](Improvements_and_updates.md) for information about non-breaking changes.
|
||||
Also see [Improvements and updates](Improvements_and_updates.md) for information about non-breaking changes.
|
||||
|
||||
### Arduino specific:
|
||||
For more advanced usage see [Usage tips](Usage_tips.md) for more performance and optimization.
|
||||
<br/>
|
||||
|
||||
### Arduino specific
|
||||
See the Refactored_original_examples in the examples folder for highlights of the differences with the original library.
|
||||
|
||||
More advanced examples highlighting many available features are in examples/NimBLE_Server, NimBLE_Client.
|
||||
|
||||
Beacon examples provided by [beegee-tokyo](https://github.com/beegee-tokyo) are in examples/BLE_Beacon_Scanner, BLE_EddystoneTLM_Beacon, BLE_EddystoneURL_Beacon.
|
||||
|
||||
Change the settings in the nimconfig.h file to customize NimBLE to your project, such as increasing max connections (default == 3).
|
||||
Change the settings in the nimconfig.h file to customize NimBLE to your project, such as increasing max connections (default is 3).
|
||||
<br/>
|
||||
|
||||
**Note To increase max connections in Arduino it is also required to change the controller max connections defined in sdkconfig.h.**
|
||||
|
||||
This is located in your Arduino/hardware/espressif/esp32/tools/sdk/include/config folder.
|
||||
|
||||
The values in `sdkconfig.h` you will need to change are:
|
||||
```
|
||||
#define CONFIG_BTDM_CONTROLLER_BLE_MAX_CONN 3
|
||||
#define CONFIG_BTDM_CONTROLLER_BLE_MAX_CONN_EFF 3
|
||||
```
|
||||
In `nimconfig.h` the value is:
|
||||
```
|
||||
#define CONFIG_BT_NIMBLE_MAX_CONNECTIONS 3
|
||||
```
|
||||
Espressif has stated the hard maximum connections is 9.
|
||||
### Arduino command line and platformio
|
||||
As an alternative to changing the configuration in nimconfig.h, Arduino command line and platformio.ini options are available.
|
||||
See the command line configuration options available in [Command line config](Command_line_config.md).
|
||||
<br/>
|
||||
|
||||
# Need help? Have a question or suggestion?
|
||||
Come chat on [gitter](https://gitter.im/NimBLE-Arduino/community?utm_source=share-link&utm_medium=link&utm_campaign=share-link) or open an issue at [NimBLE-Arduino](https://github.com/h2zero/NimBLE-Arduino/issues) or [esp-nimble-cpp](https://github.com/h2zero/esp-nimble-cpp/issues)
|
||||
<br/>
|
||||
|
||||
# Acknowledgments
|
||||
|
||||
* [nkolban](https://github.com/nkolban) and [chegewara](https://github.com/chegewara) for the [original esp32 BLE library](https://github.com/nkolban/esp32-snippets/tree/master/cpp_utils) this project was derived from.
|
||||
|
||||
@@ -41,6 +41,9 @@ class ServerCallbacks: public NimBLEServerCallbacks {
|
||||
printf("Client disconnected - start advertising\n");
|
||||
NimBLEDevice::startAdvertising();
|
||||
};
|
||||
void onMTUChange(uint16_t MTU, ble_gap_conn_desc* desc) {
|
||||
printf("MTU updated: %u for connection ID: %u\n", MTU, desc->conn_handle);
|
||||
};
|
||||
|
||||
/********************* Security handled here **********************
|
||||
****** Note: these are the same return values as defaults ********/
|
||||
|
||||
312
src/FreeRTOS.cpp
312
src/FreeRTOS.cpp
@@ -1,312 +0,0 @@
|
||||
/*
|
||||
* FreeRTOS.cpp
|
||||
*
|
||||
* Created on: Feb 24, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "NimBLELog.h"
|
||||
|
||||
#include <freertos/FreeRTOS.h> // Include the base FreeRTOS definitions
|
||||
#include <freertos/task.h> // Include the task definitions
|
||||
#include <freertos/semphr.h> // Include the semaphore definitions
|
||||
#include <string>
|
||||
|
||||
static const char* LOG_TAG = "FreeRTOS";
|
||||
|
||||
|
||||
/**
|
||||
* Sleep for the specified number of milliseconds.
|
||||
* @param[in] ms The period in milliseconds for which to sleep.
|
||||
*/
|
||||
void FreeRTOS::sleep(uint32_t ms) {
|
||||
::vTaskDelay(ms / portTICK_PERIOD_MS);
|
||||
} // sleep
|
||||
|
||||
|
||||
/**
|
||||
* Start a new task.
|
||||
* @param[in] task The function pointer to the function to be run in the task.
|
||||
* @param[in] taskName A string identifier for the task.
|
||||
* @param[in] param An optional parameter to be passed to the started task.
|
||||
* @param[in] stackSize An optional paremeter supplying the size of the stack in which to run the task.
|
||||
*/
|
||||
void FreeRTOS::startTask(void task(void*), std::string taskName, void* param, uint32_t stackSize) {
|
||||
::xTaskCreate(task, taskName.data(), stackSize, param, 5, NULL);
|
||||
} // startTask
|
||||
|
||||
|
||||
/**
|
||||
* Delete the task.
|
||||
* @param[in] pTask An optional handle to the task to be deleted. If not supplied the calling task will be deleted.
|
||||
*/
|
||||
void FreeRTOS::deleteTask(TaskHandle_t pTask) {
|
||||
::vTaskDelete(pTask);
|
||||
} // deleteTask
|
||||
|
||||
|
||||
/**
|
||||
* Get the time in milliseconds since the %FreeRTOS scheduler started.
|
||||
* @return The time in milliseconds since the %FreeRTOS scheduler started.
|
||||
*/
|
||||
uint32_t FreeRTOS::getTimeSinceStart() {
|
||||
return (uint32_t) (xTaskGetTickCount() * portTICK_PERIOD_MS);
|
||||
} // getTimeSinceStart
|
||||
|
||||
|
||||
/**
|
||||
* @brief Wait for a semaphore to be released by trying to take it and
|
||||
* then releasing it again.
|
||||
* @param [in] owner A debug tag.
|
||||
* @return The value associated with the semaphore.
|
||||
*/
|
||||
uint32_t FreeRTOS::Semaphore::wait(std::string owner) {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> wait: Semaphore waiting: %s for %s", toString().c_str(), owner.c_str());
|
||||
|
||||
if (m_usePthreads) {
|
||||
pthread_mutex_lock(&m_pthread_mutex);
|
||||
} else {
|
||||
xSemaphoreTake(m_semaphore, portMAX_DELAY);
|
||||
}
|
||||
|
||||
if (m_usePthreads) {
|
||||
pthread_mutex_unlock(&m_pthread_mutex);
|
||||
} else {
|
||||
xSemaphoreGive(m_semaphore);
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< wait: Semaphore released: %s", toString().c_str());
|
||||
return m_value;
|
||||
} // wait
|
||||
|
||||
|
||||
/**
|
||||
* @brief Wait for a semaphore to be released in a given period of time by trying to take it and
|
||||
* then releasing it again. The value associated with the semaphore can be taken by value() call after return
|
||||
* @param [in] owner A debug tag.
|
||||
* @param [in] timeoutMs timeout to wait in ms.
|
||||
* @return True if we took the semaphore within timeframe.
|
||||
*/
|
||||
bool FreeRTOS::Semaphore::timedWait(std::string owner, uint32_t timeoutMs) {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> wait: Semaphore waiting: %s for %s", toString().c_str(), owner.c_str());
|
||||
|
||||
if (m_usePthreads && timeoutMs != portMAX_DELAY) {
|
||||
assert(false); // We apparently don't have a timed wait for pthreads.
|
||||
}
|
||||
|
||||
auto ret = pdTRUE;
|
||||
|
||||
if (m_usePthreads) {
|
||||
pthread_mutex_lock(&m_pthread_mutex);
|
||||
} else {
|
||||
ret = xSemaphoreTake(m_semaphore, timeoutMs);
|
||||
}
|
||||
|
||||
if (m_usePthreads) {
|
||||
pthread_mutex_unlock(&m_pthread_mutex);
|
||||
} else {
|
||||
xSemaphoreGive(m_semaphore);
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< wait: Semaphore %s released: %d", toString().c_str(), ret);
|
||||
return ret;
|
||||
} // wait
|
||||
|
||||
|
||||
/**
|
||||
* @brief Construct a semaphore, the semaphore is given when created.
|
||||
* @param [in] name A name string to provide debugging support.
|
||||
*/
|
||||
FreeRTOS::Semaphore::Semaphore(std::string name) {
|
||||
m_usePthreads = false; // Are we using pThreads or FreeRTOS?
|
||||
if (m_usePthreads) {
|
||||
pthread_mutex_init(&m_pthread_mutex, nullptr);
|
||||
} else {
|
||||
//m_semaphore = xSemaphoreCreateMutex();
|
||||
m_semaphore = xSemaphoreCreateBinary();
|
||||
xSemaphoreGive(m_semaphore);
|
||||
}
|
||||
|
||||
m_name = name;
|
||||
m_owner = std::string("<N/A>");
|
||||
m_value = 0;
|
||||
}
|
||||
|
||||
|
||||
FreeRTOS::Semaphore::~Semaphore() {
|
||||
if (m_usePthreads) {
|
||||
pthread_mutex_destroy(&m_pthread_mutex);
|
||||
} else {
|
||||
vSemaphoreDelete(m_semaphore);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Give the semaphore.
|
||||
*/
|
||||
void FreeRTOS::Semaphore::give() {
|
||||
NIMBLE_LOGD(LOG_TAG, "Semaphore giving: %s", toString().c_str());
|
||||
m_owner = std::string("<N/A>");
|
||||
|
||||
if (m_usePthreads) {
|
||||
pthread_mutex_unlock(&m_pthread_mutex);
|
||||
} else {
|
||||
xSemaphoreGive(m_semaphore);
|
||||
}
|
||||
// #ifdef ARDUINO_ARCH_ESP32
|
||||
// FreeRTOS::sleep(10);
|
||||
// #endif
|
||||
|
||||
} // Semaphore::give
|
||||
|
||||
|
||||
/**
|
||||
* @brief Give a semaphore.
|
||||
* The Semaphore is given with an associated value.
|
||||
* @param [in] value The value to associate with the semaphore.
|
||||
*/
|
||||
void FreeRTOS::Semaphore::give(uint32_t value) {
|
||||
m_value = value;
|
||||
give();
|
||||
} // give
|
||||
|
||||
|
||||
/**
|
||||
* @brief Give a semaphore from an ISR.
|
||||
*/
|
||||
void FreeRTOS::Semaphore::giveFromISR() {
|
||||
BaseType_t higherPriorityTaskWoken;
|
||||
if (m_usePthreads) {
|
||||
assert(false);
|
||||
} else {
|
||||
xSemaphoreGiveFromISR(m_semaphore, &higherPriorityTaskWoken);
|
||||
}
|
||||
} // giveFromISR
|
||||
|
||||
|
||||
/**
|
||||
* @brief Take a semaphore.
|
||||
* Take a semaphore and wait indefinitely.
|
||||
* @param [in] owner The new owner (for debugging)
|
||||
* @return True if we took the semaphore.
|
||||
*/
|
||||
bool FreeRTOS::Semaphore::take(std::string owner) {
|
||||
NIMBLE_LOGD(LOG_TAG, "Semaphore taking: %s for %s", toString().c_str(), owner.c_str());
|
||||
bool rc = false;
|
||||
if (m_usePthreads) {
|
||||
pthread_mutex_lock(&m_pthread_mutex);
|
||||
} else {
|
||||
rc = ::xSemaphoreTake(m_semaphore, portMAX_DELAY) == pdTRUE;
|
||||
}
|
||||
m_owner = owner;
|
||||
if (rc) {
|
||||
NIMBLE_LOGD(LOG_TAG, "Semaphore taken: %s", toString().c_str());
|
||||
} else {
|
||||
NIMBLE_LOGE(LOG_TAG, "Semaphore NOT taken: %s", toString().c_str());
|
||||
}
|
||||
return rc;
|
||||
} // Semaphore::take
|
||||
|
||||
|
||||
/**
|
||||
* @brief Take a semaphore.
|
||||
* Take a semaphore but return if we haven't obtained it in the given period of milliseconds.
|
||||
* @param [in] timeoutMs Timeout in milliseconds.
|
||||
* @param [in] owner The new owner (for debugging)
|
||||
* @return True if we took the semaphore.
|
||||
*/
|
||||
bool FreeRTOS::Semaphore::take(uint32_t timeoutMs, std::string owner) {
|
||||
NIMBLE_LOGD(LOG_TAG, "Semaphore taking: %s for %s", toString().c_str(), owner.c_str());
|
||||
bool rc = false;
|
||||
if (m_usePthreads) {
|
||||
assert(false); // We apparently don't have a timed wait for pthreads.
|
||||
} else {
|
||||
rc = ::xSemaphoreTake(m_semaphore, timeoutMs / portTICK_PERIOD_MS) == pdTRUE;
|
||||
}
|
||||
m_owner = owner;
|
||||
if (rc) {
|
||||
NIMBLE_LOGD(LOG_TAG, "Semaphore taken: %s", toString().c_str());
|
||||
} else {
|
||||
NIMBLE_LOGE(LOG_TAG, "Semaphore NOT taken: %s", toString().c_str());
|
||||
}
|
||||
return rc;
|
||||
} // Semaphore::take
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a string representation of the semaphore.
|
||||
* @return A string representation of the semaphore.
|
||||
*/
|
||||
std::string FreeRTOS::Semaphore::toString() {
|
||||
char hex[9];
|
||||
std::string res = "name: " + m_name + " (0x";
|
||||
snprintf(hex, sizeof(hex), "%08x", (uint32_t)m_semaphore);
|
||||
res += hex;
|
||||
res += "), owner: " + m_owner;
|
||||
return res;
|
||||
} // toString
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the name of the semaphore.
|
||||
* @param [in] name The name of the semaphore.
|
||||
*/
|
||||
void FreeRTOS::Semaphore::setName(std::string name) {
|
||||
m_name = name;
|
||||
} // setName
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a ring buffer.
|
||||
* @param [in] length The amount of storage to allocate for the ring buffer.
|
||||
* @param [in] type The type of buffer. One of RINGBUF_TYPE_NOSPLIT, RINGBUF_TYPE_ALLOWSPLIT, RINGBUF_TYPE_BYTEBUF.
|
||||
*/
|
||||
#ifdef ESP_IDF_VERSION //Quick hack to detect if using IDF version that replaced ringbuf_type_t
|
||||
Ringbuffer::Ringbuffer(size_t length, RingbufferType_t type) {
|
||||
#else
|
||||
Ringbuffer::Ringbuffer(size_t length, ringbuf_type_t type) {
|
||||
#endif
|
||||
m_handle = ::xRingbufferCreate(length, type);
|
||||
} // Ringbuffer
|
||||
|
||||
|
||||
Ringbuffer::~Ringbuffer() {
|
||||
::vRingbufferDelete(m_handle);
|
||||
} // ~Ringbuffer
|
||||
|
||||
|
||||
/**
|
||||
* @brief Receive data from the buffer.
|
||||
* @param [out] size On return, the size of data returned.
|
||||
* @param [in] wait How long to wait.
|
||||
* @return A pointer to the storage retrieved.
|
||||
*/
|
||||
void* Ringbuffer::receive(size_t* size, TickType_t wait) {
|
||||
return ::xRingbufferReceive(m_handle, size, wait);
|
||||
} // receive
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return an item.
|
||||
* @param [in] item The item to be returned/released.
|
||||
*/
|
||||
void Ringbuffer::returnItem(void* item) {
|
||||
::vRingbufferReturnItem(m_handle, item);
|
||||
} // returnItem
|
||||
|
||||
|
||||
/**
|
||||
* @brief Send data to the buffer.
|
||||
* @param [in] data The data to place into the buffer.
|
||||
* @param [in] length The length of data to place into the buffer.
|
||||
* @param [in] wait How long to wait before giving up. The default is to wait indefinitely.
|
||||
* @return
|
||||
*/
|
||||
bool Ringbuffer::send(void* data, size_t length, TickType_t wait) {
|
||||
return ::xRingbufferSend(m_handle, data, length, wait) == pdTRUE;
|
||||
} // send
|
||||
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
* FreeRTOS.h
|
||||
*
|
||||
* Created on: Feb 24, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef MAIN_FREERTOS_H_
|
||||
#define MAIN_FREERTOS_H_
|
||||
|
||||
#include <freertos/FreeRTOS.h> // Include the base FreeRTOS definitions.
|
||||
#include <freertos/task.h> // Include the task definitions.
|
||||
#include <freertos/semphr.h> // Include the semaphore definitions.
|
||||
#include <freertos/ringbuf.h> // Include the ringbuffer definitions.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <pthread.h>
|
||||
|
||||
|
||||
/**
|
||||
* @brief Interface to %FreeRTOS functions.
|
||||
*/
|
||||
class FreeRTOS {
|
||||
public:
|
||||
static void sleep(uint32_t ms);
|
||||
static void startTask(void task(void*), std::string taskName, void* param = nullptr, uint32_t stackSize = 2048);
|
||||
static void deleteTask(TaskHandle_t pTask = nullptr);
|
||||
|
||||
static uint32_t getTimeSinceStart();
|
||||
|
||||
/**
|
||||
* @brief A binary semaphore class that operates like a mutex, it is already given when constructed.
|
||||
*/
|
||||
class Semaphore {
|
||||
public:
|
||||
Semaphore(std::string owner = "<Unknown>");
|
||||
~Semaphore();
|
||||
void give();
|
||||
void give(uint32_t value);
|
||||
void giveFromISR();
|
||||
void setName(std::string name);
|
||||
bool take(std::string owner = "<Unknown>");
|
||||
bool take(uint32_t timeoutMs, std::string owner = "<Unknown>");
|
||||
std::string toString();
|
||||
bool timedWait(std::string owner = "<Unknown>", uint32_t timeoutMs = portMAX_DELAY);
|
||||
uint32_t wait(std::string owner = "<Unknown>");
|
||||
/**
|
||||
* @brief Get the value of the semaphore.
|
||||
* @return The value stored if the semaphore was given with give(value);
|
||||
*/
|
||||
uint32_t value(){ return m_value; };
|
||||
|
||||
private:
|
||||
SemaphoreHandle_t m_semaphore;
|
||||
pthread_mutex_t m_pthread_mutex;
|
||||
std::string m_name;
|
||||
std::string m_owner;
|
||||
uint32_t m_value;
|
||||
bool m_usePthreads;
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief A wrapper class for a freeRTOS ringbuffer.
|
||||
*/
|
||||
class Ringbuffer {
|
||||
public:
|
||||
#ifdef ESP_IDF_VERSION //Quick hack to detect if using IDF version that replaced ringbuf_type_t
|
||||
Ringbuffer(size_t length, RingbufferType_t type = RINGBUF_TYPE_NOSPLIT);
|
||||
#else
|
||||
Ringbuffer(size_t length, ringbuf_type_t type = RINGBUF_TYPE_NOSPLIT);
|
||||
#endif
|
||||
~Ringbuffer();
|
||||
|
||||
void* receive(size_t* size, TickType_t wait = portMAX_DELAY);
|
||||
void returnItem(void* item);
|
||||
bool send(void* data, size_t length, TickType_t wait = portMAX_DELAY);
|
||||
private:
|
||||
RingbufHandle_t m_handle;
|
||||
};
|
||||
|
||||
#endif /* MAIN_FREERTOS_H_ */
|
||||
@@ -16,11 +16,8 @@
|
||||
* See also:
|
||||
* 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"
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
|
||||
#include "NimBLE2904.h"
|
||||
|
||||
@@ -37,7 +34,7 @@ NimBLE2904::NimBLE2904(NimBLECharacteristic* pCharacterisitic)
|
||||
m_data.m_unit = 0;
|
||||
m_data.m_description = 0;
|
||||
setValue((uint8_t*) &m_data, sizeof(m_data));
|
||||
} // BLE2902
|
||||
} // BLE2904
|
||||
|
||||
|
||||
/**
|
||||
@@ -86,5 +83,4 @@ void NimBLE2904::setUnit(uint16_t unit) {
|
||||
setValue((uint8_t*) &m_data, sizeof(m_data));
|
||||
} // setUnit
|
||||
|
||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
#endif
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||
|
||||
@@ -14,11 +14,8 @@
|
||||
|
||||
#ifndef MAIN_NIMBLE2904_H_
|
||||
#define MAIN_NIMBLE2904_H_
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
|
||||
#include "NimBLEDescriptor.h"
|
||||
|
||||
@@ -42,6 +39,7 @@ struct BLE2904_Data {
|
||||
*/
|
||||
class NimBLE2904: public NimBLEDescriptor {
|
||||
public:
|
||||
NimBLE2904(NimBLECharacteristic* pCharacterisitic = nullptr);
|
||||
static const uint8_t FORMAT_BOOLEAN = 1;
|
||||
static const uint8_t FORMAT_UINT2 = 2;
|
||||
static const uint8_t FORMAT_UINT4 = 3;
|
||||
@@ -77,11 +75,9 @@ public:
|
||||
void setUnit(uint16_t unit);
|
||||
|
||||
private:
|
||||
NimBLE2904(NimBLECharacteristic* pCharacterisitic);
|
||||
friend class NimBLECharacteristic;
|
||||
BLE2904_Data m_data;
|
||||
}; // BLE2904
|
||||
|
||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||
#endif /* MAIN_NIMBLE2904_H_ */
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
* Created on: Jul 2, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@@ -14,10 +14,15 @@
|
||||
|
||||
#ifndef COMPONENTS_NIMBLEADDRESS_H_
|
||||
#define COMPONENTS_NIMBLEADDRESS_H_
|
||||
#include "sdkconfig.h"
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
#include "nimble/ble.h"
|
||||
#else
|
||||
#include "nimble/nimble/include/nimble/ble.h"
|
||||
#endif
|
||||
|
||||
/**** FIX COMPILATION ****/
|
||||
#undef min
|
||||
#undef max
|
||||
|
||||
@@ -11,11 +11,9 @@
|
||||
* Created on: Jul 3, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#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 "NimBLEAdvertisedDevice.h"
|
||||
@@ -28,25 +26,14 @@ static const char* LOG_TAG = "NimBLEAdvertisedDevice";
|
||||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
NimBLEAdvertisedDevice::NimBLEAdvertisedDevice() {
|
||||
NimBLEAdvertisedDevice::NimBLEAdvertisedDevice() :
|
||||
m_payload(62,0)
|
||||
{
|
||||
m_advType = 0;
|
||||
m_appearance = 0;
|
||||
m_manufacturerData = "";
|
||||
m_name = "";
|
||||
m_rssi = -9999;
|
||||
m_txPower = 0;
|
||||
m_payloadLength = 0;
|
||||
m_payload = nullptr;
|
||||
|
||||
m_haveAppearance = false;
|
||||
m_haveManufacturerData = false;
|
||||
m_haveName = false;
|
||||
m_haveRSSI = false;
|
||||
m_haveServiceData = false;
|
||||
m_haveServiceUUID = false;
|
||||
m_haveTXPower = false;
|
||||
m_callbackSent = false;
|
||||
|
||||
m_callbackSent = false;
|
||||
m_timestamp = 0;
|
||||
m_advLength = 0;
|
||||
} // NimBLEAdvertisedDevice
|
||||
|
||||
|
||||
@@ -82,25 +69,126 @@ uint8_t NimBLEAdvertisedDevice::getAdvType() {
|
||||
* @return The appearance of the advertised device.
|
||||
*/
|
||||
uint16_t NimBLEAdvertisedDevice::getAppearance() {
|
||||
return m_appearance;
|
||||
uint8_t data_loc = 0;
|
||||
|
||||
if(findAdvField(BLE_HS_ADV_TYPE_APPEARANCE, 0, &data_loc) > 0) {
|
||||
ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||
if(field->length == BLE_HS_ADV_APPEARANCE_LEN + 1) {
|
||||
return *field->value | *(field->value + 1) << 8;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
} // getAppearance
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the advertisement interval.
|
||||
* @return The advertisement interval in 0.625ms units.
|
||||
*/
|
||||
uint16_t NimBLEAdvertisedDevice::getAdvInterval() {
|
||||
uint8_t data_loc = 0;
|
||||
|
||||
if(findAdvField(BLE_HS_ADV_TYPE_ADV_ITVL, 0, &data_loc) > 0) {
|
||||
ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||
if(field->length == BLE_HS_ADV_ADV_ITVL_LEN + 1) {
|
||||
return *field->value | *(field->value + 1) << 8;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
} // getAdvInterval
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the preferred min connection interval.
|
||||
* @return The preferred min connection interval in 1.25ms units.
|
||||
*/
|
||||
uint16_t NimBLEAdvertisedDevice::getMinInterval() {
|
||||
uint8_t data_loc = 0;
|
||||
|
||||
if(findAdvField(BLE_HS_ADV_TYPE_SLAVE_ITVL_RANGE, 0, &data_loc) > 0) {
|
||||
ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||
if(field->length == BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN + 1) {
|
||||
return *field->value | *(field->value + 1) << 8;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
} // getMinInterval
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the preferred max connection interval.
|
||||
* @return The preferred max connection interval in 1.25ms units.
|
||||
*/
|
||||
uint16_t NimBLEAdvertisedDevice::getMaxInterval() {
|
||||
uint8_t data_loc = 0;
|
||||
|
||||
if(findAdvField(BLE_HS_ADV_TYPE_SLAVE_ITVL_RANGE, 0, &data_loc) > 0) {
|
||||
ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||
if(field->length == BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN + 1) {
|
||||
return *(field->value + 2) | *(field->value + 3) << 8;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
} // getMaxInterval
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the manufacturer data.
|
||||
* @return The manufacturer data of the advertised device.
|
||||
*/
|
||||
std::string NimBLEAdvertisedDevice::getManufacturerData() {
|
||||
return m_manufacturerData;
|
||||
uint8_t data_loc = 0;
|
||||
|
||||
if(findAdvField(BLE_HS_ADV_TYPE_MFG_DATA, 0, &data_loc) > 0) {
|
||||
ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||
if(field->length > 1) {
|
||||
return std::string((char*)field->value, field->length - 1);
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
} // getManufacturerData
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the URI from the advertisement.
|
||||
* @return The URI data.
|
||||
*/
|
||||
std::string NimBLEAdvertisedDevice::getURI() {
|
||||
uint8_t data_loc = 0;
|
||||
|
||||
if(findAdvField(BLE_HS_ADV_TYPE_URI, 0, &data_loc) > 0) {
|
||||
ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||
if(field->length > 1) {
|
||||
return std::string((char*)field->value, field->length - 1);
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
} // getURI
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the advertised name.
|
||||
* @return The name of the advertised device.
|
||||
*/
|
||||
std::string NimBLEAdvertisedDevice::getName() {
|
||||
return m_name;
|
||||
uint8_t data_loc = 0;
|
||||
|
||||
if(findAdvField(BLE_HS_ADV_TYPE_COMP_NAME, 0, &data_loc) > 0 ||
|
||||
findAdvField(BLE_HS_ADV_TYPE_INCOMP_NAME, 0, &data_loc) > 0)
|
||||
{
|
||||
ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||
if(field->length > 1) {
|
||||
return std::string((char*)field->value, field->length - 1);
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
} // getName
|
||||
|
||||
|
||||
@@ -122,17 +210,70 @@ NimBLEScan* NimBLEAdvertisedDevice::getScan() {
|
||||
} // getScan
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the number of target addresses.
|
||||
* @return The number of addresses.
|
||||
*/
|
||||
size_t NimBLEAdvertisedDevice::getTargetAddressCount() {
|
||||
uint8_t count = 0;
|
||||
|
||||
count = findAdvField(BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR);
|
||||
count += findAdvField(BLE_HS_ADV_TYPE_RANDOM_TGT_ADDR);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the target address at the index.
|
||||
* @param [in] index The index of the target address.
|
||||
* @return The target address.
|
||||
*/
|
||||
NimBLEAddress NimBLEAdvertisedDevice::getTargetAddress(uint8_t index) {
|
||||
ble_hs_adv_field *field = nullptr;
|
||||
uint8_t count = 0;
|
||||
uint8_t data_loc = 0xFF;
|
||||
|
||||
index++;
|
||||
count = findAdvField(BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR, index, &data_loc);
|
||||
|
||||
if (count < index) {
|
||||
index -= count;
|
||||
count = findAdvField(BLE_HS_ADV_TYPE_RANDOM_TGT_ADDR, index, &data_loc);
|
||||
}
|
||||
|
||||
if(count > 0 && data_loc != 0xFF) {
|
||||
field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||
if(field->length < index * BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN) {
|
||||
index -= count - field->length / BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN;
|
||||
}
|
||||
if(field->length > index * BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN) {
|
||||
return NimBLEAddress(field->value + (index - 1) * BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN);
|
||||
}
|
||||
}
|
||||
|
||||
return NimBLEAddress("");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the service data.
|
||||
* @param [in] index The vector index of the service data requested.
|
||||
* @param [in] index The index of the service data requested.
|
||||
* @return The advertised service data or empty string if no data.
|
||||
*/
|
||||
std::string NimBLEAdvertisedDevice::getServiceData(uint8_t index) {
|
||||
if(index > m_serviceDataVec.size()) {
|
||||
NIMBLE_LOGW(LOG_TAG, "getServiceData: index out of range");
|
||||
return "";
|
||||
ble_hs_adv_field *field = nullptr;
|
||||
uint8_t bytes;
|
||||
uint8_t data_loc = findServiceData(index, &bytes);
|
||||
|
||||
if(data_loc != 0xFF) {
|
||||
field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||
if(field->length > bytes) {
|
||||
return std::string((char*)(field->value + bytes), field->length - bytes - 1);
|
||||
}
|
||||
}
|
||||
return m_serviceDataVec[index].second;
|
||||
|
||||
return "";
|
||||
} //getServiceData
|
||||
|
||||
|
||||
@@ -141,51 +282,148 @@ std::string NimBLEAdvertisedDevice::getServiceData(uint8_t index) {
|
||||
* @param [in] uuid The uuid of the service data requested.
|
||||
* @return The advertised service data or empty string if no data.
|
||||
*/
|
||||
std::string NimBLEAdvertisedDevice::getServiceData(const NimBLEUUID &uuid) const {
|
||||
for(auto &it : m_serviceDataVec) {
|
||||
if(it.first == uuid) {
|
||||
return it.second;
|
||||
std::string NimBLEAdvertisedDevice::getServiceData(const NimBLEUUID &uuid) {
|
||||
ble_hs_adv_field *field = nullptr;
|
||||
uint8_t bytes;
|
||||
uint8_t index = 0;
|
||||
uint8_t data_loc = findServiceData(index, &bytes);
|
||||
uint8_t uuidBytes = uuid.bitSize() / 8;
|
||||
uint8_t plSize = m_payload.size() - 2;
|
||||
|
||||
while(data_loc < plSize) {
|
||||
field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||
if(bytes == uuidBytes && NimBLEUUID(field->value, bytes, false) == uuid) {
|
||||
return std::string((char*)(field->value + bytes), field->length - bytes - 1);
|
||||
}
|
||||
|
||||
index++;
|
||||
data_loc = findServiceData(index, &bytes);
|
||||
}
|
||||
NIMBLE_LOGW(LOG_TAG, "getServiceData: uuid not found");
|
||||
|
||||
NIMBLE_LOGI(LOG_TAG, "No service data found");
|
||||
return "";
|
||||
} //getServiceData
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the advertised service UUID.
|
||||
* @param [in] index The vector index of the service data UUID requested.
|
||||
* @return The advertised service UUID or an empty UUID if not found.
|
||||
* @brief Get the UUID of the serice data at the index.
|
||||
* @param [in] index The index of the service data UUID requested.
|
||||
* @return The advertised service data UUID or an empty UUID if not found.
|
||||
*/
|
||||
NimBLEUUID NimBLEAdvertisedDevice::getServiceDataUUID(uint8_t index) {
|
||||
if(!haveServiceData() || index > m_serviceDataVec.size()) {
|
||||
NIMBLE_LOGW(LOG_TAG, "getServiceDataUUID: index out of range");
|
||||
return NimBLEUUID("");
|
||||
ble_hs_adv_field *field = nullptr;
|
||||
uint8_t bytes;
|
||||
uint8_t data_loc = findServiceData(index, &bytes);
|
||||
|
||||
if(data_loc != 0xFF) {
|
||||
field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||
if(field->length >= bytes) {
|
||||
return NimBLEUUID(field->value, bytes, false);
|
||||
}
|
||||
}
|
||||
return m_serviceDataVec[index].first;
|
||||
|
||||
return NimBLEUUID("");
|
||||
} // getServiceDataUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Find the service data at the index.
|
||||
* @param [in] index The index of the service data to find.
|
||||
* @param [in] bytes A pointer to storage for the number of the bytes in the UUID.
|
||||
* @return The index in the vector where the data is located, 0xFF if not found.
|
||||
*/
|
||||
uint8_t NimBLEAdvertisedDevice::findServiceData(uint8_t index, uint8_t *bytes) {
|
||||
uint8_t data_loc = 0;
|
||||
uint8_t found = 0;
|
||||
|
||||
*bytes = 0;
|
||||
index++;
|
||||
found = findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID16, index, &data_loc);
|
||||
if(found == index) {
|
||||
*bytes = 2;
|
||||
return data_loc;
|
||||
}
|
||||
|
||||
index -= found;
|
||||
found = findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID32, index, &data_loc);
|
||||
if(found == index) {
|
||||
*bytes = 4;
|
||||
return data_loc;
|
||||
}
|
||||
|
||||
index -= found;
|
||||
found = findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID128, index, &data_loc);
|
||||
if(found == index) {
|
||||
*bytes = 16;
|
||||
return data_loc;
|
||||
}
|
||||
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the count of advertised service data UUIDS
|
||||
* @return The number of service data UUIDS in the vector.
|
||||
*/
|
||||
size_t NimBLEAdvertisedDevice::getServiceDataCount() {
|
||||
return m_serviceDataVec.size();
|
||||
uint8_t count = 0;
|
||||
|
||||
count += findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID16);
|
||||
count += findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID32);
|
||||
count += findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID128);
|
||||
|
||||
return count;
|
||||
} // getServiceDataCount
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the Service UUID.
|
||||
* @param [in] index The vector index of the service UUID requested.
|
||||
* @param [in] index The index of the service UUID requested.
|
||||
* @return The Service UUID of the advertised service, or an empty UUID if not found.
|
||||
*/
|
||||
NimBLEUUID NimBLEAdvertisedDevice::getServiceUUID(uint8_t index) {
|
||||
if(!haveServiceUUID() || index > m_serviceUUIDs.size()) {
|
||||
NIMBLE_LOGW(LOG_TAG, "getServiceUUID: index out of range");
|
||||
return NimBLEUUID("");
|
||||
uint8_t count = 0;
|
||||
uint8_t data_loc = 0;
|
||||
uint8_t uuidBytes = 0;
|
||||
uint8_t type = BLE_HS_ADV_TYPE_INCOMP_UUIDS16;
|
||||
ble_hs_adv_field *field = nullptr;
|
||||
|
||||
index++;
|
||||
|
||||
do {
|
||||
count = findAdvField(type, index, &data_loc);
|
||||
if(count >= index) {
|
||||
if(type < BLE_HS_ADV_TYPE_INCOMP_UUIDS32) {
|
||||
uuidBytes = 2;
|
||||
} else if(type < BLE_HS_ADV_TYPE_INCOMP_UUIDS128) {
|
||||
uuidBytes = 4;
|
||||
} else {
|
||||
uuidBytes = 16;
|
||||
}
|
||||
break;
|
||||
|
||||
} else {
|
||||
type++;
|
||||
index -= count;
|
||||
}
|
||||
|
||||
} while(type <= BLE_HS_ADV_TYPE_COMP_UUIDS128);
|
||||
|
||||
if(uuidBytes > 0) {
|
||||
field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||
// In the case of more than one field of service uuid's we need to adjust
|
||||
// the index to account for the uuids of the previous fields.
|
||||
if(field->length < index * uuidBytes) {
|
||||
index -= count - field->length / uuidBytes;
|
||||
}
|
||||
|
||||
if(field->length > uuidBytes * index) {
|
||||
return NimBLEUUID(field->value + uuidBytes * (index - 1), uuidBytes, false);
|
||||
}
|
||||
}
|
||||
return m_serviceUUIDs[index];
|
||||
|
||||
return NimBLEUUID("");
|
||||
} // getServiceUUID
|
||||
|
||||
|
||||
@@ -194,18 +432,32 @@ NimBLEUUID NimBLEAdvertisedDevice::getServiceUUID(uint8_t index) {
|
||||
* @return The count of services in the advertising packet.
|
||||
*/
|
||||
size_t NimBLEAdvertisedDevice::getServiceUUIDCount() {
|
||||
return m_serviceUUIDs.size();
|
||||
uint8_t count = 0;
|
||||
|
||||
count += findAdvField(BLE_HS_ADV_TYPE_INCOMP_UUIDS16);
|
||||
count += findAdvField(BLE_HS_ADV_TYPE_COMP_UUIDS16);
|
||||
count += findAdvField(BLE_HS_ADV_TYPE_INCOMP_UUIDS32);
|
||||
count += findAdvField(BLE_HS_ADV_TYPE_COMP_UUIDS32);
|
||||
count += findAdvField(BLE_HS_ADV_TYPE_INCOMP_UUIDS128);
|
||||
count += findAdvField(BLE_HS_ADV_TYPE_COMP_UUIDS128);
|
||||
|
||||
return count;
|
||||
} // getServiceUUIDCount
|
||||
|
||||
|
||||
/**
|
||||
* @brief Check advertised services for existance of the required UUID
|
||||
* @param [in] uuid The service uuid to look for in the advertisement.
|
||||
* @return Return true if service is advertised
|
||||
*/
|
||||
bool NimBLEAdvertisedDevice::isAdvertisingService(const NimBLEUUID &uuid) const {
|
||||
for (int i = 0; i < m_serviceUUIDs.size(); i++) {
|
||||
if (m_serviceUUIDs[i].equals(uuid)) return true;
|
||||
bool NimBLEAdvertisedDevice::isAdvertisingService(const NimBLEUUID &uuid) {
|
||||
size_t count = getServiceUUIDCount();
|
||||
for(size_t i = 0; i < count; i++) {
|
||||
if(uuid == getServiceUUID(i)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
} // isAdvertisingService
|
||||
|
||||
@@ -215,16 +467,43 @@ bool NimBLEAdvertisedDevice::isAdvertisingService(const NimBLEUUID &uuid) const
|
||||
* @return The TX Power of the advertised device.
|
||||
*/
|
||||
int8_t NimBLEAdvertisedDevice::getTXPower() {
|
||||
return m_txPower;
|
||||
uint8_t data_loc = 0;
|
||||
|
||||
if(findAdvField(BLE_HS_ADV_TYPE_TX_PWR_LVL, 0, &data_loc) > 0) {
|
||||
ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||
if(field->length == BLE_HS_ADV_TX_PWR_LVL_LEN + 1) {
|
||||
return *(int8_t*)field->value;
|
||||
}
|
||||
}
|
||||
|
||||
return -99;
|
||||
} // getTXPower
|
||||
|
||||
|
||||
/**
|
||||
* @brief Does this advertisement have preferred connection parameters?
|
||||
* @return True if connection parameters are present.
|
||||
*/
|
||||
bool NimBLEAdvertisedDevice::haveConnParams() {
|
||||
return findAdvField(BLE_HS_ADV_TYPE_SLAVE_ITVL_RANGE) > 0;
|
||||
} // haveConnParams
|
||||
|
||||
|
||||
/**
|
||||
* @brief Does this advertisement have have the advertising interval?
|
||||
* @return True if the advertisement interval is present.
|
||||
*/
|
||||
bool NimBLEAdvertisedDevice::haveAdvInterval() {
|
||||
return findAdvField(BLE_HS_ADV_TYPE_ADV_ITVL) > 0;
|
||||
} // haveAdvInterval
|
||||
|
||||
|
||||
/**
|
||||
* @brief Does this advertisement have an appearance value?
|
||||
* @return True if there is an appearance value present.
|
||||
*/
|
||||
bool NimBLEAdvertisedDevice::haveAppearance() {
|
||||
return m_haveAppearance;
|
||||
return findAdvField(BLE_HS_ADV_TYPE_APPEARANCE) > 0;
|
||||
} // haveAppearance
|
||||
|
||||
|
||||
@@ -233,16 +512,36 @@ bool NimBLEAdvertisedDevice::haveAppearance() {
|
||||
* @return True if there is manufacturer data present.
|
||||
*/
|
||||
bool NimBLEAdvertisedDevice::haveManufacturerData() {
|
||||
return m_haveManufacturerData;
|
||||
return findAdvField(BLE_HS_ADV_TYPE_MFG_DATA) > 0;
|
||||
} // haveManufacturerData
|
||||
|
||||
|
||||
/**
|
||||
* @brief Does this advertisement have a URI?
|
||||
* @return True if there is a URI present.
|
||||
*/
|
||||
bool NimBLEAdvertisedDevice::haveURI() {
|
||||
return findAdvField(BLE_HS_ADV_TYPE_URI) > 0;
|
||||
} // haveURI
|
||||
|
||||
|
||||
/**
|
||||
* @brief Does the advertisement contain a target address?
|
||||
* @return True if an address is present.
|
||||
*/
|
||||
bool NimBLEAdvertisedDevice::haveTargetAddress() {
|
||||
return findAdvField(BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR) > 0 ||
|
||||
findAdvField(BLE_HS_ADV_TYPE_RANDOM_TGT_ADDR) > 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Does this advertisement have a name value?
|
||||
* @return True if there is a name value present.
|
||||
*/
|
||||
bool NimBLEAdvertisedDevice::haveName() {
|
||||
return m_haveName;
|
||||
return findAdvField(BLE_HS_ADV_TYPE_COMP_NAME) > 0 ||
|
||||
findAdvField(BLE_HS_ADV_TYPE_INCOMP_NAME) > 0;
|
||||
} // haveName
|
||||
|
||||
|
||||
@@ -251,7 +550,7 @@ bool NimBLEAdvertisedDevice::haveName() {
|
||||
* @return True if there is a signal strength value present.
|
||||
*/
|
||||
bool NimBLEAdvertisedDevice::haveRSSI() {
|
||||
return m_haveRSSI;
|
||||
return m_rssi != -9999;
|
||||
} // haveRSSI
|
||||
|
||||
|
||||
@@ -260,7 +559,7 @@ bool NimBLEAdvertisedDevice::haveRSSI() {
|
||||
* @return True if there is a service data value present.
|
||||
*/
|
||||
bool NimBLEAdvertisedDevice::haveServiceData() {
|
||||
return m_haveServiceData;
|
||||
return getServiceDataCount() > 0;
|
||||
} // haveServiceData
|
||||
|
||||
|
||||
@@ -269,7 +568,7 @@ bool NimBLEAdvertisedDevice::haveServiceData() {
|
||||
* @return True if there is a service UUID value present.
|
||||
*/
|
||||
bool NimBLEAdvertisedDevice::haveServiceUUID() {
|
||||
return m_haveServiceUUID;
|
||||
return getServiceUUIDCount() > 0;
|
||||
} // haveServiceUUID
|
||||
|
||||
|
||||
@@ -278,143 +577,71 @@ bool NimBLEAdvertisedDevice::haveServiceUUID() {
|
||||
* @return True if there is a transmission power value present.
|
||||
*/
|
||||
bool NimBLEAdvertisedDevice::haveTXPower() {
|
||||
return m_haveTXPower;
|
||||
return findAdvField(BLE_HS_ADV_TYPE_TX_PWR_LVL) > 0;
|
||||
} // haveTXPower
|
||||
|
||||
|
||||
/**
|
||||
* @brief Parse the advertising pay load.
|
||||
*
|
||||
* The pay load is a buffer of bytes that is either 31 bytes long or terminated by
|
||||
* a 0 length value. Each entry in the buffer has the format:
|
||||
* [length][type][data...]
|
||||
*
|
||||
* The length does not include itself but does include everything after it until the next record. A record
|
||||
* with a length value of 0 indicates a terminator.
|
||||
*
|
||||
* https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile
|
||||
*/
|
||||
void NimBLEAdvertisedDevice::parseAdvertisement(uint8_t* payload, uint8_t length) {
|
||||
struct ble_hs_adv_fields fields;
|
||||
int rc = ble_hs_adv_parse_fields(&fields, payload, length);
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Gap Event Parse ERROR.");
|
||||
return;
|
||||
uint8_t NimBLEAdvertisedDevice::findAdvField(uint8_t type, uint8_t index, uint8_t *data_loc) {
|
||||
ble_hs_adv_field *field = nullptr;
|
||||
uint8_t data = 0;
|
||||
uint8_t length = m_payload.size();
|
||||
uint8_t count = 0;
|
||||
|
||||
if(length < 2) {
|
||||
return count;
|
||||
}
|
||||
|
||||
m_payload = payload;
|
||||
m_payloadLength = length;
|
||||
while (length > 1) {
|
||||
field = (ble_hs_adv_field*)&m_payload[data];
|
||||
|
||||
#if CONFIG_LOG_DEFAULT_LEVEL > 3 || (ARDUINO_ARCH_ESP32 && CORE_DEBUG_LEVEL >= 4)
|
||||
char* pHex = NimBLEUtils::buildHexData(nullptr, m_payload, m_payloadLength);
|
||||
NIMBLE_LOGD(LOG_TAG,"payload: %s", pHex);
|
||||
free(pHex);
|
||||
#endif
|
||||
|
||||
if (fields.uuids16 != NULL) {
|
||||
for (int i = 0; i < fields.num_uuids16; i++) {
|
||||
setServiceUUID(NimBLEUUID(fields.uuids16[i].value));
|
||||
if (field->length >= length) {
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
if (fields.uuids32 != NULL) {
|
||||
for (int i = 0; i < fields.num_uuids32; i++) {
|
||||
setServiceUUID(NimBLEUUID(fields.uuids32[i].value));
|
||||
}
|
||||
}
|
||||
if (field->type == type) {
|
||||
switch(type) {
|
||||
case BLE_HS_ADV_TYPE_INCOMP_UUIDS16:
|
||||
case BLE_HS_ADV_TYPE_COMP_UUIDS16:
|
||||
count += field->length / 2;
|
||||
break;
|
||||
|
||||
if (fields.uuids128 != NULL) {
|
||||
for (int i = 0; i < fields.num_uuids128; i++) {
|
||||
setServiceUUID(NimBLEUUID(&fields.uuids128[i]));
|
||||
}
|
||||
}
|
||||
case BLE_HS_ADV_TYPE_INCOMP_UUIDS32:
|
||||
case BLE_HS_ADV_TYPE_COMP_UUIDS32:
|
||||
count += field->length / 4;
|
||||
break;
|
||||
|
||||
if (fields.name != NULL) {
|
||||
setName(std::string(reinterpret_cast<char*>(fields.name), fields.name_len));
|
||||
}
|
||||
case BLE_HS_ADV_TYPE_INCOMP_UUIDS128:
|
||||
case BLE_HS_ADV_TYPE_COMP_UUIDS128:
|
||||
count += field->length / 16;
|
||||
break;
|
||||
|
||||
if (fields.tx_pwr_lvl_is_present) {
|
||||
setTXPower(fields.tx_pwr_lvl);
|
||||
}
|
||||
case BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR:
|
||||
case BLE_HS_ADV_TYPE_RANDOM_TGT_ADDR:
|
||||
count += field->length / 6;
|
||||
break;
|
||||
|
||||
if (fields.svc_data_uuid16 != NULL ||
|
||||
fields.svc_data_uuid32 != NULL ||
|
||||
fields.svc_data_uuid128 != NULL)
|
||||
{
|
||||
ble_hs_adv_field *field;
|
||||
uint8_t *data = payload;
|
||||
while(length > 1) {
|
||||
field = (ble_hs_adv_field*)data;
|
||||
|
||||
if(field->length > length) {
|
||||
break;
|
||||
default:
|
||||
count++;
|
||||
break;
|
||||
}
|
||||
|
||||
if(field->type == BLE_HS_ADV_TYPE_SVC_DATA_UUID16) {
|
||||
if(field->length > 2) {
|
||||
uint16_t uuid;
|
||||
memcpy(&uuid, field->value, 2);
|
||||
setServiceData(NimBLEUUID(uuid), std::string(reinterpret_cast<char*>(field->value + 2), field->length - 3));
|
||||
if(data_loc != nullptr) {
|
||||
if(index == 0 || count >= index) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(field->type == BLE_HS_ADV_TYPE_SVC_DATA_UUID32) {
|
||||
if(field->length > 4) {
|
||||
uint32_t uuid;
|
||||
memcpy(&uuid, field->value, 4);
|
||||
setServiceData(NimBLEUUID(uuid), std::string(reinterpret_cast<char*>(field->value + 4), field->length - 5));
|
||||
}
|
||||
}
|
||||
|
||||
if(field->type == BLE_HS_ADV_TYPE_SVC_DATA_UUID128) {
|
||||
if(field->length > 16) {
|
||||
NimBLEUUID uuid(field->value, (size_t)16, false);
|
||||
setServiceData(uuid, std::string(reinterpret_cast<char*>(field->value + 16), field->length - 17));
|
||||
}
|
||||
}
|
||||
|
||||
length -= 1 + field->length;
|
||||
data += 1 + field->length;
|
||||
}
|
||||
|
||||
length -= 1 + field->length;
|
||||
data += 1 + field->length;
|
||||
}
|
||||
|
||||
if (fields.appearance_is_present) {
|
||||
setAppearance(fields.appearance);
|
||||
if(data_loc != nullptr && field != nullptr) {
|
||||
*data_loc = data;
|
||||
}
|
||||
|
||||
if (fields.mfg_data != NULL) {
|
||||
setManufacturerData(std::string(reinterpret_cast<char*>(fields.mfg_data), fields.mfg_data_len));
|
||||
}
|
||||
|
||||
/* TODO: create storage and fucntions for these parameters
|
||||
if (fields.public_tgt_addr != NULL) {
|
||||
NIMBLE_LOGD(LOG_TAG, " public_tgt_addr=");
|
||||
u8p = fields.public_tgt_addr;
|
||||
for (i = 0; i < fields.num_public_tgt_addrs; i++) {
|
||||
NIMBLE_LOGD(LOG_TAG, "public_tgt_addr=%s ", addr_str(u8p));
|
||||
u8p += BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN;
|
||||
}
|
||||
NIMBLE_LOGD(LOG_TAG, "\n");
|
||||
}
|
||||
|
||||
if (fields.slave_itvl_range != NULL) {
|
||||
NIMBLE_LOGD(LOG_TAG, " slave_itvl_range=");
|
||||
print_bytes(fields.slave_itvl_range, BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN);
|
||||
NIMBLE_LOGD(LOG_TAG, "\n");
|
||||
}
|
||||
|
||||
if (fields.adv_itvl_is_present) {
|
||||
NIMBLE_LOGD(LOG_TAG, " adv_itvl=0x%04x\n", fields.adv_itvl);
|
||||
}
|
||||
|
||||
if (fields.uri != NULL) {
|
||||
NIMBLE_LOGD(LOG_TAG, " uri=");
|
||||
print_bytes(fields.uri, fields.uri_len);
|
||||
NIMBLE_LOGD(LOG_TAG, "\n");
|
||||
}
|
||||
*/
|
||||
|
||||
} //parseAdvertisement
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -428,106 +655,22 @@ void NimBLEAdvertisedDevice::setAddress(NimBLEAddress address) {
|
||||
|
||||
/**
|
||||
* @brief Set the adFlag for this device.
|
||||
* @param [in] The discovered adFlag.
|
||||
* @param [in] advType The advertisement flag data from the advertisement.
|
||||
*/
|
||||
void NimBLEAdvertisedDevice::setAdvType(uint8_t advType) {
|
||||
m_advType = advType;
|
||||
} // setAdvType
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the appearance for this device.
|
||||
* @param [in] The discovered appearance.
|
||||
*/
|
||||
void NimBLEAdvertisedDevice::setAppearance(uint16_t appearance) {
|
||||
m_appearance = appearance;
|
||||
m_haveAppearance = true;
|
||||
} // setAppearance
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the manufacturer data for this device.
|
||||
* @param [in] The discovered manufacturer data.
|
||||
*/
|
||||
void NimBLEAdvertisedDevice::setManufacturerData(std::string manufacturerData) {
|
||||
m_manufacturerData = manufacturerData;
|
||||
m_haveManufacturerData = true;
|
||||
} // setManufacturerData
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the name for this device.
|
||||
* @param [in] name The discovered name.
|
||||
*/
|
||||
void NimBLEAdvertisedDevice::setName(std::string name) {
|
||||
m_name = name;
|
||||
m_haveName = true;
|
||||
} // setName
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the RSSI for this device.
|
||||
* @param [in] rssi The discovered RSSI.
|
||||
* @param [in] rssi The RSSI of the discovered device.
|
||||
*/
|
||||
void NimBLEAdvertisedDevice::setRSSI(int rssi) {
|
||||
m_rssi = rssi;
|
||||
m_haveRSSI = true;
|
||||
m_rssi = rssi;
|
||||
} // setRSSI
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the Service UUID for this device.
|
||||
* @param [in] serviceUUID The discovered serviceUUID
|
||||
*/
|
||||
|
||||
void NimBLEAdvertisedDevice::setServiceUUID(const char* serviceUUID) {
|
||||
return setServiceUUID(NimBLEUUID(serviceUUID));
|
||||
} // setServiceUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the Service UUID for this device.
|
||||
* @param [in] serviceUUID The discovered serviceUUID
|
||||
*/
|
||||
void NimBLEAdvertisedDevice::setServiceUUID(NimBLEUUID serviceUUID) {
|
||||
// Don't add duplicates
|
||||
for (int i = 0; i < m_serviceUUIDs.size(); i++) {
|
||||
if (m_serviceUUIDs[i] == serviceUUID) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
m_serviceUUIDs.push_back(serviceUUID);
|
||||
m_haveServiceUUID = true;
|
||||
} // setServiceUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the ServiceData value.
|
||||
* @param [in] uuid The UUID that the service data belongs to.
|
||||
* @param [in] data The service data.
|
||||
*/
|
||||
void NimBLEAdvertisedDevice::setServiceData(NimBLEUUID uuid, std::string data) {
|
||||
m_haveServiceData = true;
|
||||
for(auto &it : m_serviceDataVec) {
|
||||
if(it.first == uuid) {
|
||||
it.second = data;
|
||||
return;
|
||||
}
|
||||
}
|
||||
m_serviceDataVec.push_back({uuid, data});
|
||||
} //setServiceData
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the power level for this device.
|
||||
* @param [in] txPower The discovered power level.
|
||||
*/
|
||||
void NimBLEAdvertisedDevice::setTXPower(int8_t txPower) {
|
||||
m_txPower = txPower;
|
||||
m_haveTXPower = true;
|
||||
} // setTXPower
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a string representation of this device.
|
||||
* @return A string representation of this device.
|
||||
@@ -579,10 +722,35 @@ std::string NimBLEAdvertisedDevice::toString() {
|
||||
* @return The advertisement payload.
|
||||
*/
|
||||
uint8_t* NimBLEAdvertisedDevice::getPayload() {
|
||||
return m_payload;
|
||||
return &m_payload[0];
|
||||
} // getPayload
|
||||
|
||||
|
||||
/**
|
||||
* @brief Stores the payload of the advertised device in a vector.
|
||||
* @param [in] payload The advertisement payload.
|
||||
* @param [in] length The length of the payload in bytes.
|
||||
* @param [in] append Indicates if the the data should be appended (scan response).
|
||||
*/
|
||||
void NimBLEAdvertisedDevice::setPayload(const uint8_t *payload, uint8_t length, bool append) {
|
||||
if(!append) {
|
||||
m_advLength = length;
|
||||
m_payload.assign(payload, payload + length);
|
||||
} else {
|
||||
m_payload.insert(m_payload.end(), payload, payload + length);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the length of the advertisement data in the payload.
|
||||
* @return The number of bytes in the payload that is from the advertisment.
|
||||
*/
|
||||
uint8_t NimBLEAdvertisedDevice::getAdvLength() {
|
||||
return m_advLength;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the advertised device address type.
|
||||
* @return The device address type:
|
||||
@@ -610,10 +778,8 @@ time_t NimBLEAdvertisedDevice::getTimestamp() {
|
||||
* @return The size of the payload in bytes.
|
||||
*/
|
||||
size_t NimBLEAdvertisedDevice::getPayloadLength() {
|
||||
return m_payloadLength;
|
||||
return m_payload.size();
|
||||
} // getPayloadLength
|
||||
|
||||
|
||||
#endif // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|
||||
|
||||
|
||||
@@ -14,20 +14,22 @@
|
||||
|
||||
#ifndef COMPONENTS_NIMBLEADVERTISEDDEVICE_H_
|
||||
#define COMPONENTS_NIMBLEADVERTISEDDEVICE_H_
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#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 "NimBLEScan.h"
|
||||
#include "NimBLEUUID.h"
|
||||
|
||||
#if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
#include "host/ble_hs_adv.h"
|
||||
#else
|
||||
#include "nimble/nimble/host/include/host/ble_hs_adv.h"
|
||||
#endif
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
class NimBLEScan;
|
||||
@@ -44,7 +46,11 @@ public:
|
||||
NimBLEAddress getAddress();
|
||||
uint8_t getAdvType();
|
||||
uint16_t getAppearance();
|
||||
uint16_t getAdvInterval();
|
||||
uint16_t getMinInterval();
|
||||
uint16_t getMaxInterval();
|
||||
std::string getManufacturerData();
|
||||
std::string getURI();
|
||||
|
||||
/**
|
||||
* @brief A template to convert the service data to <type\>.
|
||||
@@ -67,7 +73,7 @@ public:
|
||||
NimBLEScan* getScan();
|
||||
size_t getServiceDataCount();
|
||||
std::string getServiceData(uint8_t index = 0);
|
||||
std::string getServiceData(const NimBLEUUID &uuid) const;
|
||||
std::string getServiceData(const NimBLEUUID &uuid);
|
||||
|
||||
/**
|
||||
* @brief A template to convert the service data to <tt><type\></tt>.
|
||||
@@ -106,12 +112,15 @@ public:
|
||||
NimBLEUUID getServiceDataUUID(uint8_t index = 0);
|
||||
NimBLEUUID getServiceUUID(uint8_t index = 0);
|
||||
size_t getServiceUUIDCount();
|
||||
NimBLEAddress getTargetAddress(uint8_t index = 0);
|
||||
size_t getTargetAddressCount();
|
||||
int8_t getTXPower();
|
||||
uint8_t* getPayload();
|
||||
uint8_t getAdvLength();
|
||||
size_t getPayloadLength();
|
||||
uint8_t getAddressType();
|
||||
time_t getTimestamp();
|
||||
bool isAdvertisingService(const NimBLEUUID &uuid) const;
|
||||
bool isAdvertisingService(const NimBLEUUID &uuid);
|
||||
bool haveAppearance();
|
||||
bool haveManufacturerData();
|
||||
bool haveName();
|
||||
@@ -119,46 +128,30 @@ public:
|
||||
bool haveServiceData();
|
||||
bool haveServiceUUID();
|
||||
bool haveTXPower();
|
||||
bool haveConnParams();
|
||||
bool haveAdvInterval();
|
||||
bool haveTargetAddress();
|
||||
bool haveURI();
|
||||
std::string toString();
|
||||
|
||||
private:
|
||||
friend class NimBLEScan;
|
||||
|
||||
void parseAdvertisement(uint8_t* payload, uint8_t length);
|
||||
void setAddress(NimBLEAddress address);
|
||||
void setAdvType(uint8_t advType);
|
||||
void setAppearance(uint16_t appearance);
|
||||
void setManufacturerData(std::string manufacturerData);
|
||||
void setName(std::string name);
|
||||
void setRSSI(int rssi);
|
||||
void setServiceData(NimBLEUUID serviceUUID, std::string data);
|
||||
void setServiceUUID(const char* serviceUUID);
|
||||
void setServiceUUID(NimBLEUUID serviceUUID);
|
||||
void setTXPower(int8_t txPower);
|
||||
|
||||
bool m_haveAppearance;
|
||||
bool m_haveManufacturerData;
|
||||
bool m_haveName;
|
||||
bool m_haveRSSI;
|
||||
bool m_haveServiceData;
|
||||
bool m_haveServiceUUID;
|
||||
bool m_haveTXPower;
|
||||
|
||||
void setAddress(NimBLEAddress address);
|
||||
void setAdvType(uint8_t advType);
|
||||
void setPayload(const uint8_t *payload, uint8_t length, bool append);
|
||||
void setRSSI(int rssi);
|
||||
uint8_t findAdvField(uint8_t type, uint8_t index = 0, uint8_t *data_loc = nullptr);
|
||||
uint8_t findServiceData(uint8_t index, uint8_t* bytes);
|
||||
|
||||
NimBLEAddress m_address = NimBLEAddress("");
|
||||
uint8_t m_advType;
|
||||
uint16_t m_appearance;
|
||||
std::string m_manufacturerData;
|
||||
std::string m_name;
|
||||
int m_rssi;
|
||||
int8_t m_txPower;
|
||||
uint8_t* m_payload;
|
||||
size_t m_payloadLength;
|
||||
time_t m_timestamp;
|
||||
bool m_callbackSent;
|
||||
uint8_t m_advLength;
|
||||
|
||||
std::vector<NimBLEUUID> m_serviceUUIDs;
|
||||
std::vector<std::pair<NimBLEUUID, std::string>>m_serviceDataVec;
|
||||
std::vector<uint8_t> m_payload;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -180,6 +173,5 @@ public:
|
||||
virtual void onResult(NimBLEAdvertisedDevice* advertisedDevice) = 0;
|
||||
};
|
||||
|
||||
#endif // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_OBSERVER */
|
||||
#endif /* COMPONENTS_NIMBLEADVERTISEDDEVICE_H_ */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -14,13 +14,15 @@
|
||||
|
||||
#ifndef MAIN_BLEADVERTISING_H_
|
||||
#define MAIN_BLEADVERTISING_H_
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||
|
||||
#if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
#include "host/ble_gap.h"
|
||||
#else
|
||||
#include "nimble/nimble/host/include/host/ble_gap.h"
|
||||
#endif
|
||||
|
||||
/**** FIX COMPILATION ****/
|
||||
#undef min
|
||||
#undef max
|
||||
@@ -50,18 +52,27 @@ class NimBLEAdvertisementData {
|
||||
public:
|
||||
void setAppearance(uint16_t appearance);
|
||||
void setCompleteServices(const NimBLEUUID &uuid);
|
||||
void setCompleteServices16(const std::vector<NimBLEUUID> &v_uuid);
|
||||
void setCompleteServices32(const std::vector<NimBLEUUID> &v_uuid);
|
||||
void setFlags(uint8_t);
|
||||
void setManufacturerData(const std::string &data);
|
||||
void setURI(const std::string &uri);
|
||||
void setName(const std::string &name);
|
||||
void setPartialServices(const NimBLEUUID &uuid);
|
||||
void setPartialServices16(const std::vector<NimBLEUUID> &v_uuid);
|
||||
void setPartialServices32(const std::vector<NimBLEUUID> &v_uuid);
|
||||
void setServiceData(const NimBLEUUID &uuid, const std::string &data);
|
||||
void setShortName(const std::string &name);
|
||||
void addData(const std::string &data); // Add data to the payload.
|
||||
void addData(char * data, size_t length);
|
||||
void addTxPower();
|
||||
void setPreferredParams(uint16_t min, uint16_t max);
|
||||
std::string getPayload(); // Retrieve the current advert payload.
|
||||
|
||||
private:
|
||||
friend class NimBLEAdvertising;
|
||||
void setServices(const bool complete, const uint8_t size,
|
||||
const std::vector<NimBLEUUID> &v_uuid);
|
||||
std::string m_payload; // The payload of the advertisement.
|
||||
}; // NimBLEAdvertisementData
|
||||
|
||||
@@ -77,33 +88,51 @@ public:
|
||||
void addServiceUUID(const NimBLEUUID &serviceUUID);
|
||||
void addServiceUUID(const char* serviceUUID);
|
||||
void removeServiceUUID(const NimBLEUUID &serviceUUID);
|
||||
void start();
|
||||
bool start(uint32_t duration = 0, void (*advCompleteCB)(NimBLEAdvertising *pAdv) = nullptr);
|
||||
void stop();
|
||||
void setAppearance(uint16_t appearance);
|
||||
void setName(const std::string &name);
|
||||
void setManufacturerData(const std::string &data);
|
||||
void setURI(const std::string &uri);
|
||||
void setServiceData(const NimBLEUUID &uuid, const std::string &data);
|
||||
void setAdvertisementType(uint8_t adv_type);
|
||||
void setMaxInterval(uint16_t maxinterval);
|
||||
void setMinInterval(uint16_t mininterval);
|
||||
void setAdvertisementData(NimBLEAdvertisementData& advertisementData);
|
||||
void setScanFilter(bool scanRequertWhitelistOnly, bool connectWhitelistOnly);
|
||||
void setScanFilter(bool scanRequestWhitelistOnly, bool connectWhitelistOnly);
|
||||
void setScanResponseData(NimBLEAdvertisementData& advertisementData);
|
||||
void setScanResponse(bool);
|
||||
void setMinPreferred(uint16_t);
|
||||
void setMaxPreferred(uint16_t);
|
||||
void addTxPower();
|
||||
void reset();
|
||||
void advCompleteCB();
|
||||
bool isAdvertising();
|
||||
|
||||
private:
|
||||
friend class NimBLEDevice;
|
||||
|
||||
void onHostReset();
|
||||
void onHostSync();
|
||||
static int handleGapEvent(struct ble_gap_event *event, void *arg);
|
||||
|
||||
ble_hs_adv_fields m_advData;
|
||||
ble_hs_adv_fields m_scanData;
|
||||
ble_gap_adv_params m_advParams;
|
||||
ble_hs_adv_fields m_advData;
|
||||
ble_hs_adv_fields m_scanData;
|
||||
ble_gap_adv_params m_advParams;
|
||||
std::vector<NimBLEUUID> m_serviceUUIDs;
|
||||
bool m_customAdvData = false; // Are we using custom advertising data?
|
||||
bool m_customScanResponseData = false; // Are we using custom scan response data?
|
||||
bool m_scanResp = true;
|
||||
bool m_advDataSet = false;
|
||||
|
||||
bool m_customAdvData;
|
||||
bool m_customScanResponseData;
|
||||
bool m_scanResp;
|
||||
bool m_advDataSet;
|
||||
void (*m_advCompCB)(NimBLEAdvertising *pAdv);
|
||||
uint8_t m_slaveItvl[4];
|
||||
uint32_t m_duration;
|
||||
std::vector<uint8_t> m_svcData16;
|
||||
std::vector<uint8_t> m_svcData32;
|
||||
std::vector<uint8_t> m_svcData128;
|
||||
std::vector<uint8_t> m_name;
|
||||
std::vector<uint8_t> m_mfgData;
|
||||
std::vector<uint8_t> m_uri;
|
||||
};
|
||||
|
||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER */
|
||||
#endif /* MAIN_BLEADVERTISING_H_ */
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
* Created on: Jan 4, 2018
|
||||
* Author: kolban
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include <string.h>
|
||||
|
||||
@@ -9,11 +9,9 @@
|
||||
* Created on: Jun 22, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#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 "NimBLE2904.h"
|
||||
@@ -45,15 +43,14 @@ NimBLECharacteristic::NimBLECharacteristic(const char* uuid, uint16_t properties
|
||||
* @param [in] pService - pointer to the service instance this characteristic belongs to.
|
||||
*/
|
||||
NimBLECharacteristic::NimBLECharacteristic(const NimBLEUUID &uuid, uint16_t properties, NimBLEService* pService) {
|
||||
m_uuid = uuid;
|
||||
m_handle = NULL_HANDLE;
|
||||
m_properties = properties;
|
||||
m_pCallbacks = &defaultCallback;
|
||||
m_pService = pService;
|
||||
m_value = "";
|
||||
m_valMux = portMUX_INITIALIZER_UNLOCKED;
|
||||
m_pTaskData = nullptr;
|
||||
m_timestamp = 0;
|
||||
m_uuid = uuid;
|
||||
m_handle = NULL_HANDLE;
|
||||
m_properties = properties;
|
||||
m_pCallbacks = &defaultCallback;
|
||||
m_pService = pService;
|
||||
m_value = "";
|
||||
m_timestamp = 0;
|
||||
m_removed = 0;
|
||||
} // NimBLECharacteristic
|
||||
|
||||
/**
|
||||
@@ -95,15 +92,68 @@ NimBLEDescriptor* NimBLECharacteristic::createDescriptor(const NimBLEUUID &uuid,
|
||||
pDescriptor = new NimBLEDescriptor(uuid, properties, max_len, this);
|
||||
}
|
||||
|
||||
m_dscVec.push_back(pDescriptor);
|
||||
addDescriptor(pDescriptor);
|
||||
return pDescriptor;
|
||||
} // createCharacteristic
|
||||
} // createDescriptor
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return the BLE Descriptor for the given UUID if associated with this characteristic.
|
||||
* @param [in] uuid The UUID of the descriptor that we wish to retrieve.
|
||||
* @return pointer to the NimBLEDescriptor. If no such descriptor is associated with the characteristic, nullptr is returned.
|
||||
* @brief Add a descriptor to the characteristic.
|
||||
* @param [in] pDescriptor A pointer to the descriptor to add.
|
||||
*/
|
||||
void NimBLECharacteristic::addDescriptor(NimBLEDescriptor *pDescriptor) {
|
||||
bool foundRemoved = false;
|
||||
|
||||
if(pDescriptor->m_removed > 0) {
|
||||
for(auto& it : m_dscVec) {
|
||||
if(it == pDescriptor) {
|
||||
foundRemoved = true;
|
||||
pDescriptor->m_removed = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!foundRemoved) {
|
||||
m_dscVec.push_back(pDescriptor);
|
||||
}
|
||||
|
||||
pDescriptor->setCharacteristic(this);
|
||||
NimBLEDevice::getServer()->serviceChanged();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Remove a descriptor from the characterisitc.
|
||||
* @param[in] pDescriptor A pointer to the descriptor instance to remove from the characterisitc.
|
||||
* @param[in] deleteDsc If true it will delete the descriptor instance and free it's resources.
|
||||
*/
|
||||
void NimBLECharacteristic::removeDescriptor(NimBLEDescriptor *pDescriptor, bool deleteDsc) {
|
||||
// Check if the descriptor was already removed and if so, check if this
|
||||
// is being called to delete the object and do so if requested.
|
||||
// Otherwise, ignore the call and return.
|
||||
if(pDescriptor->m_removed > 0) {
|
||||
if(deleteDsc) {
|
||||
for(auto it = m_dscVec.begin(); it != m_dscVec.end(); ++it) {
|
||||
if ((*it) == pDescriptor) {
|
||||
delete *it;
|
||||
m_dscVec.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
pDescriptor->m_removed = deleteDsc ? NIMBLE_ATT_REMOVE_DELETE : NIMBLE_ATT_REMOVE_HIDE;
|
||||
NimBLEDevice::getServer()->serviceChanged();
|
||||
} // removeDescriptor
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return the BLE Descriptor for the given UUID.
|
||||
* @param [in] uuid The UUID of the descriptor.
|
||||
* @return A pointer to the descriptor object or nullptr if not found.
|
||||
*/
|
||||
NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const char* uuid) {
|
||||
return getDescriptorByUUID(NimBLEUUID(uuid));
|
||||
@@ -111,9 +161,9 @@ NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const char* uuid) {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return the BLE Descriptor for the given UUID if associated with this characteristic.
|
||||
* @param [in] uuid The UUID of the descriptor that we wish to retrieve.
|
||||
* @return pointer to the NimBLEDescriptor. If no such descriptor is associated with the characteristic, nullptr is returned.
|
||||
* @brief Return the BLE Descriptor for the given UUID.
|
||||
* @param [in] uuid The UUID of the descriptor.
|
||||
* @return A pointer to the descriptor object or nullptr if not found.
|
||||
*/
|
||||
NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const NimBLEUUID &uuid) {
|
||||
for (auto &it : m_dscVec) {
|
||||
@@ -124,6 +174,20 @@ NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const NimBLEUUID &uu
|
||||
return nullptr;
|
||||
} // getDescriptorByUUID
|
||||
|
||||
/**
|
||||
* @brief Return the BLE Descriptor for the given handle.
|
||||
* @param [in] handle The handle of the descriptor.
|
||||
* @return A pointer to the descriptor object or nullptr if not found.
|
||||
*/
|
||||
NimBLEDescriptor *NimBLECharacteristic::getDescriptorByHandle(uint16_t handle) {
|
||||
for (auto &it : m_dscVec) {
|
||||
if (it->getHandle() == handle) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the handle of the characteristic.
|
||||
@@ -151,6 +215,11 @@ NimBLEService* NimBLECharacteristic::getService() {
|
||||
} // getService
|
||||
|
||||
|
||||
void NimBLECharacteristic::setService(NimBLEService *pService) {
|
||||
m_pService = pService;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the UUID of the characteristic.
|
||||
* @return The UUID of the characteristic.
|
||||
@@ -165,12 +234,12 @@ NimBLEUUID NimBLECharacteristic::getUUID() {
|
||||
* @return A std::string containing the current characteristic value.
|
||||
*/
|
||||
std::string NimBLECharacteristic::getValue(time_t *timestamp) {
|
||||
portENTER_CRITICAL(&m_valMux);
|
||||
ble_npl_hw_enter_critical();
|
||||
std::string retVal = m_value;
|
||||
if(timestamp != nullptr) {
|
||||
*timestamp = m_timestamp;
|
||||
}
|
||||
portEXIT_CRITICAL(&m_valMux);
|
||||
ble_npl_hw_exit_critical(0);
|
||||
|
||||
return retVal;
|
||||
} // getValue
|
||||
@@ -181,10 +250,9 @@ std::string NimBLECharacteristic::getValue(time_t *timestamp) {
|
||||
* @return The length of the current characteristic data.
|
||||
*/
|
||||
size_t NimBLECharacteristic::getDataLength() {
|
||||
portENTER_CRITICAL(&m_valMux);
|
||||
ble_npl_hw_enter_critical();
|
||||
size_t len = m_value.length();
|
||||
portEXIT_CRITICAL(&m_valMux);
|
||||
|
||||
ble_npl_hw_exit_critical(0);
|
||||
return len;
|
||||
}
|
||||
|
||||
@@ -217,11 +285,10 @@ int NimBLECharacteristic::handleGapEvent(uint16_t conn_handle, uint16_t attr_han
|
||||
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(),
|
||||
pCharacteristic->m_value.length());
|
||||
portEXIT_CRITICAL(&pCharacteristic->m_valMux);
|
||||
|
||||
ble_npl_hw_exit_critical(0);
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
|
||||
@@ -287,16 +354,13 @@ void NimBLECharacteristic::setSubscribe(struct ble_gap_event *event) {
|
||||
subVal |= NIMBLE_SUB_INDICATE;
|
||||
}
|
||||
|
||||
if(m_pTaskData != nullptr) {
|
||||
m_pTaskData->rc = (subVal & NIMBLE_SUB_INDICATE) ? 0 :
|
||||
NimBLECharacteristicCallbacks::Status::ERROR_INDICATE_DISABLED;
|
||||
xTaskNotifyGive(m_pTaskData->task);
|
||||
}
|
||||
|
||||
NIMBLE_LOGI(LOG_TAG, "New subscribe value for conn: %d val: %d",
|
||||
event->subscribe.conn_handle, subVal);
|
||||
event->subscribe.conn_handle, subVal);
|
||||
|
||||
if(!event->subscribe.cur_indicate && event->subscribe.prev_indicate) {
|
||||
NimBLEDevice::getServer()->clearIndicateWait(event->subscribe.conn_handle);
|
||||
}
|
||||
|
||||
m_pCallbacks->onSubscribe(this, &desc, subVal);
|
||||
|
||||
auto it = m_subscribedVec.begin();
|
||||
for(;it != m_subscribedVec.end(); ++it) {
|
||||
@@ -308,16 +372,14 @@ void NimBLECharacteristic::setSubscribe(struct ble_gap_event *event) {
|
||||
if(subVal > 0) {
|
||||
if(it == m_subscribedVec.end()) {
|
||||
m_subscribedVec.push_back({event->subscribe.conn_handle, subVal});
|
||||
return;
|
||||
} else {
|
||||
(*it).second = subVal;
|
||||
}
|
||||
|
||||
(*it).second = subVal;
|
||||
|
||||
} else if(it != m_subscribedVec.end()) {
|
||||
m_subscribedVec.erase(it);
|
||||
m_subscribedVec.shrink_to_fit();
|
||||
}
|
||||
|
||||
|
||||
m_pCallbacks->onSubscribe(this, &desc, subVal);
|
||||
}
|
||||
|
||||
|
||||
@@ -332,6 +394,7 @@ void NimBLECharacteristic::indicate() {
|
||||
NIMBLE_LOGD(LOG_TAG, "<< indicate");
|
||||
} // indicate
|
||||
|
||||
|
||||
/**
|
||||
* @brief Send a notification.\n
|
||||
* A notification is a transmission of up to the first 20 bytes of the characteristic value.\n
|
||||
@@ -339,8 +402,18 @@ void NimBLECharacteristic::indicate() {
|
||||
* @param[in] is_notification if true sends a notification, false sends an indication.
|
||||
*/
|
||||
void NimBLECharacteristic::notify(bool is_notification) {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> notify: length: %d", getDataLength());
|
||||
notify(getValue(), is_notification);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Send a notification.\n
|
||||
* A notification is a transmission of up to the first 20 bytes of the characteristic value.\n
|
||||
* A notification will not block; it is a fire and forget.
|
||||
* @param[in] is_notification if true sends a notification, false sends an indication.
|
||||
*/
|
||||
void NimBLECharacteristic::notify(std::string value, bool is_notification) {
|
||||
size_t length = value.length();
|
||||
NIMBLE_LOGD(LOG_TAG, ">> notify: length: %d", length);
|
||||
|
||||
if(!(m_properties & NIMBLE_PROPERTY::NOTIFY) &&
|
||||
!(m_properties & NIMBLE_PROPERTY::INDICATE))
|
||||
@@ -357,15 +430,13 @@ void NimBLECharacteristic::notify(bool is_notification) {
|
||||
|
||||
m_pCallbacks->onNotify(this);
|
||||
|
||||
std::string value = getValue();
|
||||
size_t length = value.length();
|
||||
bool reqSec = (m_properties & BLE_GATT_CHR_F_READ_AUTHEN) ||
|
||||
(m_properties & BLE_GATT_CHR_F_READ_AUTHOR) ||
|
||||
(m_properties & BLE_GATT_CHR_F_READ_ENC);
|
||||
int rc = 0;
|
||||
|
||||
for (auto &it : m_subscribedVec) {
|
||||
uint16_t _mtu = getService()->getServer()->getPeerMTU(it.first);
|
||||
uint16_t _mtu = getService()->getServer()->getPeerMTU(it.first) - 3;
|
||||
|
||||
// check if connected and subscribed
|
||||
if(_mtu == 0 || it.second == 0) {
|
||||
@@ -381,8 +452,8 @@ void NimBLECharacteristic::notify(bool is_notification) {
|
||||
}
|
||||
}
|
||||
|
||||
if (length > _mtu - 3) {
|
||||
NIMBLE_LOGW(LOG_TAG, "- Truncating to %d bytes (maximum notify size)", _mtu - 3);
|
||||
if (length > _mtu) {
|
||||
NIMBLE_LOGW(LOG_TAG, "- Truncating to %d bytes (maximum notify size)", _mtu);
|
||||
}
|
||||
|
||||
if(is_notification && (!(it.second & NIMBLE_SUB_NOTIFY))) {
|
||||
@@ -402,40 +473,20 @@ void NimBLECharacteristic::notify(bool is_notification) {
|
||||
// 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);
|
||||
|
||||
NimBLECharacteristicCallbacks::Status statusRC;
|
||||
|
||||
if(!is_notification && (m_properties & NIMBLE_PROPERTY::INDICATE)) {
|
||||
ble_task_data_t taskData = {nullptr, xTaskGetCurrentTaskHandle(),0, nullptr};
|
||||
m_pTaskData = &taskData;
|
||||
if(!NimBLEDevice::getServer()->setIndicateWait(it.first)) {
|
||||
NIMBLE_LOGE(LOG_TAG, "prior Indication in progress");
|
||||
os_mbuf_free_chain(om);
|
||||
return;
|
||||
}
|
||||
|
||||
rc = ble_gattc_indicate_custom(it.first, m_handle, om);
|
||||
if(rc != 0){
|
||||
statusRC = NimBLECharacteristicCallbacks::Status::ERROR_GATT;
|
||||
} else {
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
rc = m_pTaskData->rc;
|
||||
}
|
||||
|
||||
m_pTaskData = nullptr;
|
||||
|
||||
if(rc == BLE_HS_EDONE) {
|
||||
rc = 0;
|
||||
statusRC = NimBLECharacteristicCallbacks::Status::SUCCESS_INDICATE;
|
||||
} else if(rc == BLE_HS_ETIMEOUT) {
|
||||
statusRC = NimBLECharacteristicCallbacks::Status::ERROR_INDICATE_TIMEOUT;
|
||||
} else {
|
||||
statusRC = NimBLECharacteristicCallbacks::Status::ERROR_INDICATE_FAILURE;
|
||||
NimBLEDevice::getServer()->clearIndicateWait(it.first);
|
||||
}
|
||||
} else {
|
||||
rc = ble_gattc_notify_custom(it.first, m_handle, om);
|
||||
if(rc == 0) {
|
||||
statusRC = NimBLECharacteristicCallbacks::Status::SUCCESS_NOTIFY;
|
||||
} else {
|
||||
statusRC = NimBLECharacteristicCallbacks::Status::ERROR_GATT;
|
||||
}
|
||||
ble_gattc_notify_custom(it.first, m_handle, om);
|
||||
}
|
||||
|
||||
m_pCallbacks->onStatus(this, statusRC, rc);
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< notify");
|
||||
@@ -455,6 +506,13 @@ void NimBLECharacteristic::setCallbacks(NimBLECharacteristicCallbacks* pCallback
|
||||
}
|
||||
} // setCallbacks
|
||||
|
||||
/**
|
||||
* @brief Get the callback handlers for this characteristic.
|
||||
*/
|
||||
NimBLECharacteristicCallbacks* NimBLECharacteristic::getCallbacks() {
|
||||
return m_pCallbacks;
|
||||
} //getCallbacks
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the value of the characteristic.
|
||||
@@ -462,7 +520,7 @@ void NimBLECharacteristic::setCallbacks(NimBLECharacteristicCallbacks* pCallback
|
||||
* @param [in] length The length of the data in bytes.
|
||||
*/
|
||||
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);
|
||||
NIMBLE_LOGD(LOG_TAG, ">> setValue: length=%d, data=%s, characteristic UUID=%s", length, pHex, getUUID().toString().c_str());
|
||||
free(pHex);
|
||||
@@ -473,10 +531,11 @@ void NimBLECharacteristic::setValue(const uint8_t* data, size_t length) {
|
||||
return;
|
||||
}
|
||||
|
||||
portENTER_CRITICAL(&m_valMux);
|
||||
time_t t = time(nullptr);
|
||||
ble_npl_hw_enter_critical();
|
||||
m_value = std::string((char*)data, length);
|
||||
m_timestamp = time(nullptr);
|
||||
portEXIT_CRITICAL(&m_valMux);
|
||||
m_timestamp = t;
|
||||
ble_npl_hw_exit_critical(0);
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< setValue");
|
||||
} // setValue
|
||||
@@ -586,6 +645,4 @@ void NimBLECharacteristicCallbacks::onSubscribe(NimBLECharacteristic* pCharacter
|
||||
NIMBLE_LOGD("NimBLECharacteristicCallbacks", "onSubscribe: default");
|
||||
}
|
||||
|
||||
|
||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||
|
||||
@@ -13,13 +13,15 @@
|
||||
|
||||
#ifndef MAIN_NIMBLECHARACTERISTIC_H_
|
||||
#define MAIN_NIMBLECHARACTERISTIC_H_
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#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"
|
||||
#else
|
||||
#include "nimble/nimble/host/include/host/ble_hs.h"
|
||||
#endif
|
||||
|
||||
/**** FIX COMPILATION ****/
|
||||
#undef min
|
||||
#undef max
|
||||
@@ -59,6 +61,33 @@ class NimBLECharacteristicCallbacks;
|
||||
*/
|
||||
class NimBLECharacteristic {
|
||||
public:
|
||||
NimBLECharacteristic(const char* uuid,
|
||||
uint16_t properties =
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE,
|
||||
NimBLEService* pService = nullptr);
|
||||
NimBLECharacteristic(const NimBLEUUID &uuid,
|
||||
uint16_t properties =
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE,
|
||||
NimBLEService* pService = nullptr);
|
||||
|
||||
~NimBLECharacteristic();
|
||||
|
||||
uint16_t getHandle();
|
||||
NimBLEUUID getUUID();
|
||||
std::string toString();
|
||||
|
||||
void setCallbacks(NimBLECharacteristicCallbacks* pCallbacks);
|
||||
NimBLECharacteristicCallbacks*
|
||||
getCallbacks();
|
||||
|
||||
void indicate();
|
||||
void notify(bool is_notification = true);
|
||||
void notify(std::string value, bool is_notification = true);
|
||||
|
||||
size_t getSubscribedCount();
|
||||
|
||||
NimBLEDescriptor* createDescriptor(const char* uuid,
|
||||
uint32_t properties =
|
||||
NIMBLE_PROPERTY::READ |
|
||||
@@ -70,11 +99,14 @@ public:
|
||||
NIMBLE_PROPERTY::WRITE,
|
||||
uint16_t max_len = 100);
|
||||
|
||||
void addDescriptor(NimBLEDescriptor *pDescriptor);
|
||||
NimBLEDescriptor* getDescriptorByUUID(const char* uuid);
|
||||
NimBLEDescriptor* getDescriptorByUUID(const NimBLEUUID &uuid);
|
||||
NimBLEUUID getUUID();
|
||||
std::string getValue(time_t *timestamp = nullptr);
|
||||
NimBLEDescriptor* getDescriptorByHandle(uint16_t handle);
|
||||
void removeDescriptor(NimBLEDescriptor *pDescriptor, bool deleteDsc = false);
|
||||
|
||||
std::string getValue(time_t *timestamp = nullptr);
|
||||
size_t getDataLength();
|
||||
/**
|
||||
* @brief A template to convert the characteristic data to <type\>.
|
||||
* @tparam T The type to convert the data to.
|
||||
@@ -92,46 +124,26 @@ public:
|
||||
return *((T *)pData);
|
||||
}
|
||||
|
||||
size_t getDataLength();
|
||||
void indicate();
|
||||
void notify(bool is_notification = true);
|
||||
void setCallbacks(NimBLECharacteristicCallbacks* pCallbacks);
|
||||
void setValue(const uint8_t* data, size_t size);
|
||||
void setValue(const std::string &value);
|
||||
|
||||
/**
|
||||
* @brief Convenience template to set the characteristic value to <type\>val.
|
||||
* @param [in] s The value to set.
|
||||
*/
|
||||
template<typename T>
|
||||
void setValue(const T &s) {
|
||||
void setValue(const T &s) {
|
||||
setValue((uint8_t*)&s, sizeof(T));
|
||||
}
|
||||
|
||||
std::string toString();
|
||||
uint16_t getHandle();
|
||||
size_t getSubscribedCount();
|
||||
NimBLEService* getService();
|
||||
uint16_t getProperties();
|
||||
|
||||
private:
|
||||
|
||||
friend class NimBLEServer;
|
||||
friend class NimBLEService;
|
||||
friend class NimBLEServer;
|
||||
friend class NimBLEService;
|
||||
|
||||
NimBLECharacteristic(const char* uuid,
|
||||
uint16_t properties =
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE,
|
||||
NimBLEService* pService = nullptr);
|
||||
NimBLECharacteristic(const NimBLEUUID &uuid,
|
||||
uint16_t properties =
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE,
|
||||
NimBLEService* pService = nullptr);
|
||||
|
||||
~NimBLECharacteristic();
|
||||
|
||||
NimBLEService* getService();
|
||||
uint16_t getProperties();
|
||||
void setService(NimBLEService *pService);
|
||||
void setSubscribe(struct ble_gap_event *event);
|
||||
static int handleGapEvent(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg);
|
||||
@@ -143,9 +155,8 @@ private:
|
||||
NimBLEService* m_pService;
|
||||
std::string m_value;
|
||||
std::vector<NimBLEDescriptor*> m_dscVec;
|
||||
ble_task_data_t *m_pTaskData;
|
||||
portMUX_TYPE m_valMux;
|
||||
time_t m_timestamp;
|
||||
uint8_t m_removed;
|
||||
|
||||
std::vector<std::pair<uint16_t, uint16_t>> m_subscribedVec;
|
||||
}; // NimBLECharacteristic
|
||||
@@ -187,6 +198,5 @@ public:
|
||||
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 */
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||
#endif /*MAIN_NIMBLECHARACTERISTIC_H_*/
|
||||
|
||||
@@ -11,11 +11,8 @@
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#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 "NimBLEDevice.h"
|
||||
@@ -23,6 +20,13 @@
|
||||
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
#include <climits>
|
||||
|
||||
#if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
#include "nimble/nimble_port.h"
|
||||
#else
|
||||
#include "nimble/porting/nimble/include/nimble/nimble_port.h"
|
||||
#endif
|
||||
|
||||
static const char* LOG_TAG = "NimBLEClient";
|
||||
static NimBLEClientCallbacks defaultCallbacks;
|
||||
@@ -56,11 +60,11 @@ static NimBLEClientCallbacks defaultCallbacks;
|
||||
NimBLEClient::NimBLEClient(const NimBLEAddress &peerAddress) : m_peerAddress(peerAddress) {
|
||||
m_pClientCallbacks = &defaultCallbacks;
|
||||
m_conn_id = BLE_HS_CONN_HANDLE_NONE;
|
||||
m_isConnected = false;
|
||||
m_waitingToConnect = false;
|
||||
m_connectTimeout = 30000;
|
||||
m_deleteCallbacks = false;
|
||||
m_pTaskData = nullptr;
|
||||
m_connEstablished = false;
|
||||
m_lastErr = 0;
|
||||
|
||||
m_pConnParams.scan_itvl = 16; // Scan interval in 0.625ms units (NimBLE Default)
|
||||
m_pConnParams.scan_window = 16; // Scan window in 0.625ms units (NimBLE Default)
|
||||
@@ -70,6 +74,10 @@ NimBLEClient::NimBLEClient(const NimBLEAddress &peerAddress) : m_peerAddress(pee
|
||||
m_pConnParams.supervision_timeout = BLE_GAP_INITIAL_SUPERVISION_TIMEOUT; // timeout = 400*10ms = 4000ms
|
||||
m_pConnParams.min_ce_len = BLE_GAP_INITIAL_CONN_MIN_CE_LEN; // Minimum length of connection event in 0.625ms units
|
||||
m_pConnParams.max_ce_len = BLE_GAP_INITIAL_CONN_MAX_CE_LEN; // Maximum length of connection event in 0.625ms units
|
||||
|
||||
memset(&m_dcTimer, 0, sizeof(m_dcTimer));
|
||||
ble_npl_callout_init(&m_dcTimer, nimble_port_get_dflt_eventq(),
|
||||
NimBLEClient::dcTimerCb, this);
|
||||
} // NimBLEClient
|
||||
|
||||
|
||||
@@ -89,6 +97,20 @@ NimBLEClient::~NimBLEClient() {
|
||||
} // ~NimBLEClient
|
||||
|
||||
|
||||
/**
|
||||
* @brief If we have asked to disconnect and the event does not
|
||||
* occur within the supervision timeout + added delay, this will
|
||||
* be called to reset the host in the case of a stalled controller.
|
||||
*/
|
||||
void NimBLEClient::dcTimerCb(ble_npl_event *event) {
|
||||
/* NimBLEClient *pClient = (NimBLEClient*)event->arg;
|
||||
NIMBLE_LOGC(LOG_TAG, "Timed out disconnecting from %s - resetting host",
|
||||
std::string(pClient->getPeerAddress()).c_str());
|
||||
*/
|
||||
ble_hs_sched_reset(BLE_HS_ECONTROLLER);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Delete all service objects created by this client and clear the vector.
|
||||
*/
|
||||
@@ -164,70 +186,127 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttibutes) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(ble_gap_conn_active()) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Connection in progress - must wait.");
|
||||
if(isConnected() || m_connEstablished || m_pTaskData != nullptr) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Client busy, connected to %s, id=%d",
|
||||
std::string(m_peerAddress).c_str(), getConnId());
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!NimBLEDevice::getScan()->stop()) {
|
||||
ble_addr_t peerAddr_t;
|
||||
memcpy(&peerAddr_t.val, address.getNative(),6);
|
||||
peerAddr_t.type = address.getType();
|
||||
if(ble_gap_conn_find_by_addr(&peerAddr_t, NULL) == 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "A connection to %s already exists",
|
||||
address.toString().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if(address == NimBLEAddress("")) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Invalid peer address;(NULL)");
|
||||
return false;
|
||||
} else if(m_peerAddress != address) {
|
||||
} else {
|
||||
m_peerAddress = address;
|
||||
}
|
||||
|
||||
ble_addr_t peerAddrt;
|
||||
memcpy(&peerAddrt.val, m_peerAddress.getNative(),6);
|
||||
peerAddrt.type = m_peerAddress.getType();
|
||||
|
||||
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;
|
||||
|
||||
int rc = 0;
|
||||
|
||||
/* Try to connect the the advertiser. Allow 30 seconds (30000 ms) for
|
||||
* timeout (default value of m_connectTimeout).
|
||||
* Loop on BLE_HS_EBUSY if the scan hasn't stopped yet.
|
||||
*/
|
||||
do{
|
||||
rc = ble_gap_connect(BLE_OWN_ADDR_PUBLIC, &peerAddrt, m_connectTimeout, &m_pConnParams,
|
||||
NimBLEClient::handleGapEvent, this);
|
||||
if(rc == BLE_HS_EBUSY) {
|
||||
vTaskDelay(1 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}while(rc == BLE_HS_EBUSY);
|
||||
do {
|
||||
rc = ble_gap_connect(NimBLEDevice::m_own_addr_type, &peerAddr_t,
|
||||
m_connectTimeout, &m_pConnParams,
|
||||
NimBLEClient::handleGapEvent, this);
|
||||
switch (rc) {
|
||||
case 0:
|
||||
break;
|
||||
|
||||
if (rc != 0 && rc != BLE_HS_EDONE) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Error: Failed to connect to device; "
|
||||
"addr=%s, rc=%d; %s",
|
||||
std::string(m_peerAddress).c_str(),
|
||||
rc, NimBLEUtils::returnCodeToString(rc));
|
||||
case BLE_HS_EBUSY:
|
||||
// Scan was still running, stop it and try again
|
||||
if (!NimBLEDevice::getScan()->stop()) {
|
||||
rc = BLE_HS_EUNKNOWN;
|
||||
}
|
||||
break;
|
||||
|
||||
case BLE_HS_EDONE:
|
||||
// A connection to this device already exists, do not connect twice.
|
||||
NIMBLE_LOGE(LOG_TAG, "Already connected to device; addr=%s",
|
||||
std::string(m_peerAddress).c_str());
|
||||
break;
|
||||
|
||||
case BLE_HS_EALREADY:
|
||||
// Already attemting to connect to this device, cancel the previous
|
||||
// attempt and report failure here so we don't get 2 connections.
|
||||
NIMBLE_LOGE(LOG_TAG, "Already attempting to connect to %s - cancelling",
|
||||
std::string(m_peerAddress).c_str());
|
||||
ble_gap_conn_cancel();
|
||||
break;
|
||||
|
||||
default:
|
||||
NIMBLE_LOGE(LOG_TAG, "Failed to connect to %s, rc=%d; %s",
|
||||
std::string(m_peerAddress).c_str(),
|
||||
rc, NimBLEUtils::returnCodeToString(rc));
|
||||
break;
|
||||
}
|
||||
|
||||
} while (rc == BLE_HS_EBUSY);
|
||||
|
||||
m_lastErr = rc;
|
||||
|
||||
if(rc != 0) {
|
||||
m_pTaskData = nullptr;
|
||||
m_waitingToConnect = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_waitingToConnect = true;
|
||||
#ifdef ulTaskNotifyValueClear
|
||||
// Clear the task notification value to ensure we block
|
||||
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
|
||||
#endif
|
||||
// Wait for the connect timeout time +1 second for the connection to complete
|
||||
if(ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(m_connectTimeout + 1000)) == pdFALSE) {
|
||||
m_pTaskData = nullptr;
|
||||
// If a connection was made but no response from MTU exchange; disconnect
|
||||
if(isConnected()) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Connect timeout - no response");
|
||||
disconnect();
|
||||
} else {
|
||||
// workaround; if the controller doesn't cancel the connection
|
||||
// at the timeout, cancel it here.
|
||||
NIMBLE_LOGE(LOG_TAG, "Connect timeout - cancelling");
|
||||
ble_gap_conn_cancel();
|
||||
}
|
||||
|
||||
// Wait for the connection to complete.
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
|
||||
if(taskData.rc != 0){
|
||||
return false;
|
||||
|
||||
} else if(taskData.rc != 0){
|
||||
m_lastErr = taskData.rc;
|
||||
NIMBLE_LOGE(LOG_TAG, "Connection failed; status=%d %s",
|
||||
taskData.rc,
|
||||
NimBLEUtils::returnCodeToString(taskData.rc));
|
||||
// If the failure was not a result of a disconnection
|
||||
// make sure we disconnect now to avoid dangling connections
|
||||
if(isConnected()) {
|
||||
disconnect();
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
NIMBLE_LOGI(LOG_TAG, "Connection established");
|
||||
}
|
||||
|
||||
if(deleteAttibutes) {
|
||||
deleteServices();
|
||||
}
|
||||
|
||||
m_connEstablished = true;
|
||||
m_pClientCallbacks->onConnect(this);
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< connect()");
|
||||
return true;
|
||||
// Check if still connected before returning
|
||||
return isConnected();
|
||||
} // connect
|
||||
|
||||
|
||||
@@ -237,7 +316,8 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttibutes) {
|
||||
* @return True on success.
|
||||
*/
|
||||
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;
|
||||
|
||||
@@ -246,14 +326,20 @@ bool NimBLEClient::secureConnection() {
|
||||
|
||||
int rc = NimBLEDevice::startSecurity(m_conn_id);
|
||||
if(rc != 0){
|
||||
m_lastErr = rc;
|
||||
m_pTaskData = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef ulTaskNotifyValueClear
|
||||
// Clear the task notification value to ensure we block
|
||||
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
|
||||
#endif
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
} while (taskData.rc == (BLE_HS_ERR_HCI_BASE + BLE_ERR_PINKEY_MISSING) && retryCount--);
|
||||
|
||||
if(taskData.rc != 0){
|
||||
m_lastErr = taskData.rc;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -268,27 +354,55 @@ bool NimBLEClient::secureConnection() {
|
||||
int NimBLEClient::disconnect(uint8_t reason) {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> disconnect()");
|
||||
int rc = 0;
|
||||
if(m_isConnected){
|
||||
rc = ble_gap_terminate(m_conn_id, reason);
|
||||
if(rc != 0){
|
||||
NIMBLE_LOGE(LOG_TAG, "ble_gap_terminate failed: rc=%d %s", rc,
|
||||
NimBLEUtils::returnCodeToString(rc));
|
||||
if(isConnected()) {
|
||||
// If the timer was already started, ignore this call.
|
||||
if(ble_npl_callout_is_active(&m_dcTimer)) {
|
||||
NIMBLE_LOGI(LOG_TAG, "Already disconnecting, timer started");
|
||||
return BLE_HS_EALREADY;
|
||||
}
|
||||
|
||||
ble_gap_conn_desc desc;
|
||||
if(ble_gap_conn_find(m_conn_id, &desc) != 0){
|
||||
NIMBLE_LOGI(LOG_TAG, "Connection ID not found");
|
||||
return BLE_HS_EALREADY;
|
||||
}
|
||||
|
||||
// We use a timer to detect a controller error in the event that it does
|
||||
// not inform the stack when disconnection is complete.
|
||||
// This is a common error in certain esp-idf versions.
|
||||
// The disconnect timeout time is the supervison timeout time + 1 second.
|
||||
// In the case that the event happenss shortly after the supervision timeout
|
||||
// we don't want to prematurely reset the host.
|
||||
ble_npl_time_t ticks;
|
||||
ble_npl_time_ms_to_ticks((desc.supervision_timeout + 100) * 10, &ticks);
|
||||
ble_npl_callout_reset(&m_dcTimer, ticks);
|
||||
|
||||
rc = ble_gap_terminate(m_conn_id, reason);
|
||||
if (rc != 0) {
|
||||
if(rc != BLE_HS_EALREADY) {
|
||||
ble_npl_callout_stop(&m_dcTimer);
|
||||
}
|
||||
NIMBLE_LOGE(LOG_TAG, "ble_gap_terminate failed: rc=%d %s",
|
||||
rc, NimBLEUtils::returnCodeToString(rc));
|
||||
}
|
||||
} else {
|
||||
NIMBLE_LOGD(LOG_TAG, "Not connected to any peers");
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< disconnect()");
|
||||
m_lastErr = rc;
|
||||
return rc;
|
||||
} // disconnect
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the connection paramaters to use when connecting to a server.
|
||||
* @param [in] minInterval minimum connection interval in 0.625ms units.
|
||||
* @param [in] maxInterval maximum connection interval in 0.625ms units.
|
||||
* @param [in] latency number of packets allowed to skip (extends max interval)
|
||||
* @param [in] timeout the timeout time in 10ms units before disconnecting
|
||||
* @param [in] scanInterval the scan interval to use when attempting to connect in 0.625ms units.
|
||||
* @param [in] scanWindow the scan window to use when attempting to connect in 0.625ms units.
|
||||
* @param [in] minInterval The minimum connection interval in 1.25ms units.
|
||||
* @param [in] maxInterval The maximum connection interval in 1.25ms units.
|
||||
* @param [in] latency The number of packets allowed to skip (extends max interval).
|
||||
* @param [in] timeout The timeout time in 10ms units before disconnecting.
|
||||
* @param [in] scanInterval The scan interval to use when attempting to connect in 0.625ms units.
|
||||
* @param [in] scanWindow The scan window to use when attempting to connect in 0.625ms units.
|
||||
*/
|
||||
void NimBLEClient::setConnectionParams(uint16_t minInterval, uint16_t maxInterval,
|
||||
uint16_t latency, uint16_t timeout,
|
||||
@@ -315,10 +429,10 @@ void NimBLEClient::setConnectionParams(uint16_t minInterval, uint16_t maxInterva
|
||||
/**
|
||||
* @brief Update the connection parameters:
|
||||
* * Can only be used after a connection has been established.
|
||||
* @param [in] minInterval minimum connection interval in 0.625ms units.
|
||||
* @param [in] maxInterval maximum connection interval in 0.625ms units.
|
||||
* @param [in] latency number of packets allowed to skip (extends max interval)
|
||||
* @param [in] timeout the timeout time in 10ms units before disconnecting
|
||||
* @param [in] minInterval The minimum connection interval in 1.25ms units.
|
||||
* @param [in] maxInterval The maximum connection interval in 1.25ms units.
|
||||
* @param [in] latency The number of packets allowed to skip (extends max interval).
|
||||
* @param [in] timeout The timeout time in 10ms units before disconnecting.
|
||||
*/
|
||||
void NimBLEClient::updateConnParams(uint16_t minInterval, uint16_t maxInterval,
|
||||
uint16_t latency, uint16_t timeout)
|
||||
@@ -341,6 +455,47 @@ void NimBLEClient::updateConnParams(uint16_t minInterval, uint16_t maxInterval,
|
||||
} // 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 <= ESP_IDF_VERSION_VAL(4,3,2)
|
||||
return;
|
||||
#else
|
||||
uint16_t tx_time = (tx_octets + 14) * 8;
|
||||
|
||||
int rc = ble_gap_set_data_len(m_conn_id, tx_octets, tx_time);
|
||||
if(rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Set data length error: %d, %s", rc, NimBLEUtils::returnCodeToString(rc));
|
||||
}
|
||||
#endif
|
||||
} // setDataLen
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get detailed information about the current peer connection.
|
||||
*/
|
||||
NimBLEConnInfo NimBLEClient::getConnInfo() {
|
||||
NimBLEConnInfo connInfo;
|
||||
if (!isConnected()) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Not connected");
|
||||
} else {
|
||||
int rc = ble_gap_conn_find(m_conn_id, &connInfo.m_desc);
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Connection info not found");
|
||||
}
|
||||
}
|
||||
|
||||
return connInfo;
|
||||
} // getConnInfo
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the timeout to wait for connection attempt to complete.
|
||||
* @param [in] time The number of seconds before timeout.
|
||||
@@ -399,6 +554,7 @@ int NimBLEClient::getRssi() {
|
||||
if(rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Failed to read RSSI error code: %d, %s",
|
||||
rc, NimBLEUtils::returnCodeToString(rc));
|
||||
m_lastErr = rc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -454,6 +610,16 @@ NimBLERemoteService* NimBLEClient::getService(const NimBLEUUID &uuid) {
|
||||
if(m_servicesVector.size() > prev_size) {
|
||||
return m_servicesVector.back();
|
||||
}
|
||||
|
||||
// If the request was successful but 16/32 bit service not found
|
||||
// try again with the 128 bit uuid.
|
||||
if(uuid.bitSize() == BLE_UUID_TYPE_16 ||
|
||||
uuid.bitSize() == BLE_UUID_TYPE_32)
|
||||
{
|
||||
NimBLEUUID uuid128(uuid);
|
||||
uuid128.to128();
|
||||
return getService(uuid128);
|
||||
}
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< getService: not found");
|
||||
@@ -510,13 +676,14 @@ bool NimBLEClient::retrieveServices(const NimBLEUUID *uuid_filter) {
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, ">> retrieveServices");
|
||||
|
||||
if(!m_isConnected){
|
||||
if(!isConnected()){
|
||||
NIMBLE_LOGE(LOG_TAG, "Disconnected, could not retrieve services -aborting");
|
||||
return false;
|
||||
}
|
||||
|
||||
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) {
|
||||
rc = ble_gattc_disc_all_svcs(m_conn_id, NimBLEClient::serviceDiscoveredCB, &taskData);
|
||||
@@ -527,11 +694,18 @@ bool NimBLEClient::retrieveServices(const NimBLEUUID *uuid_filter) {
|
||||
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "ble_gattc_disc_all_svcs: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
|
||||
m_lastErr = rc;
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef ulTaskNotifyValueClear
|
||||
// Clear the task notification value to ensure we block
|
||||
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
|
||||
#endif
|
||||
|
||||
// wait until we have all the services
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
m_lastErr = taskData.rc;
|
||||
|
||||
if(taskData.rc == 0){
|
||||
NIMBLE_LOGD(LOG_TAG, "<< retrieveServices");
|
||||
@@ -618,10 +792,11 @@ std::string NimBLEClient::getValue(const NimBLEUUID &serviceUUID, const NimBLEUU
|
||||
* @param [in] serviceUUID The service that owns the characteristic.
|
||||
* @param [in] characteristicUUID The characteristic whose value we wish to write.
|
||||
* @param [in] value The value to write to the characteristic.
|
||||
* @param [in] response If true, uses write with response operation.
|
||||
* @returns true if successful otherwise false
|
||||
*/
|
||||
bool NimBLEClient::setValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID,
|
||||
const std::string &value)
|
||||
const std::string &value, bool response)
|
||||
{
|
||||
NIMBLE_LOGD(LOG_TAG, ">> setValue: serviceUUID: %s, characteristicUUID: %s",
|
||||
serviceUUID.toString().c_str(), characteristicUUID.toString().c_str());
|
||||
@@ -632,7 +807,7 @@ bool NimBLEClient::setValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &cha
|
||||
if(pService != nullptr) {
|
||||
NimBLERemoteCharacteristic* pChar = pService->getCharacteristic(characteristicUUID);
|
||||
if(pChar != nullptr) {
|
||||
ret = pChar->writeValue(value);
|
||||
ret = pChar->writeValue(value, response);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -641,6 +816,31 @@ bool NimBLEClient::setValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &cha
|
||||
} // setValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the remote characteristic with the specified handle.
|
||||
* @param [in] handle The handle of the desired characteristic.
|
||||
* @returns The matching remote characteristic, nullptr otherwise.
|
||||
*/
|
||||
NimBLERemoteCharacteristic* NimBLEClient::getCharacteristic(const uint16_t handle)
|
||||
{
|
||||
NimBLERemoteService *pService = nullptr;
|
||||
for(auto it = m_servicesVector.begin(); it != m_servicesVector.end(); ++it) {
|
||||
if ((*it)->getStartHandle() <= handle && handle <= (*it)->getEndHandle()) {
|
||||
pService = *it;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pService != nullptr) {
|
||||
for (auto it = pService->begin(); it != pService->end(); ++it) {
|
||||
if ((*it)->getHandle() == handle) {
|
||||
return *it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the current mtu of this connection.
|
||||
@@ -656,7 +856,8 @@ uint16_t NimBLEClient::getMTU() {
|
||||
* @param [in] event The event structure sent by the NimBLE stack.
|
||||
* @param [in] arg A pointer to the client instance that registered for this callback.
|
||||
*/
|
||||
/*STATIC*/ int NimBLEClient::handleGapEvent(struct ble_gap_event *event, void *arg) {
|
||||
/*STATIC*/
|
||||
int NimBLEClient::handleGapEvent(struct ble_gap_event *event, void *arg) {
|
||||
NimBLEClient* client = (NimBLEClient*)arg;
|
||||
int rc;
|
||||
|
||||
@@ -665,61 +866,67 @@ uint16_t NimBLEClient::getMTU() {
|
||||
switch(event->type) {
|
||||
|
||||
case BLE_GAP_EVENT_DISCONNECT: {
|
||||
if(!client->m_isConnected)
|
||||
return 0;
|
||||
|
||||
if(client->m_conn_id != event->disconnect.conn.conn_handle)
|
||||
return 0;
|
||||
|
||||
client->m_isConnected = false;
|
||||
client->m_waitingToConnect=false;
|
||||
// Remove the device from ignore list so we will scan it again
|
||||
NimBLEDevice::removeIgnored(client->m_peerAddress);
|
||||
|
||||
NIMBLE_LOGI(LOG_TAG, "disconnect; reason=%d, %s", event->disconnect.reason,
|
||||
NimBLEUtils::returnCodeToString(event->disconnect.reason));
|
||||
|
||||
rc = event->disconnect.reason;
|
||||
// If Host reset tell the device now before returning to prevent
|
||||
// any errors caused by calling host functions before resyncing.
|
||||
switch(event->disconnect.reason) {
|
||||
case BLE_HS_ETIMEOUT_HCI:
|
||||
case BLE_HS_EOS:
|
||||
switch(rc) {
|
||||
case BLE_HS_ECONTROLLER:
|
||||
case BLE_HS_ETIMEOUT_HCI:
|
||||
case BLE_HS_ENOTSYNCED:
|
||||
NIMBLE_LOGC(LOG_TAG, "Disconnect - host reset, rc=%d", event->disconnect.reason);
|
||||
NimBLEDevice::onReset(event->disconnect.reason);
|
||||
case BLE_HS_EOS:
|
||||
NIMBLE_LOGC(LOG_TAG, "Disconnect - host reset, rc=%d", rc);
|
||||
NimBLEDevice::onReset(rc);
|
||||
break;
|
||||
default:
|
||||
// Check that the event is for this client.
|
||||
if(client->m_conn_id != event->disconnect.conn.conn_handle) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
//client->m_conn_id = BLE_HS_CONN_HANDLE_NONE;
|
||||
// Stop the disconnect timer since we are now disconnected.
|
||||
ble_npl_callout_stop(&client->m_dcTimer);
|
||||
|
||||
// Remove the device from ignore list so we will scan it again
|
||||
NimBLEDevice::removeIgnored(client->m_peerAddress);
|
||||
|
||||
// No longer connected, clear the connection ID.
|
||||
client->m_conn_id = BLE_HS_CONN_HANDLE_NONE;
|
||||
|
||||
// If we received a connected event but did not get established (no PDU)
|
||||
// then a disconnect event will be sent but we should not send it to the
|
||||
// app for processing. Instead we will ensure the task is released
|
||||
// and report the error.
|
||||
if(!client->m_connEstablished)
|
||||
break;
|
||||
|
||||
NIMBLE_LOGI(LOG_TAG, "disconnect; reason=%d, %s",
|
||||
rc, NimBLEUtils::returnCodeToString(rc));
|
||||
|
||||
client->m_connEstablished = false;
|
||||
client->m_pClientCallbacks->onDisconnect(client);
|
||||
rc = event->disconnect.reason;
|
||||
break;
|
||||
} // BLE_GAP_EVENT_DISCONNECT
|
||||
|
||||
case BLE_GAP_EVENT_CONNECT: {
|
||||
|
||||
if(!client->m_waitingToConnect)
|
||||
// If we aren't waiting for this connection response
|
||||
// we should drop the connection immediately.
|
||||
if(client->isConnected() || client->m_pTaskData == nullptr) {
|
||||
ble_gap_terminate(event->connect.conn_handle, BLE_ERR_REM_USER_CONN_TERM);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//if(client->m_conn_id != BLE_HS_CONN_HANDLE_NONE)
|
||||
// return 0;
|
||||
|
||||
client->m_waitingToConnect=false;
|
||||
|
||||
if (event->connect.status == 0) {
|
||||
client->m_isConnected = true;
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "Connection established");
|
||||
rc = event->connect.status;
|
||||
if (rc == 0) {
|
||||
NIMBLE_LOGI(LOG_TAG, "Connected event");
|
||||
|
||||
client->m_conn_id = event->connect.conn_handle;
|
||||
|
||||
rc = ble_gattc_exchange_mtu(client->m_conn_id, NULL,NULL);
|
||||
if(rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "ble_gattc_exchange_mtu: rc=%d %s",rc,
|
||||
NimBLEUtils::returnCodeToString(rc));
|
||||
NIMBLE_LOGE(LOG_TAG, "MTU exchange error; rc=%d %s",
|
||||
rc, NimBLEUtils::returnCodeToString(rc));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -727,14 +934,10 @@ uint16_t NimBLEClient::getMTU() {
|
||||
// scanning since we are already connected to it
|
||||
NimBLEDevice::addIgnored(client->m_peerAddress);
|
||||
} else {
|
||||
NIMBLE_LOGE(LOG_TAG, "Error: Connection failed; status=%d %s",
|
||||
event->connect.status,
|
||||
NimBLEUtils::returnCodeToString(event->connect.status));
|
||||
|
||||
client->m_isConnected = false;
|
||||
rc = event->connect.status;
|
||||
client->m_conn_id = BLE_HS_CONN_HANDLE_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
} // BLE_GAP_EVENT_CONNECT
|
||||
|
||||
@@ -742,7 +945,14 @@ uint16_t NimBLEClient::getMTU() {
|
||||
if(client->m_conn_id != event->notify_rx.conn_handle)
|
||||
return 0;
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "Notify Recieved for handle: %d",event->notify_rx.attr_handle);
|
||||
// If a notification comes before this flag is set we might
|
||||
// access a vector while it is being cleared in connect()
|
||||
if(!client->m_connEstablished) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "Notify Recieved for handle: %d",
|
||||
event->notify_rx.attr_handle);
|
||||
|
||||
for(auto &it: client->m_servicesVector) {
|
||||
// Dont waste cycles searching services without this handle in its range
|
||||
@@ -752,8 +962,8 @@ uint16_t NimBLEClient::getMTU() {
|
||||
|
||||
auto cVector = &it->m_characteristicVector;
|
||||
NIMBLE_LOGD(LOG_TAG, "checking service %s for handle: %d",
|
||||
it->getUUID().toString().c_str(),
|
||||
event->notify_rx.attr_handle);
|
||||
it->getUUID().toString().c_str(),
|
||||
event->notify_rx.attr_handle);
|
||||
|
||||
auto characteristic = cVector->cbegin();
|
||||
for(; characteristic != cVector->cend(); ++characteristic) {
|
||||
@@ -762,19 +972,21 @@ uint16_t NimBLEClient::getMTU() {
|
||||
}
|
||||
|
||||
if(characteristic != cVector->cend()) {
|
||||
NIMBLE_LOGD(LOG_TAG, "Got Notification for characteristic %s", (*characteristic)->toString().c_str());
|
||||
NIMBLE_LOGD(LOG_TAG, "Got Notification for characteristic %s",
|
||||
(*characteristic)->toString().c_str());
|
||||
|
||||
portENTER_CRITICAL(&(*characteristic)->m_valMux);
|
||||
(*characteristic)->m_value = std::string((char *)event->notify_rx.om->om_data, event->notify_rx.om->om_len);
|
||||
(*characteristic)->m_timestamp = time(nullptr);
|
||||
portEXIT_CRITICAL(&(*characteristic)->m_valMux);
|
||||
uint32_t data_len = OS_MBUF_PKTLEN(event->notify_rx.om);
|
||||
time_t t = time(nullptr);
|
||||
ble_npl_hw_enter_critical();
|
||||
(*characteristic)->m_value = std::string((char *)event->notify_rx.om->om_data, data_len);
|
||||
(*characteristic)->m_timestamp = t;
|
||||
ble_npl_hw_exit_critical(0);
|
||||
|
||||
if ((*characteristic)->m_notifyCallback != nullptr) {
|
||||
NIMBLE_LOGD(LOG_TAG, "Invoking callback for notification on characteristic %s",
|
||||
(*characteristic)->toString().c_str());
|
||||
(*characteristic)->toString().c_str());
|
||||
(*characteristic)->m_notifyCallback(*characteristic, event->notify_rx.om->om_data,
|
||||
event->notify_rx.om->om_len,
|
||||
!event->notify_rx.indication);
|
||||
data_len, !event->notify_rx.indication);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -790,10 +1002,10 @@ uint16_t NimBLEClient::getMTU() {
|
||||
}
|
||||
NIMBLE_LOGD(LOG_TAG, "Peer requesting to update connection parameters");
|
||||
NIMBLE_LOGD(LOG_TAG, "MinInterval: %d, MaxInterval: %d, Latency: %d, Timeout: %d",
|
||||
event->conn_update_req.peer_params->itvl_min,
|
||||
event->conn_update_req.peer_params->itvl_max,
|
||||
event->conn_update_req.peer_params->latency,
|
||||
event->conn_update_req.peer_params->supervision_timeout);
|
||||
event->conn_update_req.peer_params->itvl_min,
|
||||
event->conn_update_req.peer_params->itvl_max,
|
||||
event->conn_update_req.peer_params->latency,
|
||||
event->conn_update_req.peer_params->supervision_timeout);
|
||||
|
||||
rc = client->m_pClientCallbacks->onConnParamsUpdateRequest(client,
|
||||
event->conn_update_req.peer_params) ? 0 : BLE_ERR_CONN_PARMS;
|
||||
@@ -827,7 +1039,9 @@ uint16_t NimBLEClient::getMTU() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(event->enc_change.status == 0 || event->enc_change.status == (BLE_HS_ERR_HCI_BASE + BLE_ERR_PINKEY_MISSING)) {
|
||||
if(event->enc_change.status == 0 ||
|
||||
event->enc_change.status == (BLE_HS_ERR_HCI_BASE + BLE_ERR_PINKEY_MISSING))
|
||||
{
|
||||
struct ble_gap_conn_desc desc;
|
||||
rc = ble_gap_conn_find(event->enc_change.conn_handle, &desc);
|
||||
assert(rc == 0);
|
||||
@@ -922,7 +1136,9 @@ uint16_t NimBLEClient::getMTU() {
|
||||
|
||||
if(client->m_pTaskData != nullptr) {
|
||||
client->m_pTaskData->rc = rc;
|
||||
xTaskNotifyGive(client->m_pTaskData->task);
|
||||
if(client->m_pTaskData->task) {
|
||||
xTaskNotifyGive(client->m_pTaskData->task);
|
||||
}
|
||||
client->m_pTaskData = nullptr;
|
||||
}
|
||||
|
||||
@@ -935,7 +1151,7 @@ uint16_t NimBLEClient::getMTU() {
|
||||
* @return True if we are connected and false if we are not connected.
|
||||
*/
|
||||
bool NimBLEClient::isConnected() {
|
||||
return m_isConnected;
|
||||
return m_conn_id != BLE_HS_CONN_HANDLE_NONE;
|
||||
} // isConnected
|
||||
|
||||
|
||||
@@ -970,6 +1186,15 @@ std::string NimBLEClient::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) {
|
||||
NIMBLE_LOGD("NimBLEClientCallbacks", "onConnect: default");
|
||||
}
|
||||
@@ -1004,5 +1229,4 @@ bool NimBLEClientCallbacks::onConfirmPIN(uint32_t pin){
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
#endif // CONFIG_BT_ENABLED
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|
||||
|
||||
@@ -14,15 +14,13 @@
|
||||
#ifndef MAIN_NIMBLECLIENT_H_
|
||||
#define MAIN_NIMBLECLIENT_H_
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#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 "NimBLEUUID.h"
|
||||
#include "NimBLEUtils.h"
|
||||
#include "NimBLEConnInfo.h"
|
||||
#include "NimBLEAdvertisedDevice.h"
|
||||
#include "NimBLERemoteService.h"
|
||||
|
||||
@@ -30,6 +28,7 @@
|
||||
#include <string>
|
||||
|
||||
class NimBLERemoteService;
|
||||
class NimBLERemoteCharacteristic;
|
||||
class NimBLEClientCallbacks;
|
||||
class NimBLEAdvertisedDevice;
|
||||
|
||||
@@ -54,7 +53,8 @@ public:
|
||||
size_t deleteService(const NimBLEUUID &uuid);
|
||||
std::string getValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID);
|
||||
bool setValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID,
|
||||
const std::string &value);
|
||||
const std::string &value, bool response = false);
|
||||
NimBLERemoteCharacteristic* getCharacteristic(const uint16_t handle);
|
||||
bool isConnected();
|
||||
void setClientCallbacks(NimBLEClientCallbacks *pClientCallbacks,
|
||||
bool deleteCallbacks = true);
|
||||
@@ -68,7 +68,10 @@ public:
|
||||
uint16_t scanInterval=16, uint16_t scanWindow=16);
|
||||
void updateConnParams(uint16_t minInterval, uint16_t maxInterval,
|
||||
uint16_t latency, uint16_t timeout);
|
||||
void setDataLen(uint16_t tx_octets);
|
||||
void discoverAttributes();
|
||||
NimBLEConnInfo getConnInfo();
|
||||
int getLastError();
|
||||
|
||||
private:
|
||||
NimBLEClient(const NimBLEAddress &peerAddress);
|
||||
@@ -82,16 +85,18 @@ private:
|
||||
const struct ble_gatt_error *error,
|
||||
const struct ble_gatt_svc *service,
|
||||
void *arg);
|
||||
static void dcTimerCb(ble_npl_event *event);
|
||||
bool retrieveServices(const NimBLEUUID *uuid_filter = nullptr);
|
||||
|
||||
NimBLEAddress m_peerAddress;
|
||||
int m_lastErr;
|
||||
uint16_t m_conn_id;
|
||||
bool m_isConnected;
|
||||
bool m_waitingToConnect;
|
||||
bool m_connEstablished;
|
||||
bool m_deleteCallbacks;
|
||||
int32_t m_connectTimeout;
|
||||
NimBLEClientCallbacks* m_pClientCallbacks;
|
||||
ble_task_data_t *m_pTaskData;
|
||||
ble_task_data_t* m_pTaskData;
|
||||
ble_npl_callout m_dcTimer;
|
||||
|
||||
std::vector<NimBLERemoteService*> m_servicesVector;
|
||||
|
||||
@@ -153,6 +158,5 @@ public:
|
||||
virtual bool onConfirmPIN(uint32_t pin);
|
||||
};
|
||||
|
||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
#endif // CONFIG_BT_ENABLED
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|
||||
#endif /* MAIN_NIMBLECLIENT_H_ */
|
||||
|
||||
55
src/NimBLEConnInfo.h
Normal file
55
src/NimBLEConnInfo.h
Normal file
@@ -0,0 +1,55 @@
|
||||
#ifndef NIMBLECONNINFO_H_
|
||||
#define NIMBLECONNINFO_H_
|
||||
|
||||
#include "NimBLEAddress.h"
|
||||
|
||||
/**
|
||||
* @brief Connection information.
|
||||
*/
|
||||
class NimBLEConnInfo {
|
||||
friend class NimBLEServer;
|
||||
friend class NimBLEClient;
|
||||
ble_gap_conn_desc m_desc;
|
||||
NimBLEConnInfo() { m_desc = {}; }
|
||||
NimBLEConnInfo(ble_gap_conn_desc desc) { m_desc = desc; }
|
||||
public:
|
||||
/** @brief Gets the over-the-air address of the connected peer */
|
||||
NimBLEAddress getAddress() { return NimBLEAddress(m_desc.peer_ota_addr); }
|
||||
|
||||
/** @brief Gets the ID address of the connected peer */
|
||||
NimBLEAddress getIdAddress() { return NimBLEAddress(m_desc.peer_id_addr); }
|
||||
|
||||
/** @brief Gets the connection handle of the connected peer */
|
||||
uint16_t getConnHandle() { return m_desc.conn_handle; }
|
||||
|
||||
/** @brief Gets the connection interval for this connection (in 1.25ms units) */
|
||||
uint16_t getConnInterval() { return m_desc.conn_itvl; }
|
||||
|
||||
/** @brief Gets the supervision timeout for this connection (in 10ms units) */
|
||||
uint16_t getConnTimeout() { return m_desc.supervision_timeout; }
|
||||
|
||||
/** @brief Gets the allowable latency for this connection (unit = number of intervals) */
|
||||
uint16_t getConnLatency() { return m_desc.conn_latency; }
|
||||
|
||||
/** @brief Gets the maximum transmission unit size for this connection (in bytes) */
|
||||
uint16_t getMTU() { return ble_att_mtu(m_desc.conn_handle); }
|
||||
|
||||
/** @brief Check if we are in the master role in this connection */
|
||||
bool isMaster() { return (m_desc.role == BLE_GAP_ROLE_MASTER); }
|
||||
|
||||
/** @brief Check if we are in the slave role in this connection */
|
||||
bool isSlave() { return (m_desc.role == BLE_GAP_ROLE_SLAVE); }
|
||||
|
||||
/** @brief Check if we are connected to a bonded peer */
|
||||
bool isBonded() { return (m_desc.sec_state.bonded == 1); }
|
||||
|
||||
/** @brief Check if the connection in encrypted */
|
||||
bool isEncrypted() { return (m_desc.sec_state.encrypted == 1); }
|
||||
|
||||
/** @brief Check if the the connection has been authenticated */
|
||||
bool isAuthenticated() { return (m_desc.sec_state.authenticated == 1); }
|
||||
|
||||
/** @brief Gets the key size used to encrypt the connection */
|
||||
uint8_t getSecKeySize() { return m_desc.sec_state.key_size; }
|
||||
};
|
||||
#endif
|
||||
@@ -11,11 +11,9 @@
|
||||
* Created on: Jun 22, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#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 "NimBLEDescriptor.h"
|
||||
@@ -37,6 +35,7 @@ NimBLEDescriptor::NimBLEDescriptor(const char* uuid, uint16_t properties, uint16
|
||||
: NimBLEDescriptor(NimBLEUUID(uuid), max_len, properties, pCharacteristic) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief NimBLEDescriptor constructor.
|
||||
*/
|
||||
@@ -47,11 +46,11 @@ NimBLEDescriptor::NimBLEDescriptor(NimBLEUUID uuid, uint16_t properties, uint16_
|
||||
m_value.attr_len = 0; // Initial length is 0.
|
||||
m_value.attr_max_len = max_len; // Maximum length of the data.
|
||||
m_handle = NULL_HANDLE; // Handle is initially unknown.
|
||||
m_pCharacteristic = nullptr; // No initial characteristic.
|
||||
m_pCharacteristic = pCharacteristic;
|
||||
m_pCallbacks = &defaultCallbacks; // No initial callback.
|
||||
m_value.attr_value = (uint8_t*) calloc(max_len,1); // Allocate storage for the value.
|
||||
m_valMux = portMUX_INITIALIZER_UNLOCKED;
|
||||
m_properties = 0;
|
||||
m_removed = 0;
|
||||
|
||||
if (properties & BLE_GATT_CHR_F_READ) { // convert uint16_t properties to uint8_t
|
||||
m_properties |= BLE_ATT_F_READ;
|
||||
@@ -123,10 +122,29 @@ uint8_t* NimBLEDescriptor::getValue() {
|
||||
} // getValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the value of this descriptor as a string.
|
||||
* @return A std::string instance containing a copy of the descriptor's value.
|
||||
*/
|
||||
std::string NimBLEDescriptor::getStringValue() {
|
||||
return std::string((char *) m_value.attr_value, m_value.attr_len);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the characteristic this descriptor belongs to.
|
||||
* @return A pointer to the characteristic this descriptor belongs to.
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEDescriptor::getCharacteristic() {
|
||||
return m_pCharacteristic;
|
||||
} // getCharacteristic
|
||||
|
||||
|
||||
int NimBLEDescriptor::handleGapEvent(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt,
|
||||
void *arg)
|
||||
{
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg) {
|
||||
(void)conn_handle;
|
||||
(void)attr_handle;
|
||||
|
||||
const ble_uuid_t *uuid;
|
||||
int rc;
|
||||
NimBLEDescriptor* pDescriptor = (NimBLEDescriptor*)arg;
|
||||
@@ -143,9 +161,10 @@ int NimBLEDescriptor::handleGapEvent(uint16_t conn_handle, uint16_t attr_handle,
|
||||
if(ctxt->om->om_pkthdr_len > 8) {
|
||||
pDescriptor->m_pCallbacks->onRead(pDescriptor);
|
||||
}
|
||||
portENTER_CRITICAL(&pDescriptor->m_valMux);
|
||||
|
||||
ble_npl_hw_enter_critical();
|
||||
rc = os_mbuf_append(ctxt->om, pDescriptor->getValue(), pDescriptor->getLength());
|
||||
portEXIT_CRITICAL(&pDescriptor->m_valMux);
|
||||
ble_npl_hw_exit_critical(0);
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
|
||||
@@ -163,7 +182,7 @@ int NimBLEDescriptor::handleGapEvent(uint16_t conn_handle, uint16_t attr_handle,
|
||||
if((len + next->om_len) > pDescriptor->m_value.attr_max_len) {
|
||||
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||
}
|
||||
memcpy(&buf[len-1], next->om_data, next->om_len);
|
||||
memcpy(&buf[len], next->om_data, next->om_len);
|
||||
len += next->om_len;
|
||||
next = SLIST_NEXT(next, om_next);
|
||||
}
|
||||
@@ -216,10 +235,12 @@ void NimBLEDescriptor::setValue(const uint8_t* data, size_t 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);
|
||||
|
||||
ble_npl_hw_enter_critical();
|
||||
m_value.attr_len = length;
|
||||
memcpy(m_value.attr_value, data, length);
|
||||
portEXIT_CRITICAL(&m_valMux);
|
||||
ble_npl_hw_exit_critical(0);
|
||||
|
||||
} // setValue
|
||||
|
||||
|
||||
@@ -231,6 +252,14 @@ void NimBLEDescriptor::setValue(const std::string &value) {
|
||||
setValue((uint8_t*) value.data(), value.length());
|
||||
} // setValue
|
||||
|
||||
/**
|
||||
* @brief Set the characteristic this descriptor belongs to.
|
||||
* @param [in] pChar A pointer to the characteristic this descriptior belongs to.
|
||||
*/
|
||||
void NimBLEDescriptor::setCharacteristic(NimBLECharacteristic* pChar) {
|
||||
m_pCharacteristic = pChar;
|
||||
} // setCharacteristic
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return a string representation of the descriptor.
|
||||
@@ -251,6 +280,7 @@ NimBLEDescriptorCallbacks::~NimBLEDescriptorCallbacks() {}
|
||||
* @param [in] pDescriptor The descriptor that is the source of the event.
|
||||
*/
|
||||
void NimBLEDescriptorCallbacks::onRead(NimBLEDescriptor* pDescriptor) {
|
||||
(void)pDescriptor;
|
||||
NIMBLE_LOGD("NimBLEDescriptorCallbacks", "onRead: default");
|
||||
} // onRead
|
||||
|
||||
@@ -260,8 +290,8 @@ void NimBLEDescriptorCallbacks::onRead(NimBLEDescriptor* pDescriptor) {
|
||||
* @param [in] pDescriptor The descriptor that is the source of the event.
|
||||
*/
|
||||
void NimBLEDescriptorCallbacks::onWrite(NimBLEDescriptor* pDescriptor) {
|
||||
(void)pDescriptor;
|
||||
NIMBLE_LOGD("NimBLEDescriptorCallbacks", "onWrite: default");
|
||||
} // onWrite
|
||||
|
||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||
|
||||
@@ -14,11 +14,9 @@
|
||||
|
||||
#ifndef MAIN_NIMBLEDESCRIPTOR_H_
|
||||
#define MAIN_NIMBLEDESCRIPTOR_H_
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#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 "NimBLEUUID.h"
|
||||
@@ -43,14 +41,29 @@ class NimBLEDescriptorCallbacks;
|
||||
*/
|
||||
class NimBLEDescriptor {
|
||||
public:
|
||||
uint16_t getHandle();
|
||||
size_t getLength();
|
||||
NimBLEUUID getUUID();
|
||||
uint8_t* getValue();
|
||||
void setCallbacks(NimBLEDescriptorCallbacks* pCallbacks);
|
||||
void setValue(const uint8_t* data, size_t size);
|
||||
void setValue(const std::string &value);
|
||||
std::string toString();
|
||||
NimBLEDescriptor(const char* uuid, uint16_t properties,
|
||||
uint16_t max_len,
|
||||
NimBLECharacteristic* pCharacteristic = nullptr);
|
||||
|
||||
NimBLEDescriptor(NimBLEUUID uuid, uint16_t properties,
|
||||
uint16_t max_len,
|
||||
NimBLECharacteristic* pCharacteristic = nullptr);
|
||||
|
||||
~NimBLEDescriptor();
|
||||
|
||||
uint16_t getHandle();
|
||||
NimBLEUUID getUUID();
|
||||
std::string toString();
|
||||
|
||||
void setCallbacks(NimBLEDescriptorCallbacks* pCallbacks);
|
||||
|
||||
size_t getLength();
|
||||
uint8_t* getValue();
|
||||
std::string getStringValue();
|
||||
|
||||
void setValue(const uint8_t* data, size_t size);
|
||||
void setValue(const std::string &value);
|
||||
NimBLECharacteristic* getCharacteristic();
|
||||
|
||||
/**
|
||||
* @brief Convenience template to set the descriptor value to <type\>val.
|
||||
@@ -64,22 +77,12 @@ public:
|
||||
private:
|
||||
friend class NimBLECharacteristic;
|
||||
friend class NimBLEService;
|
||||
friend class NimBLE2902;
|
||||
friend class NimBLE2904;
|
||||
|
||||
NimBLEDescriptor(const char* uuid, uint16_t properties,
|
||||
uint16_t max_len,
|
||||
NimBLECharacteristic* pCharacteristic);
|
||||
|
||||
NimBLEDescriptor(NimBLEUUID uuid, uint16_t properties,
|
||||
uint16_t max_len,
|
||||
NimBLECharacteristic* pCharacteristic);
|
||||
|
||||
~NimBLEDescriptor();
|
||||
|
||||
static int handleGapEvent(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg);
|
||||
void setHandle(uint16_t handle);
|
||||
void setCharacteristic(NimBLECharacteristic* pChar);
|
||||
|
||||
NimBLEUUID m_uuid;
|
||||
uint16_t m_handle;
|
||||
@@ -87,7 +90,7 @@ private:
|
||||
NimBLECharacteristic* m_pCharacteristic;
|
||||
uint8_t m_properties;
|
||||
attr_value_t m_value;
|
||||
portMUX_TYPE m_valMux;
|
||||
uint8_t m_removed;
|
||||
}; // NimBLEDescriptor
|
||||
|
||||
|
||||
@@ -107,6 +110,5 @@ public:
|
||||
|
||||
#include "NimBLE2904.h"
|
||||
|
||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||
#endif /* MAIN_NIMBLEDESCRIPTOR_H_ */
|
||||
|
||||
@@ -11,26 +11,45 @@
|
||||
* Created on: Mar 16, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include "NimBLEDevice.h"
|
||||
#include "NimBLEUtils.h"
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "esp_bt.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_nimble_hci.h"
|
||||
#include "nimble/nimble_port.h"
|
||||
#include "nimble/nimble_port_freertos.h"
|
||||
#include "host/ble_hs.h"
|
||||
#include "host/util/util.h"
|
||||
#include "services/gap/ble_svc_gap.h"
|
||||
#include "services/gatt/ble_svc_gatt.h"
|
||||
#ifdef ESP_PLATFORM
|
||||
# include "esp_err.h"
|
||||
# include "esp_bt.h"
|
||||
# include "nvs_flash.h"
|
||||
# if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
# include "esp_nimble_hci.h"
|
||||
# include "nimble/nimble_port.h"
|
||||
# include "nimble/nimble_port_freertos.h"
|
||||
# include "host/ble_hs.h"
|
||||
# include "host/ble_hs_pvcy.h"
|
||||
# include "host/util/util.h"
|
||||
# include "services/gap/ble_svc_gap.h"
|
||||
# include "services/gatt/ble_svc_gatt.h"
|
||||
# else
|
||||
# include "nimble/esp_port/esp-hci/include/esp_nimble_hci.h"
|
||||
# endif
|
||||
#else
|
||||
# include "nimble/nimble/controller/include/controller/ble_phy.h"
|
||||
#endif
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#include "esp32-hal-bt.h"
|
||||
#ifndef CONFIG_NIMBLE_CPP_IDF
|
||||
# include "nimble/porting/nimble/include/nimble/nimble_port.h"
|
||||
# include "nimble/porting/npl/freertos/include/nimble/nimble_port_freertos.h"
|
||||
# include "nimble/nimble/host/include/host/ble_hs.h"
|
||||
# include "nimble/nimble/host/include/host/ble_hs_pvcy.h"
|
||||
# include "nimble/nimble/host/util/include/host/util/util.h"
|
||||
# include "nimble/nimble/host/services/gap/include/services/gap/ble_svc_gap.h"
|
||||
# include "nimble/nimble/host/services/gatt/include/services/gatt/ble_svc_gatt.h"
|
||||
#endif
|
||||
|
||||
#if defined(ESP_PLATFORM) && defined(CONFIG_ENABLE_ARDUINO_DEPENDS)
|
||||
# include "esp32-hal-bt.h"
|
||||
#endif
|
||||
|
||||
#include "NimBLELog.h"
|
||||
@@ -59,8 +78,13 @@ ble_gap_event_listener NimBLEDevice::m_listener;
|
||||
std::list <NimBLEClient*> NimBLEDevice::m_cList;
|
||||
#endif
|
||||
std::list <NimBLEAddress> NimBLEDevice::m_ignoreList;
|
||||
std::vector<NimBLEAddress> NimBLEDevice::m_whiteList;
|
||||
NimBLESecurityCallbacks* NimBLEDevice::m_securityCallbacks = nullptr;
|
||||
|
||||
uint8_t NimBLEDevice::m_own_addr_type = BLE_OWN_ADDR_PUBLIC;
|
||||
#ifdef ESP_PLATFORM
|
||||
uint16_t NimBLEDevice::m_scanDuplicateSize = CONFIG_BTDM_SCAN_DUPL_CACHE_SIZE;
|
||||
uint8_t NimBLEDevice::m_scanFilterMode = CONFIG_BTDM_SCAN_DUPL_TYPE;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Create a new instance of a server.
|
||||
@@ -125,7 +149,8 @@ void NimBLEDevice::stopAdvertising() {
|
||||
* try and release/delete it.
|
||||
*/
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||
/* STATIC */ NimBLEScan* NimBLEDevice::getScan() {
|
||||
/* STATIC */
|
||||
NimBLEScan* NimBLEDevice::getScan() {
|
||||
if (m_pScan == nullptr) {
|
||||
m_pScan = new NimBLEScan();
|
||||
}
|
||||
@@ -142,10 +167,11 @@ void NimBLEDevice::stopAdvertising() {
|
||||
* @return A reference to the new client object.
|
||||
*/
|
||||
#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) {
|
||||
NIMBLE_LOGW("Number of clients exceeds Max connections. Max=(%d)",
|
||||
NIMBLE_MAX_CONNECTIONS);
|
||||
NIMBLE_LOGW(LOG_TAG,"Number of clients exceeds Max connections. Cur=%d Max=%d",
|
||||
m_cList.size(), NIMBLE_MAX_CONNECTIONS);
|
||||
}
|
||||
|
||||
NimBLEClient* pClient = new NimBLEClient(peerAddress);
|
||||
@@ -160,31 +186,37 @@ void NimBLEDevice::stopAdvertising() {
|
||||
* Checks if it is connected or trying to connect and disconnects/stops it first.
|
||||
* @param [in] pClient A pointer to the client object.
|
||||
*/
|
||||
/* STATIC */ bool NimBLEDevice::deleteClient(NimBLEClient* pClient) {
|
||||
/* STATIC */
|
||||
bool NimBLEDevice::deleteClient(NimBLEClient* pClient) {
|
||||
if(pClient == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set the connection established flag to false to stop notifications
|
||||
// from accessing the attribute vectors while they are being deleted.
|
||||
pClient->m_connEstablished = false;
|
||||
int rc =0;
|
||||
|
||||
if(pClient->m_isConnected) {
|
||||
if(pClient->isConnected()) {
|
||||
rc = pClient->disconnect();
|
||||
if (rc != 0 && rc != BLE_HS_EALREADY && rc != BLE_HS_ENOTCONN) {
|
||||
return false;
|
||||
}
|
||||
|
||||
while(pClient->m_isConnected) {
|
||||
vTaskDelay(10);
|
||||
while(pClient->isConnected()) {
|
||||
taskYIELD();
|
||||
}
|
||||
}
|
||||
// Since we set the flag to false the app will not get a callback
|
||||
// in the disconnect event so we call it here for good measure.
|
||||
pClient->m_pClientCallbacks->onDisconnect(pClient);
|
||||
|
||||
if(pClient->m_waitingToConnect) {
|
||||
} else if(pClient->m_pTaskData != nullptr) {
|
||||
rc = ble_gap_conn_cancel();
|
||||
if (rc != 0 && rc != BLE_HS_EALREADY) {
|
||||
return false;
|
||||
}
|
||||
while(pClient->m_waitingToConnect) {
|
||||
vTaskDelay(10);
|
||||
while(pClient->m_pTaskData != nullptr) {
|
||||
taskYIELD();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,7 +231,8 @@ void NimBLEDevice::stopAdvertising() {
|
||||
* @brief Get the list of created client objects.
|
||||
* @return A pointer to the list of clients.
|
||||
*/
|
||||
/* STATIC */std::list<NimBLEClient*>* NimBLEDevice::getClientList() {
|
||||
/* STATIC */
|
||||
std::list<NimBLEClient*>* NimBLEDevice::getClientList() {
|
||||
return &m_cList;
|
||||
} // getClientList
|
||||
|
||||
@@ -208,7 +241,8 @@ void NimBLEDevice::stopAdvertising() {
|
||||
* @brief Get the number of created client objects.
|
||||
* @return Number of client objects created.
|
||||
*/
|
||||
/* STATIC */size_t NimBLEDevice::getClientListSize() {
|
||||
/* STATIC */
|
||||
size_t NimBLEDevice::getClientListSize() {
|
||||
return m_cList.size();
|
||||
} // getClientList
|
||||
|
||||
@@ -218,7 +252,8 @@ void NimBLEDevice::stopAdvertising() {
|
||||
* @param [in] conn_id The client connection ID to search for.
|
||||
* @return A pointer to the client object with the spcified connection ID.
|
||||
*/
|
||||
/* STATIC */NimBLEClient* NimBLEDevice::getClientByID(uint16_t conn_id) {
|
||||
/* STATIC */
|
||||
NimBLEClient* NimBLEDevice::getClientByID(uint16_t conn_id) {
|
||||
for(auto it = m_cList.cbegin(); it != m_cList.cend(); ++it) {
|
||||
if((*it)->getConnId() == conn_id) {
|
||||
return (*it);
|
||||
@@ -234,7 +269,8 @@ void NimBLEDevice::stopAdvertising() {
|
||||
* @param [in] peer_addr The address of the peer to search for.
|
||||
* @return A pointer to the client object with the peer address.
|
||||
*/
|
||||
/* STATIC */NimBLEClient* NimBLEDevice::getClientByPeerAddress(const NimBLEAddress &peer_addr) {
|
||||
/* STATIC */
|
||||
NimBLEClient* NimBLEDevice::getClientByPeerAddress(const NimBLEAddress &peer_addr) {
|
||||
for(auto it = m_cList.cbegin(); it != m_cList.cend(); ++it) {
|
||||
if((*it)->getPeerAddress().equals(peer_addr)) {
|
||||
return (*it);
|
||||
@@ -248,7 +284,8 @@ void NimBLEDevice::stopAdvertising() {
|
||||
* @brief Finds the first disconnected client in the list.
|
||||
* @return A pointer to the first client object that is not connected to a peer.
|
||||
*/
|
||||
/* STATIC */NimBLEClient* NimBLEDevice::getDisconnectedClient() {
|
||||
/* STATIC */
|
||||
NimBLEClient* NimBLEDevice::getDisconnectedClient() {
|
||||
for(auto it = m_cList.cbegin(); it != m_cList.cend(); ++it) {
|
||||
if(!(*it)->isConnected()) {
|
||||
return (*it);
|
||||
@@ -259,7 +296,7 @@ void NimBLEDevice::stopAdvertising() {
|
||||
|
||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
/**
|
||||
* @brief Set the transmission power.
|
||||
* @param [in] powerLevel The power level to set, can be one of:
|
||||
@@ -285,18 +322,21 @@ void NimBLEDevice::stopAdvertising() {
|
||||
* * ESP_BLE_PWR_TYPE_SCAN = 10, For scan
|
||||
* * ESP_BLE_PWR_TYPE_DEFAULT = 11, For default, if not set other, it will use default value
|
||||
*/
|
||||
/* STATIC */ void NimBLEDevice::setPower(esp_power_level_t powerLevel, esp_ble_power_type_t powerType) {
|
||||
/* STATIC */
|
||||
void NimBLEDevice::setPower(esp_power_level_t powerLevel, esp_ble_power_type_t powerType) {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> setPower: %d (type: %d)", powerLevel, powerType);
|
||||
|
||||
esp_err_t errRc = esp_ble_tx_power_set(powerType, powerLevel);
|
||||
if (errRc != ESP_OK) {
|
||||
NIMBLE_LOGE(LOG_TAG, "esp_ble_tx_power_set: rc=%d", errRc);
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< setPower");
|
||||
} // setPower
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the transmission power.
|
||||
* @brief Get the transmission power.
|
||||
* @param [in] powerType The power level to set, can be one of:
|
||||
* * ESP_BLE_PWR_TYPE_CONN_HDL0 = 0, For connection handle 0
|
||||
* * ESP_BLE_PWR_TYPE_CONN_HDL1 = 1, For connection handle 1
|
||||
@@ -312,9 +352,8 @@ void NimBLEDevice::stopAdvertising() {
|
||||
* * ESP_BLE_PWR_TYPE_DEFAULT = 11, For default, if not set other, it will use default value
|
||||
* @return the power level currently used by the type specified.
|
||||
*/
|
||||
|
||||
/* STATIC */ int NimBLEDevice::getPower(esp_ble_power_type_t powerType) {
|
||||
|
||||
/* STATIC */
|
||||
int NimBLEDevice::getPower(esp_ble_power_type_t powerType) {
|
||||
switch(esp_ble_tx_power_get(powerType)) {
|
||||
case ESP_PWR_LVL_N12:
|
||||
return -12;
|
||||
@@ -335,15 +374,27 @@ void NimBLEDevice::stopAdvertising() {
|
||||
default:
|
||||
return BLE_HS_ADV_TX_PWR_LVL_AUTO;
|
||||
}
|
||||
} // setPower
|
||||
} // getPower
|
||||
|
||||
#else
|
||||
|
||||
void NimBLEDevice::setPower(int dbm) {
|
||||
ble_phy_txpwr_set(dbm);
|
||||
}
|
||||
|
||||
|
||||
int NimBLEDevice::getPower() {
|
||||
return ble_phy_txpwr_get();
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Get our device address.
|
||||
* @return A NimBLEAddress object of our public address if we have one,
|
||||
* if not then our current random address.
|
||||
*/
|
||||
/* STATIC*/ NimBLEAddress NimBLEDevice::getAddress() {
|
||||
/* STATIC*/
|
||||
NimBLEAddress NimBLEDevice::getAddress() {
|
||||
ble_addr_t addr = {BLE_ADDR_PUBLIC, 0};
|
||||
|
||||
if(BLE_HS_ENOADDR == ble_hs_id_copy_addr(BLE_ADDR_PUBLIC, addr.val, NULL)) {
|
||||
@@ -360,7 +411,8 @@ void NimBLEDevice::stopAdvertising() {
|
||||
* @brief Return a string representation of the address of this device.
|
||||
* @return A string representation of this device address.
|
||||
*/
|
||||
/* STATIC */ std::string NimBLEDevice::toString() {
|
||||
/* STATIC */
|
||||
std::string NimBLEDevice::toString() {
|
||||
return getAddress().toString();
|
||||
} // toString
|
||||
|
||||
@@ -370,7 +422,8 @@ void NimBLEDevice::stopAdvertising() {
|
||||
* @param [in] mtu Value to set local mtu:
|
||||
* * This should be larger than 23 and lower or equal to BLE_ATT_MTU_MAX = 527.
|
||||
*/
|
||||
/* STATIC */int NimBLEDevice::setMTU(uint16_t mtu) {
|
||||
/* STATIC */
|
||||
int NimBLEDevice::setMTU(uint16_t mtu) {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> setLocalMTU: %d", mtu);
|
||||
|
||||
int rc = ble_att_set_preferred_mtu(mtu);
|
||||
@@ -388,16 +441,277 @@ void NimBLEDevice::stopAdvertising() {
|
||||
* @brief Get local MTU value set.
|
||||
* @return The current preferred MTU setting.
|
||||
*/
|
||||
/* STATIC */uint16_t NimBLEDevice::getMTU() {
|
||||
/* STATIC */
|
||||
uint16_t NimBLEDevice::getMTU() {
|
||||
return ble_att_preferred_mtu();
|
||||
}
|
||||
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
/**
|
||||
* @brief Set the duplicate filter cache size for filtering scanned devices.
|
||||
* @param [in] cacheSize The number of advertisements filtered before the cache is reset.\n
|
||||
* Range is 10-1000, a larger value will reduce how often the same devices are reported.
|
||||
* @details Must only be called before calling NimBLEDevice::init.
|
||||
*/
|
||||
/*STATIC*/
|
||||
void NimBLEDevice::setScanDuplicateCacheSize(uint16_t cacheSize) {
|
||||
if(initialized) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Cannot change scan cache size while initialized");
|
||||
return;
|
||||
} else if(cacheSize > 1000 || cacheSize <10) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Invalid scan cache size; min=10 max=1000");
|
||||
return;
|
||||
}
|
||||
|
||||
m_scanDuplicateSize = cacheSize;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the duplicate filter mode for filtering scanned devices.
|
||||
* @param [in] mode One of three possible options:
|
||||
* * CONFIG_BTDM_SCAN_DUPL_TYPE_DEVICE (0) (default)\n
|
||||
Filter by device address only, advertisements from the same address will be reported only once.
|
||||
* * CONFIG_BTDM_SCAN_DUPL_TYPE_DATA (1)\n
|
||||
Filter by data only, advertisements with the same data will only be reported once,\n
|
||||
even from different addresses.
|
||||
* * CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE (2)\n
|
||||
Filter by address and data, advertisements from the same address will be reported only once,\n
|
||||
except if the data in the advertisement has changed, then it will be reported again.
|
||||
* @details Must only be called before calling NimBLEDevice::init.
|
||||
*/
|
||||
/*STATIC*/
|
||||
void NimBLEDevice::setScanFilterMode(uint8_t mode) {
|
||||
if(initialized) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Cannot change scan duplicate type while initialized");
|
||||
return;
|
||||
} else if(mode > 2) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Invalid scan duplicate type");
|
||||
return;
|
||||
}
|
||||
|
||||
m_scanFilterMode = mode;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL) || defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
/**
|
||||
* @brief Gets the number of bonded peers stored
|
||||
*/
|
||||
/*STATIC*/
|
||||
int NimBLEDevice::getNumBonds() {
|
||||
ble_addr_t peer_id_addrs[MYNEWT_VAL(BLE_STORE_MAX_BONDS)];
|
||||
int num_peers, rc;
|
||||
|
||||
rc = ble_store_util_bonded_peers(&peer_id_addrs[0], &num_peers, MYNEWT_VAL(BLE_STORE_MAX_BONDS));
|
||||
if (rc !=0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return num_peers;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Deletes all bonding information.
|
||||
*/
|
||||
/*STATIC*/
|
||||
void NimBLEDevice::deleteAllBonds() {
|
||||
ble_store_clear();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Deletes a peer bond.
|
||||
* @param [in] address The address of the peer with which to delete bond info.
|
||||
* @returns true on success.
|
||||
*/
|
||||
/*STATIC*/
|
||||
bool NimBLEDevice::deleteBond(const NimBLEAddress &address) {
|
||||
ble_addr_t delAddr;
|
||||
memcpy(&delAddr.val, address.getNative(),6);
|
||||
delAddr.type = address.getType();
|
||||
|
||||
int rc = ble_gap_unpair(&delAddr);
|
||||
if (rc != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Checks if a peer device is bonded.
|
||||
* @param [in] address The address to check for bonding.
|
||||
* @returns true if bonded.
|
||||
*/
|
||||
/*STATIC*/
|
||||
bool NimBLEDevice::isBonded(const NimBLEAddress &address) {
|
||||
ble_addr_t peer_id_addrs[MYNEWT_VAL(BLE_STORE_MAX_BONDS)];
|
||||
int num_peers, rc;
|
||||
|
||||
rc = ble_store_util_bonded_peers(&peer_id_addrs[0], &num_peers, MYNEWT_VAL(BLE_STORE_MAX_BONDS));
|
||||
if (rc != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < num_peers; i++) {
|
||||
NimBLEAddress storedAddr(peer_id_addrs[i]);
|
||||
if(storedAddr == address) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the address of a bonded peer device by index.
|
||||
* @param [in] index The index to retrieve the peer address of.
|
||||
* @returns NimBLEAddress of the found bonded peer or nullptr if not found.
|
||||
*/
|
||||
/*STATIC*/
|
||||
NimBLEAddress NimBLEDevice::getBondedAddress(int index) {
|
||||
ble_addr_t peer_id_addrs[MYNEWT_VAL(BLE_STORE_MAX_BONDS)];
|
||||
int num_peers, rc;
|
||||
|
||||
rc = ble_store_util_bonded_peers(&peer_id_addrs[0], &num_peers, MYNEWT_VAL(BLE_STORE_MAX_BONDS));
|
||||
if (rc != 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (index > num_peers || index < 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return NimBLEAddress(peer_id_addrs[index]);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Checks if a peer device is whitelisted.
|
||||
* @param [in] address The address to check for in the whitelist.
|
||||
* @returns true if the address is in the whitelist.
|
||||
*/
|
||||
/*STATIC*/
|
||||
bool NimBLEDevice::onWhiteList(const NimBLEAddress & address) {
|
||||
for (auto &it : m_whiteList) {
|
||||
if (it == address) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Add a peer address to the whitelist.
|
||||
* @param [in] address The address to add to the whitelist.
|
||||
* @returns true if successful.
|
||||
*/
|
||||
/*STATIC*/
|
||||
bool NimBLEDevice::whiteListAdd(const NimBLEAddress & address) {
|
||||
if (NimBLEDevice::onWhiteList(address)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
m_whiteList.push_back(address);
|
||||
std::vector<ble_addr_t> wlVec;
|
||||
wlVec.reserve(m_whiteList.size());
|
||||
|
||||
for (auto &it : m_whiteList) {
|
||||
ble_addr_t wlAddr;
|
||||
memcpy(&wlAddr.val, it.getNative(), 6);
|
||||
wlAddr.type = it.getType();
|
||||
wlVec.push_back(wlAddr);
|
||||
}
|
||||
|
||||
int rc = ble_gap_wl_set(&wlVec[0], wlVec.size());
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Failed adding to whitelist rc=%d", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Remove a peer address from the whitelist.
|
||||
* @param [in] address The address to remove from the whitelist.
|
||||
* @returns true if successful.
|
||||
*/
|
||||
/*STATIC*/
|
||||
bool NimBLEDevice::whiteListRemove(const NimBLEAddress & address) {
|
||||
if (!NimBLEDevice::onWhiteList(address)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<ble_addr_t> wlVec;
|
||||
wlVec.reserve(m_whiteList.size());
|
||||
|
||||
for (auto &it : m_whiteList) {
|
||||
if (it != address) {
|
||||
ble_addr_t wlAddr;
|
||||
memcpy(&wlAddr.val, it.getNative(), 6);
|
||||
wlAddr.type = it.getType();
|
||||
wlVec.push_back(wlAddr);
|
||||
}
|
||||
}
|
||||
|
||||
int rc = ble_gap_wl_set(&wlVec[0], wlVec.size());
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Failed removing from whitelist rc=%d", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't remove from the list unless NimBLE returned success
|
||||
for (auto it = m_whiteList.begin(); it < m_whiteList.end(); ++it) {
|
||||
if ((*it) == address) {
|
||||
m_whiteList.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Gets the count of addresses in the whitelist.
|
||||
* @returns The number of addresses in the whitelist.
|
||||
*/
|
||||
/*STATIC*/
|
||||
size_t NimBLEDevice::getWhiteListCount() {
|
||||
return m_whiteList.size();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Gets the address at the vector index.
|
||||
* @param [in] index The vector index to retrieve the address from.
|
||||
* @returns the NimBLEAddress at the whitelist index or nullptr if not found.
|
||||
*/
|
||||
/*STATIC*/
|
||||
NimBLEAddress NimBLEDevice::getWhiteListAddress(size_t index) {
|
||||
if (index > m_whiteList.size()) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Invalid index; %u", index);
|
||||
return nullptr;
|
||||
}
|
||||
return m_whiteList[index];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Host reset, we pass the message so we don't make calls until resynced.
|
||||
* @param [in] reason The reason code for the reset.
|
||||
*/
|
||||
/* STATIC */ void NimBLEDevice::onReset(int reason)
|
||||
/* STATIC */
|
||||
void NimBLEDevice::onReset(int reason)
|
||||
{
|
||||
if(!m_synced) {
|
||||
return;
|
||||
@@ -405,37 +719,24 @@ void NimBLEDevice::stopAdvertising() {
|
||||
|
||||
m_synced = false;
|
||||
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||
if(m_pScan != nullptr) {
|
||||
m_pScan->onHostReset();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Not needed
|
||||
if(m_pServer != nullptr) {
|
||||
m_pServer->onHostReset();
|
||||
}
|
||||
|
||||
for(auto it = m_cList.cbegin(); it != m_cList.cend(); ++it) {
|
||||
(*it)->onHostReset();
|
||||
}
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||
if(m_bleAdvertising != nullptr) {
|
||||
m_bleAdvertising->onHostReset();
|
||||
}
|
||||
#endif
|
||||
|
||||
NIMBLE_LOGC(LOG_TAG, "Resetting state; reason=%d, %s", reason,
|
||||
NimBLEUtils::returnCodeToString(reason));
|
||||
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||
if(initialized) {
|
||||
if(m_pScan != nullptr) {
|
||||
m_pScan->onHostReset();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} // onReset
|
||||
|
||||
|
||||
/**
|
||||
* @brief Host resynced with controller, all clear to make calls to the stack.
|
||||
*/
|
||||
/* STATIC */ void NimBLEDevice::onSync(void)
|
||||
/* STATIC */
|
||||
void NimBLEDevice::onSync(void)
|
||||
{
|
||||
NIMBLE_LOGI(LOG_TAG, "NimBle host synced.");
|
||||
// This check is needed due to potentially being called multiple times in succession
|
||||
@@ -448,20 +749,30 @@ void NimBLEDevice::stopAdvertising() {
|
||||
int rc = ble_hs_util_ensure_addr(0);
|
||||
assert(rc == 0);
|
||||
|
||||
#ifndef ESP_PLATFORM
|
||||
rc = ble_hs_id_infer_auto(m_own_addr_type, &m_own_addr_type);
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "error determining address type; rc=%d", rc);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Yield for houskeeping before returning to operations.
|
||||
// Occasionally triggers exception without.
|
||||
taskYIELD();
|
||||
|
||||
m_synced = true;
|
||||
|
||||
if(initialized) {
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||
if(m_pScan != nullptr) {
|
||||
// Restart scanning with the last values sent, allow to clear results.
|
||||
m_pScan->start(m_pScan->m_duration, m_pScan->m_scanCompleteCB);
|
||||
m_pScan->onHostSync();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||
if(m_bleAdvertising != nullptr) {
|
||||
// Restart advertisng, parameters should already be set.
|
||||
m_bleAdvertising->start();
|
||||
m_bleAdvertising->onHostSync();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -471,9 +782,11 @@ void NimBLEDevice::stopAdvertising() {
|
||||
/**
|
||||
* @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");
|
||||
|
||||
/* This function will return only when nimble_port_stop() is executed */
|
||||
nimble_port_run();
|
||||
|
||||
@@ -485,12 +798,14 @@ void NimBLEDevice::stopAdvertising() {
|
||||
* @brief Initialize the %BLE environment.
|
||||
* @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){
|
||||
int rc=0;
|
||||
#ifdef ESP_PLATFORM
|
||||
esp_err_t errRc = ESP_OK;
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#ifdef CONFIG_ENABLE_ARDUINO_DEPENDS
|
||||
// make sure the linker includes esp32-hal-bt.c so ardruino init doesn't release BLE memory.
|
||||
btStarted();
|
||||
#endif
|
||||
@@ -504,8 +819,22 @@ void NimBLEDevice::stopAdvertising() {
|
||||
|
||||
ESP_ERROR_CHECK(errRc);
|
||||
|
||||
ESP_ERROR_CHECK(esp_nimble_hci_and_controller_init());
|
||||
esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT);
|
||||
|
||||
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
||||
#if defined (CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
bt_cfg.bluetooth_mode = ESP_BT_MODE_BLE;
|
||||
#else
|
||||
bt_cfg.mode = ESP_BT_MODE_BLE;
|
||||
bt_cfg.ble_max_conn = CONFIG_BT_NIMBLE_MAX_CONNECTIONS;
|
||||
#endif
|
||||
bt_cfg.normal_adv_size = m_scanDuplicateSize;
|
||||
bt_cfg.scan_duplicate_type = m_scanFilterMode;
|
||||
|
||||
ESP_ERROR_CHECK(esp_bt_controller_init(&bt_cfg));
|
||||
ESP_ERROR_CHECK(esp_bt_controller_enable(ESP_BT_MODE_BLE));
|
||||
ESP_ERROR_CHECK(esp_nimble_hci_init());
|
||||
#endif
|
||||
nimble_port_init();
|
||||
|
||||
// Setup callbacks for host events
|
||||
@@ -530,9 +859,10 @@ void NimBLEDevice::stopAdvertising() {
|
||||
|
||||
nimble_port_freertos_init(NimBLEDevice::host_task);
|
||||
}
|
||||
|
||||
// Wait for host and controller to sync before returning and accepting new tasks
|
||||
while(!m_synced){
|
||||
vTaskDelay(1 / portTICK_PERIOD_MS);
|
||||
taskYIELD();
|
||||
}
|
||||
|
||||
initialized = true; // Set the initialization flag to ensure we are only initialized once.
|
||||
@@ -544,16 +874,17 @@ void NimBLEDevice::stopAdvertising() {
|
||||
* @param [in] clearAll If true, deletes all server/advertising/scan/client objects after deinitializing.
|
||||
* @note If clearAll is true when called, any references to the created objects become invalid.
|
||||
*/
|
||||
/* STATIC */ void NimBLEDevice::deinit(bool clearAll) {
|
||||
/* STATIC */
|
||||
void NimBLEDevice::deinit(bool clearAll) {
|
||||
int ret = nimble_port_stop();
|
||||
if (ret == 0) {
|
||||
nimble_port_deinit();
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
ret = esp_nimble_hci_and_controller_deinit();
|
||||
if (ret != ESP_OK) {
|
||||
NIMBLE_LOGE(LOG_TAG, "esp_nimble_hci_and_controller_deinit() failed with error: %d", ret);
|
||||
}
|
||||
|
||||
#endif
|
||||
initialized = false;
|
||||
m_synced = false;
|
||||
|
||||
@@ -600,6 +931,7 @@ void NimBLEDevice::stopAdvertising() {
|
||||
* @brief Check if the initialization is complete.
|
||||
* @return true if initialized.
|
||||
*/
|
||||
/*STATIC*/
|
||||
bool NimBLEDevice::getInitialized() {
|
||||
return initialized;
|
||||
} // getInitialized
|
||||
@@ -611,7 +943,8 @@ bool NimBLEDevice::getInitialized() {
|
||||
* @param mitm If true we are capable of man in the middle protection, false if not.
|
||||
* @param sc If true we will perform secure connection pairing, false we will use legacy pairing.
|
||||
*/
|
||||
/*STATIC*/ void NimBLEDevice::setSecurityAuth(bool bonding, bool mitm, bool sc) {
|
||||
/*STATIC*/
|
||||
void NimBLEDevice::setSecurityAuth(bool bonding, bool mitm, bool sc) {
|
||||
NIMBLE_LOGD(LOG_TAG, "Setting bonding: %d, mitm: %d, sc: %d",bonding,mitm,sc);
|
||||
ble_hs_cfg.sm_bonding = bonding;
|
||||
ble_hs_cfg.sm_mitm = mitm;
|
||||
@@ -628,7 +961,8 @@ bool NimBLEDevice::getInitialized() {
|
||||
* * 0x08 BLE_SM_PAIR_AUTHREQ_SC
|
||||
* * 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,
|
||||
(auth_req & BLE_SM_PAIR_AUTHREQ_MITM)>0,
|
||||
(auth_req & BLE_SM_PAIR_AUTHREQ_SC)>0);
|
||||
@@ -644,7 +978,8 @@ bool NimBLEDevice::getInitialized() {
|
||||
* * 0x03 BLE_HS_IO_NO_INPUT_OUTPUT NoInputNoOutput IO capability
|
||||
* * 0x04 BLE_HS_IO_KEYBOARD_DISPLAY KeyboardDisplay Only IO capability
|
||||
*/
|
||||
/*STATIC*/ void NimBLEDevice::setSecurityIOCap(uint8_t iocap) {
|
||||
/*STATIC*/
|
||||
void NimBLEDevice::setSecurityIOCap(uint8_t iocap) {
|
||||
ble_hs_cfg.sm_io_cap = iocap;
|
||||
} // setSecurityIOCap
|
||||
|
||||
@@ -658,7 +993,8 @@ bool NimBLEDevice::getInitialized() {
|
||||
* * 0x04: BLE_SM_PAIR_KEY_DIST_SIGN
|
||||
* * 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;
|
||||
} // setsSecurityInitKey
|
||||
|
||||
@@ -672,7 +1008,8 @@ bool NimBLEDevice::getInitialized() {
|
||||
* * 0x04: BLE_SM_PAIR_KEY_DIST_SIGN
|
||||
* * 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;
|
||||
} // setsSecurityRespKey
|
||||
|
||||
@@ -681,7 +1018,8 @@ bool NimBLEDevice::getInitialized() {
|
||||
* @brief Set the passkey the server will ask for when pairing.
|
||||
* @param [in] pin The passkey to use.
|
||||
*/
|
||||
/*STATIC*/void NimBLEDevice::setSecurityPasskey(uint32_t pin) {
|
||||
/*STATIC*/
|
||||
void NimBLEDevice::setSecurityPasskey(uint32_t pin) {
|
||||
m_passkey = pin;
|
||||
} // setSecurityPasskey
|
||||
|
||||
@@ -690,7 +1028,8 @@ bool NimBLEDevice::getInitialized() {
|
||||
* @brief Get the current passkey used for pairing.
|
||||
* @return The current passkey.
|
||||
*/
|
||||
/*STATIC*/uint32_t NimBLEDevice::getSecurityPasskey() {
|
||||
/*STATIC*/
|
||||
uint32_t NimBLEDevice::getSecurityPasskey() {
|
||||
return m_passkey;
|
||||
} // getSecurityPasskey
|
||||
|
||||
@@ -700,21 +1039,56 @@ bool NimBLEDevice::getInitialized() {
|
||||
* @param [in] callbacks Pointer to NimBLESecurityCallbacks class
|
||||
* @deprecated For backward compatibility, New code should use client/server callback methods.
|
||||
*/
|
||||
/*STATIC*/
|
||||
void NimBLEDevice::setSecurityCallbacks(NimBLESecurityCallbacks* callbacks) {
|
||||
NimBLEDevice::m_securityCallbacks = callbacks;
|
||||
} // setSecurityCallbacks
|
||||
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
/**
|
||||
* @brief Set the own address type.
|
||||
* @param [in] own_addr_type Own Bluetooth Device address type.\n
|
||||
* The available bits are defined as:
|
||||
* * 0x00: BLE_OWN_ADDR_PUBLIC
|
||||
* * 0x01: BLE_OWN_ADDR_RANDOM
|
||||
* * 0x02: BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT
|
||||
* * 0x03: BLE_OWN_ADDR_RPA_RANDOM_DEFAULT
|
||||
* @param [in] useNRPA If true, and address type is random, uses a non-resolvable random address.
|
||||
*/
|
||||
/*STATIC*/
|
||||
void NimBLEDevice::setOwnAddrType(uint8_t own_addr_type, bool useNRPA) {
|
||||
m_own_addr_type = own_addr_type;
|
||||
switch (own_addr_type) {
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
case BLE_OWN_ADDR_PUBLIC:
|
||||
ble_hs_pvcy_rpa_config(NIMBLE_HOST_DISABLE_PRIVACY);
|
||||
break;
|
||||
#endif
|
||||
case BLE_OWN_ADDR_RANDOM:
|
||||
setSecurityInitKey(BLE_SM_PAIR_KEY_DIST_ENC | BLE_SM_PAIR_KEY_DIST_ID);
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
ble_hs_pvcy_rpa_config(useNRPA ? NIMBLE_HOST_ENABLE_NRPA : NIMBLE_HOST_ENABLE_RPA);
|
||||
#endif
|
||||
break;
|
||||
case BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT:
|
||||
case BLE_OWN_ADDR_RPA_RANDOM_DEFAULT:
|
||||
setSecurityInitKey(BLE_SM_PAIR_KEY_DIST_ENC | BLE_SM_PAIR_KEY_DIST_ID);
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
ble_hs_pvcy_rpa_config(NIMBLE_HOST_ENABLE_RPA);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
} // setOwnAddrType
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Start the connection securing and authorization for this connection.
|
||||
* @param conn_id The connection id of the peer device.
|
||||
* @returns NimBLE stack return code, 0 = success.
|
||||
*/
|
||||
/* STATIC */int NimBLEDevice::startSecurity(uint16_t conn_id) {
|
||||
/* if(m_securityCallbacks != nullptr) {
|
||||
m_securityCallbacks->onSecurityRequest();
|
||||
}
|
||||
*/
|
||||
/* STATIC */
|
||||
int NimBLEDevice::startSecurity(uint16_t conn_id) {
|
||||
int rc = ble_gap_security_initiate(conn_id);
|
||||
if(rc != 0){
|
||||
NIMBLE_LOGE(LOG_TAG, "ble_gap_security_initiate: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
|
||||
@@ -729,7 +1103,8 @@ void NimBLEDevice::setSecurityCallbacks(NimBLESecurityCallbacks* callbacks) {
|
||||
* @param [in] address The address to look for.
|
||||
* @return True if ignoring.
|
||||
*/
|
||||
/*STATIC*/ bool NimBLEDevice::isIgnored(const NimBLEAddress &address) {
|
||||
/*STATIC*/
|
||||
bool NimBLEDevice::isIgnored(const NimBLEAddress &address) {
|
||||
for(auto &it : m_ignoreList) {
|
||||
if(it.equals(address)){
|
||||
return true;
|
||||
@@ -744,7 +1119,8 @@ void NimBLEDevice::setSecurityCallbacks(NimBLESecurityCallbacks* callbacks) {
|
||||
* @brief Add a device to the ignore list.
|
||||
* @param [in] address The address of the device we want to ignore.
|
||||
*/
|
||||
/*STATIC*/ void NimBLEDevice::addIgnored(const NimBLEAddress &address) {
|
||||
/*STATIC*/
|
||||
void NimBLEDevice::addIgnored(const NimBLEAddress &address) {
|
||||
m_ignoreList.push_back(address);
|
||||
}
|
||||
|
||||
@@ -753,7 +1129,8 @@ void NimBLEDevice::setSecurityCallbacks(NimBLESecurityCallbacks* callbacks) {
|
||||
* @brief Remove a device from the ignore list.
|
||||
* @param [in] address The address of the device we want to remove from the list.
|
||||
*/
|
||||
/*STATIC*/void NimBLEDevice::removeIgnored(const NimBLEAddress &address) {
|
||||
/*STATIC*/
|
||||
void NimBLEDevice::removeIgnored(const NimBLEAddress &address) {
|
||||
for(auto it = m_ignoreList.begin(); it != m_ignoreList.end(); ++it) {
|
||||
if((*it).equals(address)){
|
||||
m_ignoreList.erase(it);
|
||||
@@ -767,6 +1144,7 @@ void NimBLEDevice::setSecurityCallbacks(NimBLESecurityCallbacks* callbacks) {
|
||||
* @brief Set a custom callback for gap events.
|
||||
* @param [in] handler The function to call when gap events occur.
|
||||
*/
|
||||
/*STATIC*/
|
||||
void NimBLEDevice::setCustomGapHandler(gap_event_handler handler) {
|
||||
m_customGapHandler = handler;
|
||||
int rc = ble_gap_event_listener_register(&m_listener, m_customGapHandler, NULL);
|
||||
@@ -778,5 +1156,4 @@ void NimBLEDevice::setCustomGapHandler(gap_event_handler handler) {
|
||||
}
|
||||
} // setCustomGapHandler
|
||||
|
||||
|
||||
#endif // CONFIG_BT_ENABLED
|
||||
|
||||
@@ -14,10 +14,9 @@
|
||||
|
||||
#ifndef MAIN_NIMBLEDEVICE_H_
|
||||
#define MAIN_NIMBLEDEVICE_H_
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||
#include "NimBLEScan.h"
|
||||
@@ -39,7 +38,9 @@
|
||||
#include "NimBLESecurity.h"
|
||||
#include "NimBLEAddress.h"
|
||||
|
||||
#include "esp_bt.h"
|
||||
#ifdef ESP_PLATFORM
|
||||
# include "esp_bt.h"
|
||||
#endif
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
@@ -95,6 +96,11 @@ public:
|
||||
static bool getInitialized();
|
||||
static NimBLEAddress getAddress();
|
||||
static std::string toString();
|
||||
static bool whiteListAdd(const NimBLEAddress & address);
|
||||
static bool whiteListRemove(const NimBLEAddress & address);
|
||||
static bool onWhiteList(const NimBLEAddress & address);
|
||||
static size_t getWhiteListCount();
|
||||
static NimBLEAddress getWhiteListAddress(size_t index);
|
||||
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||
static NimBLEScan* getScan();
|
||||
@@ -105,8 +111,17 @@ public:
|
||||
static NimBLEServer* getServer();
|
||||
#endif
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
static void setPower(esp_power_level_t powerLevel, esp_ble_power_type_t powerType=ESP_BLE_PWR_TYPE_DEFAULT);
|
||||
static int getPower(esp_ble_power_type_t powerType=ESP_BLE_PWR_TYPE_DEFAULT);
|
||||
static void setOwnAddrType(uint8_t own_addr_type, bool useNRPA=false);
|
||||
static void setScanDuplicateCacheSize(uint16_t cacheSize);
|
||||
static void setScanFilterMode(uint8_t type);
|
||||
#else
|
||||
static void setPower(int dbm);
|
||||
static int getPower();
|
||||
#endif
|
||||
|
||||
static void setCustomGapHandler(gap_event_handler handler);
|
||||
static void setSecurityAuth(bool bonding, bool mitm, bool sc);
|
||||
static void setSecurityAuth(uint8_t auth_req);
|
||||
@@ -139,6 +154,14 @@ public:
|
||||
static std::list<NimBLEClient*>* getClientList();
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL) || defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
static bool deleteBond(const NimBLEAddress &address);
|
||||
static int getNumBonds();
|
||||
static bool isBonded(const NimBLEAddress &address);
|
||||
static void deleteAllBonds();
|
||||
static NimBLEAddress getBondedAddress(int index);
|
||||
#endif
|
||||
|
||||
private:
|
||||
#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
friend class NimBLEClient;
|
||||
@@ -182,6 +205,12 @@ private:
|
||||
static uint32_t m_passkey;
|
||||
static ble_gap_event_listener m_listener;
|
||||
static gap_event_handler m_customGapHandler;
|
||||
static uint8_t m_own_addr_type;
|
||||
#ifdef ESP_PLATFORM
|
||||
static uint16_t m_scanDuplicateSize;
|
||||
static uint8_t m_scanFilterMode;
|
||||
#endif
|
||||
static std::vector<NimBLEAddress> m_whiteList;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -11,12 +11,14 @@
|
||||
* Created on: Mar 12, 2018
|
||||
* Author: pcbreflux
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include "NimBLEEddystoneTLM.h"
|
||||
#include "NimBLELog.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <cstring>
|
||||
|
||||
#define ENDIAN_CHANGE_U16(x) ((((x)&0xFF00)>>8) + (((x)&0xFF)<<8))
|
||||
@@ -124,30 +126,30 @@ std::string NimBLEEddystoneTLM::toString() {
|
||||
out += " C\n";
|
||||
|
||||
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 += "\n";
|
||||
|
||||
out += "Time in seconds ";
|
||||
snprintf(val, sizeof(val), "%d", rawsec/10);
|
||||
snprintf(val, sizeof(val), "%" PRIu32, rawsec/10);
|
||||
out += val;
|
||||
out += "\n";
|
||||
|
||||
out += "Time ";
|
||||
|
||||
snprintf(val, sizeof(val), "%04d", rawsec / 864000);
|
||||
snprintf(val, sizeof(val), "%04" PRIu32, rawsec / 864000);
|
||||
out += val;
|
||||
out += ".";
|
||||
|
||||
snprintf(val, sizeof(val), "%02d", (rawsec / 36000) % 24);
|
||||
snprintf(val, sizeof(val), "%02" PRIu32, (rawsec / 36000) % 24);
|
||||
out += val;
|
||||
out += ":";
|
||||
|
||||
snprintf(val, sizeof(val), "%02d", (rawsec / 600) % 60);
|
||||
snprintf(val, sizeof(val), "%02" PRIu32, (rawsec / 600) % 60);
|
||||
out += val;
|
||||
out += ":";
|
||||
|
||||
snprintf(val, sizeof(val), "%02d", (rawsec / 10) % 60);
|
||||
snprintf(val, sizeof(val), "%02" PRIu32, (rawsec / 10) % 60);
|
||||
out += val;
|
||||
out += "\n";
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#ifndef _NimBLEEddystoneTLM_H_
|
||||
#define _NimBLEEddystoneTLM_H_
|
||||
|
||||
#include "NimBLEUUID.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
* Created on: Mar 12, 2018
|
||||
* Author: pcbreflux
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include "NimBLEEddystoneURL.h"
|
||||
|
||||
248
src/NimBLEHIDDevice.cpp
Normal file
248
src/NimBLEHIDDevice.cpp
Normal file
@@ -0,0 +1,248 @@
|
||||
/*
|
||||
* NimBLEHIDDevice.cpp
|
||||
*
|
||||
* Created: on Oct 06 2020
|
||||
* Author wakwak-koba
|
||||
*
|
||||
* Originally:
|
||||
*
|
||||
* BLEHIDDevice.cpp
|
||||
*
|
||||
* Created on: Jan 03, 2018
|
||||
* Author: chegewara
|
||||
*/
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
|
||||
#include "NimBLEHIDDevice.h"
|
||||
#include "NimBLE2904.h"
|
||||
|
||||
/**
|
||||
* @brief Construct a default NimBLEHIDDevice object.
|
||||
* @param [in] server A pointer to the server instance this HID Device will use.
|
||||
*/
|
||||
NimBLEHIDDevice::NimBLEHIDDevice(NimBLEServer* server) {
|
||||
/*
|
||||
* Here we create mandatory services described in bluetooth specification
|
||||
*/
|
||||
m_deviceInfoService = server->createService(NimBLEUUID((uint16_t) 0x180a));
|
||||
m_hidService = server->createService(NimBLEUUID((uint16_t) 0x1812));
|
||||
m_batteryService = server->createService(NimBLEUUID((uint16_t) 0x180f));
|
||||
|
||||
/*
|
||||
* Mandatory characteristic for device info service
|
||||
*/
|
||||
m_pnpCharacteristic = m_deviceInfoService->createCharacteristic((uint16_t) 0x2a50, NIMBLE_PROPERTY::READ);
|
||||
|
||||
/*
|
||||
* Mandatory characteristics for HID service
|
||||
*/
|
||||
m_hidInfoCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4a, NIMBLE_PROPERTY::READ);
|
||||
m_reportMapCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4b, NIMBLE_PROPERTY::READ);
|
||||
m_hidControlCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4c, NIMBLE_PROPERTY::WRITE_NR);
|
||||
m_protocolModeCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4e, NIMBLE_PROPERTY::WRITE_NR | NIMBLE_PROPERTY::READ);
|
||||
|
||||
/*
|
||||
* Mandatory battery level characteristic with notification and presence descriptor
|
||||
*/
|
||||
m_batteryLevelCharacteristic = m_batteryService->createCharacteristic((uint16_t) 0x2a19, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::NOTIFY);
|
||||
NimBLE2904* batteryLevelDescriptor = (NimBLE2904*)m_batteryLevelCharacteristic->createDescriptor((uint16_t) 0x2904);
|
||||
batteryLevelDescriptor->setFormat(NimBLE2904::FORMAT_UINT8);
|
||||
batteryLevelDescriptor->setNamespace(1);
|
||||
batteryLevelDescriptor->setUnit(0x27ad);
|
||||
|
||||
/*
|
||||
* This value is setup here because its default value in most usage cases, its very rare to use boot mode
|
||||
* and we want to simplify library using as much as possible
|
||||
*/
|
||||
const uint8_t pMode[] = { 0x01 };
|
||||
protocolMode()->setValue((uint8_t*) pMode, 1);
|
||||
}
|
||||
|
||||
NimBLEHIDDevice::~NimBLEHIDDevice() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the report map data formatting information.
|
||||
* @param [in] map A pointer to an array with the values to set.
|
||||
* @param [in] size The number of values in the array.
|
||||
*/
|
||||
void NimBLEHIDDevice::reportMap(uint8_t* map, uint16_t size) {
|
||||
m_reportMapCharacteristic->setValue(map, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start the HID device services.\n
|
||||
* This function called when all the services have been created.
|
||||
*/
|
||||
void NimBLEHIDDevice::startServices() {
|
||||
m_deviceInfoService->start();
|
||||
m_hidService->start();
|
||||
m_batteryService->start();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a manufacturer characteristic (this characteristic is optional).
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEHIDDevice::manufacturer() {
|
||||
m_manufacturerCharacteristic = m_deviceInfoService->createCharacteristic((uint16_t) 0x2a29, NIMBLE_PROPERTY::READ);
|
||||
return m_manufacturerCharacteristic;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set manufacturer name
|
||||
* @param [in] name The manufacturer name of this HID device.
|
||||
*/
|
||||
void NimBLEHIDDevice::manufacturer(std::string name) {
|
||||
m_manufacturerCharacteristic->setValue(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the Plug n Play characterisc value.
|
||||
* @param [in] sig The vendor ID source number.
|
||||
* @param [in] vid The vendor ID number.
|
||||
* @param [in] pid The product ID number.
|
||||
* @param [in] version The produce version number.
|
||||
*/
|
||||
void NimBLEHIDDevice::pnp(uint8_t sig, uint16_t vid, uint16_t pid, uint16_t version) {
|
||||
uint8_t pnp[] = { sig, (uint8_t) (vid >> 8), (uint8_t) vid, (uint8_t) (pid >> 8), (uint8_t) pid, (uint8_t) (version >> 8), (uint8_t) version };
|
||||
m_pnpCharacteristic->setValue(pnp, sizeof(pnp));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the HID Information characteristic value.
|
||||
* @param [in] country The country code for the device.
|
||||
* @param [in] flags The HID Class Specification release number to use.
|
||||
*/
|
||||
void NimBLEHIDDevice::hidInfo(uint8_t country, uint8_t flags) {
|
||||
uint8_t info[] = { 0x11, 0x1, country, flags };
|
||||
m_hidInfoCharacteristic->setValue(info, sizeof(info));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create input report characteristic
|
||||
* @param [in] reportID input report ID, the same as in report map for input object related to the characteristic
|
||||
* @return pointer to new input report characteristic
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEHIDDevice::inputReport(uint8_t reportID) {
|
||||
NimBLECharacteristic* inputReportCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4d, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ_ENC);
|
||||
NimBLEDescriptor* inputReportDescriptor = inputReportCharacteristic->createDescriptor((uint16_t) 0x2908, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::READ_ENC);
|
||||
|
||||
uint8_t desc1_val[] = { reportID, 0x01 };
|
||||
inputReportDescriptor->setValue((uint8_t*) desc1_val, 2);
|
||||
|
||||
return inputReportCharacteristic;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create output report characteristic
|
||||
* @param [in] reportID Output report ID, the same as in report map for output object related to the characteristic
|
||||
* @return Pointer to new output report characteristic
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEHIDDevice::outputReport(uint8_t reportID) {
|
||||
NimBLECharacteristic* outputReportCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4d, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::WRITE_NR | NIMBLE_PROPERTY::READ_ENC | NIMBLE_PROPERTY::WRITE_ENC);
|
||||
NimBLEDescriptor* outputReportDescriptor = outputReportCharacteristic->createDescriptor((uint16_t) 0x2908, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::READ_ENC | NIMBLE_PROPERTY::WRITE_ENC);
|
||||
|
||||
uint8_t desc1_val[] = { reportID, 0x02 };
|
||||
outputReportDescriptor->setValue((uint8_t*) desc1_val, 2);
|
||||
|
||||
return outputReportCharacteristic;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create feature report characteristic.
|
||||
* @param [in] reportID Feature report ID, the same as in report map for feature object related to the characteristic
|
||||
* @return Pointer to new feature report characteristic
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEHIDDevice::featureReport(uint8_t reportID) {
|
||||
NimBLECharacteristic* featureReportCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4d, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::READ_ENC | NIMBLE_PROPERTY::WRITE_ENC);
|
||||
NimBLEDescriptor* featureReportDescriptor = featureReportCharacteristic->createDescriptor((uint16_t) 0x2908, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::READ_ENC | NIMBLE_PROPERTY::WRITE_ENC);
|
||||
|
||||
uint8_t desc1_val[] = { reportID, 0x03 };
|
||||
featureReportDescriptor->setValue((uint8_t*) desc1_val, 2);
|
||||
|
||||
return featureReportCharacteristic;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates a keyboard boot input report characteristic
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEHIDDevice::bootInput() {
|
||||
return m_hidService->createCharacteristic((uint16_t) 0x2a22, NIMBLE_PROPERTY::NOTIFY);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a keyboard boot output report characteristic
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEHIDDevice::bootOutput() {
|
||||
return m_hidService->createCharacteristic((uint16_t) 0x2a32, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::WRITE_NR);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a pointer to the HID control point characteristic.
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEHIDDevice::hidControl() {
|
||||
return m_hidControlCharacteristic;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a pointer to the protocol mode characteristic.
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEHIDDevice::protocolMode() {
|
||||
return m_protocolModeCharacteristic;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the battery level characteristic value.
|
||||
* @param [in] level The battery level value.
|
||||
*/
|
||||
void NimBLEHIDDevice::setBatteryLevel(uint8_t level) {
|
||||
m_batteryLevelCharacteristic->setValue(&level, 1);
|
||||
}
|
||||
/*
|
||||
* @brief Returns battery level characteristic
|
||||
* @ return battery level characteristic
|
||||
*//*
|
||||
BLECharacteristic* BLEHIDDevice::batteryLevel() {
|
||||
return m_batteryLevelCharacteristic;
|
||||
}
|
||||
|
||||
|
||||
|
||||
BLECharacteristic* BLEHIDDevice::reportMap() {
|
||||
return m_reportMapCharacteristic;
|
||||
}
|
||||
|
||||
BLECharacteristic* BLEHIDDevice::pnp() {
|
||||
return m_pnpCharacteristic;
|
||||
}
|
||||
|
||||
|
||||
BLECharacteristic* BLEHIDDevice::hidInfo() {
|
||||
return m_hidInfoCharacteristic;
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Returns a pointer to the device information service.
|
||||
*/
|
||||
NimBLEService* NimBLEHIDDevice::deviceInfo() {
|
||||
return m_deviceInfoService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a pointer to the HID service.
|
||||
*/
|
||||
NimBLEService* NimBLEHIDDevice::hidService() {
|
||||
return m_hidService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief @brief Returns a pointer to the battery service.
|
||||
*/
|
||||
NimBLEService* NimBLEHIDDevice::batteryService() {
|
||||
return m_batteryService;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||
86
src/NimBLEHIDDevice.h
Normal file
86
src/NimBLEHIDDevice.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* NimBLEHIDDevice.h
|
||||
*
|
||||
* Created: on Oct 06 2020
|
||||
* Author wakwak-koba
|
||||
*
|
||||
* Originally:
|
||||
*
|
||||
* BLEHIDDevice.h
|
||||
*
|
||||
* Created on: Jan 03, 2018
|
||||
* Author: chegewara
|
||||
*/
|
||||
|
||||
#ifndef _BLEHIDDEVICE_H_
|
||||
#define _BLEHIDDEVICE_H_
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||
|
||||
#include "NimBLECharacteristic.h"
|
||||
#include "NimBLEService.h"
|
||||
#include "NimBLEDescriptor.h"
|
||||
#include "HIDTypes.h"
|
||||
|
||||
#define GENERIC_HID 0x03C0
|
||||
#define HID_KEYBOARD 0x03C1
|
||||
#define HID_MOUSE 0x03C2
|
||||
#define HID_JOYSTICK 0x03C3
|
||||
#define HID_GAMEPAD 0x03C4
|
||||
#define HID_TABLET 0x03C5
|
||||
#define HID_CARD_READER 0x03C6
|
||||
#define HID_DIGITAL_PEN 0x03C7
|
||||
#define HID_BARCODE 0x03C8
|
||||
|
||||
|
||||
/**
|
||||
* @brief A model of a %BLE Human Interface Device.
|
||||
*/
|
||||
class NimBLEHIDDevice {
|
||||
public:
|
||||
NimBLEHIDDevice(NimBLEServer*);
|
||||
virtual ~NimBLEHIDDevice();
|
||||
|
||||
void reportMap(uint8_t* map, uint16_t);
|
||||
void startServices();
|
||||
|
||||
NimBLEService* deviceInfo();
|
||||
NimBLEService* hidService();
|
||||
NimBLEService* batteryService();
|
||||
|
||||
NimBLECharacteristic* manufacturer();
|
||||
void manufacturer(std::string name);
|
||||
//NimBLECharacteristic* pnp();
|
||||
void pnp(uint8_t sig, uint16_t vid, uint16_t pid, uint16_t version);
|
||||
//NimBLECharacteristic* hidInfo();
|
||||
void hidInfo(uint8_t country, uint8_t flags);
|
||||
//NimBLECharacteristic* batteryLevel();
|
||||
void setBatteryLevel(uint8_t level);
|
||||
|
||||
|
||||
//NimBLECharacteristic* reportMap();
|
||||
NimBLECharacteristic* hidControl();
|
||||
NimBLECharacteristic* inputReport(uint8_t reportID);
|
||||
NimBLECharacteristic* outputReport(uint8_t reportID);
|
||||
NimBLECharacteristic* featureReport(uint8_t reportID);
|
||||
NimBLECharacteristic* protocolMode();
|
||||
NimBLECharacteristic* bootInput();
|
||||
NimBLECharacteristic* bootOutput();
|
||||
|
||||
private:
|
||||
NimBLEService* m_deviceInfoService; //0x180a
|
||||
NimBLEService* m_hidService; //0x1812
|
||||
NimBLEService* m_batteryService = 0; //0x180f
|
||||
|
||||
NimBLECharacteristic* m_manufacturerCharacteristic; //0x2a29
|
||||
NimBLECharacteristic* m_pnpCharacteristic; //0x2a50
|
||||
NimBLECharacteristic* m_hidInfoCharacteristic; //0x2a4a
|
||||
NimBLECharacteristic* m_reportMapCharacteristic; //0x2a4b
|
||||
NimBLECharacteristic* m_hidControlCharacteristic; //0x2a4c
|
||||
NimBLECharacteristic* m_protocolModeCharacteristic; //0x2a4e
|
||||
NimBLECharacteristic* m_batteryLevelCharacteristic; //0x2a19
|
||||
};
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER */
|
||||
#endif /* _BLEHIDDEVICE_H_ */
|
||||
100
src/NimBLELog.h
100
src/NimBLELog.h
@@ -7,54 +7,74 @@
|
||||
*/
|
||||
#ifndef MAIN_NIMBLELOG_H_
|
||||
#define MAIN_NIMBLELOG_H_
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include "nimconfig.h"
|
||||
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include "syscfg/syscfg.h"
|
||||
#include "modlog/modlog.h"
|
||||
#if defined(CONFIG_NIMBLE_CPP_IDF) // using esp-idf
|
||||
# include "esp_log.h"
|
||||
# ifndef CONFIG_NIMBLE_CPP_LOG_LEVEL
|
||||
# define CONFIG_NIMBLE_CPP_LOG_LEVEL 0
|
||||
# endif
|
||||
|
||||
# define NIMBLE_CPP_LOG_PRINT(level, tag, format, ...) do { \
|
||||
if (CONFIG_NIMBLE_CPP_LOG_LEVEL >= level) \
|
||||
ESP_LOG_LEVEL_LOCAL(level, tag, format, ##__VA_ARGS__); \
|
||||
} while(0)
|
||||
|
||||
// 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.
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#ifndef CORE_DEBUG_LEVEL
|
||||
#define CORE_DEBUG_LEVEL CONFIG_ARDUHAL_LOG_DEFAULT_LEVEL
|
||||
#endif
|
||||
# define NIMBLE_LOGD(tag, format, ...) \
|
||||
NIMBLE_CPP_LOG_PRINT(ESP_LOG_DEBUG, tag, format, ##__VA_ARGS__)
|
||||
|
||||
#if CORE_DEBUG_LEVEL >= 4
|
||||
#define NIMBLE_LOGD( tag, format, ... ) MODLOG_DFLT(ERROR, "D %s: "#format"\n",tag,##__VA_ARGS__)
|
||||
#else
|
||||
#define NIMBLE_LOGD( tag, format, ... ) (void)tag
|
||||
#endif
|
||||
# define NIMBLE_LOGI(tag, format, ...) \
|
||||
NIMBLE_CPP_LOG_PRINT(ESP_LOG_INFO, tag, format, ##__VA_ARGS__)
|
||||
|
||||
#if CORE_DEBUG_LEVEL >= 3
|
||||
#define NIMBLE_LOGI( tag, format, ... ) MODLOG_DFLT(ERROR, "I %s: "#format"\n",tag,##__VA_ARGS__)
|
||||
#else
|
||||
#define NIMBLE_LOGI( tag, format, ... ) (void)tag
|
||||
#endif
|
||||
# define NIMBLE_LOGW(tag, format, ...) \
|
||||
NIMBLE_CPP_LOG_PRINT(ESP_LOG_WARN, tag, format, ##__VA_ARGS__)
|
||||
|
||||
#if CORE_DEBUG_LEVEL >= 2
|
||||
#define NIMBLE_LOGW( tag, format, ... ) MODLOG_DFLT(ERROR, "W %s: "#format"\n",tag,##__VA_ARGS__)
|
||||
#else
|
||||
#define NIMBLE_LOGW( tag, format, ... ) (void)tag
|
||||
#endif
|
||||
# define NIMBLE_LOGE(tag, format, ...) \
|
||||
NIMBLE_CPP_LOG_PRINT(ESP_LOG_ERROR, tag, format, ##__VA_ARGS__)
|
||||
|
||||
#if CORE_DEBUG_LEVEL >= 1
|
||||
#define NIMBLE_LOGE( tag, format, ... ) MODLOG_DFLT(ERROR, "E %s: "#format"\n",tag,##__VA_ARGS__)
|
||||
#else
|
||||
#define NIMBLE_LOGE( tag, format, ... ) (void)tag
|
||||
#endif
|
||||
# define NIMBLE_LOGC(tag, format, ...) \
|
||||
NIMBLE_CPP_LOG_PRINT(ESP_LOG_ERROR, tag, format, ##__VA_ARGS__)
|
||||
|
||||
#define NIMBLE_LOGC( tag, format, ... ) MODLOG_DFLT(CRITICAL, "CRIT %s: "#format"\n",tag,##__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
|
||||
|
||||
#else
|
||||
#define NIMBLE_LOGE( tag, format, ... ) MODLOG_DFLT(ERROR, "\033[0;31mE %s: "#format"\033[0m\n",tag,##__VA_ARGS__)
|
||||
#define NIMBLE_LOGW( tag, format, ... ) MODLOG_DFLT(WARN, "\033[0;33mW %s: "#format"\033[0m\n",tag,##__VA_ARGS__)
|
||||
#define NIMBLE_LOGI( tag, format, ... ) MODLOG_DFLT(INFO, "\033[0;32mI %s: "#format"\033[0m\n",tag,##__VA_ARGS__)
|
||||
#define NIMBLE_LOGD( tag, format, ... ) MODLOG_DFLT(DEBUG, "D %s: "#format"\n",tag,##__VA_ARGS__)
|
||||
#define NIMBLE_LOGC( tag, format, ... ) MODLOG_DFLT(CRITICAL, "\033[1;31mCRIT %s: "#format"\033[0m\n",tag,##__VA_ARGS__)
|
||||
#endif /*ARDUINO_ARCH_ESP32*/
|
||||
# if CONFIG_NIMBLE_CPP_LOG_LEVEL >= 4
|
||||
# define NIMBLE_LOGD( tag, format, ... ) console_printf("D %s: "#format"\n",tag,##__VA_ARGS__)
|
||||
# else
|
||||
# define NIMBLE_LOGD( tag, format, ... ) (void)tag
|
||||
# endif
|
||||
|
||||
#endif /*CONFIG_BT_ENABLED*/
|
||||
#endif /*MAIN_NIMBLELOG_H_*/
|
||||
# if CONFIG_NIMBLE_CPP_LOG_LEVEL >= 3
|
||||
# define NIMBLE_LOGI( tag, format, ... ) console_printf("I %s: "#format"\n",tag,##__VA_ARGS__)
|
||||
# else
|
||||
# define NIMBLE_LOGI( tag, format, ... ) (void)tag
|
||||
# endif
|
||||
|
||||
# if CONFIG_NIMBLE_CPP_LOG_LEVEL >= 2
|
||||
# define NIMBLE_LOGW( tag, format, ... ) console_printf("W %s: "#format"\n",tag,##__VA_ARGS__)
|
||||
# else
|
||||
# define NIMBLE_LOGW( tag, format, ... ) (void)tag
|
||||
# endif
|
||||
|
||||
# if CONFIG_NIMBLE_CPP_LOG_LEVEL >= 1
|
||||
# define NIMBLE_LOGE( tag, format, ... ) console_printf("E %s: "#format"\n",tag,##__VA_ARGS__)
|
||||
# define NIMBLE_LOGC( tag, format, ... ) console_printf("CRIT %s: "#format"\n",tag,##__VA_ARGS__)
|
||||
# else
|
||||
# define NIMBLE_LOGE( tag, format, ... ) (void)tag
|
||||
# define NIMBLE_LOGC( tag, format, ... ) (void)tag
|
||||
# endif
|
||||
|
||||
#endif /* CONFIG_NIMBLE_CPP_IDF */
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
#endif /* MAIN_NIMBLELOG_H_ */
|
||||
|
||||
@@ -12,16 +12,15 @@
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#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 "NimBLEUtils.h"
|
||||
#include "NimBLELog.h"
|
||||
|
||||
#include <climits>
|
||||
|
||||
static const char* LOG_TAG = "NimBLERemoteCharacteristic";
|
||||
|
||||
/**
|
||||
@@ -38,7 +37,7 @@ static const char* LOG_TAG = "NimBLERemoteCharacteristic";
|
||||
NimBLERemoteCharacteristic::NimBLERemoteCharacteristic(NimBLERemoteService *pRemoteService,
|
||||
const struct ble_gatt_chr *chr)
|
||||
{
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, ">> NimBLERemoteCharacteristic()");
|
||||
switch (chr->uuid.u.type) {
|
||||
case BLE_UUID_TYPE_16:
|
||||
m_uuid = NimBLEUUID(chr->uuid.u16.value);
|
||||
@@ -50,17 +49,18 @@ static const char* LOG_TAG = "NimBLERemoteCharacteristic";
|
||||
m_uuid = NimBLEUUID(const_cast<ble_uuid128_t*>(&chr->uuid.u128));
|
||||
break;
|
||||
default:
|
||||
m_uuid = nullptr;
|
||||
break;
|
||||
}
|
||||
|
||||
m_handle = chr->val_handle;
|
||||
m_defHandle = chr->def_handle;
|
||||
m_endHandle = 0;
|
||||
m_charProp = chr->properties;
|
||||
m_pRemoteService = pRemoteService;
|
||||
m_notifyCallback = nullptr;
|
||||
m_timestamp = 0;
|
||||
m_valMux = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< NimBLERemoteCharacteristic(): %s", m_uuid.toString().c_str());
|
||||
} // NimBLERemoteCharacteristic
|
||||
|
||||
|
||||
@@ -145,31 +145,25 @@ int NimBLERemoteCharacteristic::descriptorDiscCB(uint16_t conn_handle,
|
||||
const struct ble_gatt_dsc *dsc,
|
||||
void *arg)
|
||||
{
|
||||
NIMBLE_LOGD(LOG_TAG,"Descriptor Discovered >> status: %d handle: %d",
|
||||
error->status, (error->status == 0) ? dsc->handle : -1);
|
||||
int rc = error->status;
|
||||
NIMBLE_LOGD(LOG_TAG, "Descriptor Discovered >> status: %d handle: %d",
|
||||
rc, (rc == 0) ? dsc->handle : -1);
|
||||
|
||||
desc_filter_t *filter = (desc_filter_t*)arg;
|
||||
const NimBLEUUID *uuid_filter = filter->uuid;
|
||||
ble_task_data_t *pTaskData = (ble_task_data_t*)filter->task_data;
|
||||
NimBLERemoteCharacteristic *characteristic = (NimBLERemoteCharacteristic*)pTaskData->pATT;
|
||||
int rc=0;
|
||||
|
||||
if(characteristic->getRemoteService()->getClient()->getConnId() != conn_handle){
|
||||
if (characteristic->getRemoteService()->getClient()->getConnId() != conn_handle){
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (error->status) {
|
||||
switch (rc) {
|
||||
case 0: {
|
||||
if(dsc->uuid.u.type == BLE_UUID_TYPE_16 && dsc->uuid.u16.value == uint16_t(0x2803)) {
|
||||
NIMBLE_LOGD(LOG_TAG,"Descriptor NOT found - end of Characteristic definintion");
|
||||
rc = BLE_HS_EDONE;
|
||||
break;
|
||||
}
|
||||
if(uuid_filter != nullptr) {
|
||||
if(ble_uuid_cmp(&uuid_filter->getNative()->u, &dsc->uuid.u) != 0) {
|
||||
if (uuid_filter != nullptr) {
|
||||
if (ble_uuid_cmp(&uuid_filter->getNative()->u, &dsc->uuid.u) != 0) {
|
||||
return 0;
|
||||
} else {
|
||||
NIMBLE_LOGD(LOG_TAG,"Descriptor Found");
|
||||
rc = BLE_HS_EDONE;
|
||||
}
|
||||
}
|
||||
@@ -179,11 +173,10 @@ int NimBLERemoteCharacteristic::descriptorDiscCB(uint16_t conn_handle,
|
||||
break;
|
||||
}
|
||||
default:
|
||||
rc = error->status;
|
||||
break;
|
||||
}
|
||||
|
||||
/** If rc == BLE_HS_EDONE, resume the task with a success error code and stop the discovery process.
|
||||
/* If rc == BLE_HS_EDONE, resume the task with a success error code and stop the discovery process.
|
||||
* Else if rc == 0, just return 0 to continue the discovery until we get BLE_HS_EDONE.
|
||||
* If we get any other error code tell the application to abort by returning non-zero in the rc.
|
||||
*/
|
||||
@@ -201,6 +194,38 @@ int NimBLERemoteCharacteristic::descriptorDiscCB(uint16_t conn_handle,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief callback from NimBLE when the next characteristic of the service is discovered.
|
||||
*/
|
||||
int NimBLERemoteCharacteristic::nextCharCB(uint16_t conn_handle,
|
||||
const struct ble_gatt_error *error,
|
||||
const struct ble_gatt_chr *chr, void *arg)
|
||||
{
|
||||
int rc = error->status;
|
||||
NIMBLE_LOGD(LOG_TAG, "Next Characteristic >> status: %d handle: %d",
|
||||
rc, (rc == 0) ? chr->val_handle : -1);
|
||||
|
||||
ble_task_data_t *pTaskData = (ble_task_data_t*)arg;
|
||||
NimBLERemoteCharacteristic *pChar = (NimBLERemoteCharacteristic*)pTaskData->pATT;
|
||||
|
||||
if (pChar->getRemoteService()->getClient()->getConnId() != conn_handle) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (rc == 0) {
|
||||
pChar->m_endHandle = chr->def_handle - 1;
|
||||
rc = BLE_HS_EDONE;
|
||||
} else if (rc == BLE_HS_EDONE) {
|
||||
pChar->m_endHandle = pChar->getRemoteService()->getEndHandle();
|
||||
} else {
|
||||
pTaskData->rc = rc;
|
||||
}
|
||||
|
||||
xTaskNotifyGive(pTaskData->task);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Populate the descriptors (if any) for this characteristic.
|
||||
* @param [in] the end handle of the characteristic, or the service, whichever comes first.
|
||||
@@ -208,29 +233,67 @@ int NimBLERemoteCharacteristic::descriptorDiscCB(uint16_t conn_handle,
|
||||
bool NimBLERemoteCharacteristic::retrieveDescriptors(const NimBLEUUID *uuid_filter) {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> retrieveDescriptors() for characteristic: %s", getUUID().toString().c_str());
|
||||
|
||||
// If this is the last handle then there are no descriptors
|
||||
if (m_handle == getRemoteService()->getEndHandle()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int rc = 0;
|
||||
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
|
||||
// The end handle is the next characteristic definition handle -1.
|
||||
if (m_endHandle == 0) {
|
||||
rc = ble_gattc_disc_all_chrs(getRemoteService()->getClient()->getConnId(),
|
||||
m_handle,
|
||||
getRemoteService()->getEndHandle(),
|
||||
NimBLERemoteCharacteristic::nextCharCB,
|
||||
&taskData);
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Error getting end handle rc=%d", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef ulTaskNotifyValueClear
|
||||
// Clear the task notification value to ensure we block
|
||||
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
|
||||
#endif
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
|
||||
if (taskData.rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Could not retrieve end handle rc=%d", taskData.rc);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
desc_filter_t filter = {uuid_filter, &taskData};
|
||||
|
||||
rc = ble_gattc_disc_all_dscs(getRemoteService()->getClient()->getConnId(),
|
||||
m_handle,
|
||||
getRemoteService()->getEndHandle(),
|
||||
m_endHandle,
|
||||
NimBLERemoteCharacteristic::descriptorDiscCB,
|
||||
&filter);
|
||||
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "ble_gattc_disc_all_chrs: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
|
||||
NIMBLE_LOGE(LOG_TAG, "ble_gattc_disc_all_dscs: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef ulTaskNotifyValueClear
|
||||
// Clear the task notification value to ensure we block
|
||||
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
|
||||
#endif
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
|
||||
if(taskData.rc != 0) {
|
||||
return false;
|
||||
if (taskData.rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Failed to retrieve descriptors; startHandle:%d endHandle:%d taskData.rc=%d",
|
||||
m_handle, m_endHandle, taskData.rc);
|
||||
}
|
||||
|
||||
return true;
|
||||
NIMBLE_LOGD(LOG_TAG, "<< retrieveDescriptors(): Found %d descriptors.", m_descriptorVector.size());
|
||||
} // getDescriptors
|
||||
return (taskData.rc == 0);
|
||||
} // retrieveDescriptors
|
||||
|
||||
|
||||
/**
|
||||
@@ -243,7 +306,7 @@ NimBLERemoteDescriptor* NimBLERemoteCharacteristic::getDescriptor(const NimBLEUU
|
||||
|
||||
for(auto &it: m_descriptorVector) {
|
||||
if(it->getUUID() == uuid) {
|
||||
NIMBLE_LOGD(LOG_TAG, "<< getDescriptor: found");
|
||||
NIMBLE_LOGD(LOG_TAG, "<< getDescriptor: found the descriptor with uuid: %s", uuid.toString().c_str());
|
||||
return it;
|
||||
}
|
||||
}
|
||||
@@ -253,7 +316,18 @@ NimBLERemoteDescriptor* NimBLERemoteCharacteristic::getDescriptor(const NimBLEUU
|
||||
if(m_descriptorVector.size() > prev_size) {
|
||||
return m_descriptorVector.back();
|
||||
}
|
||||
|
||||
// If the request was successful but 16/32 bit descriptor not found
|
||||
// try again with the 128 bit uuid.
|
||||
if(uuid.bitSize() == BLE_UUID_TYPE_16 ||
|
||||
uuid.bitSize() == BLE_UUID_TYPE_32)
|
||||
{
|
||||
NimBLEUUID uuid128(uuid);
|
||||
uuid128.to128();
|
||||
return getDescriptor(uuid128);
|
||||
}
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< getDescriptor: Not found");
|
||||
return nullptr;
|
||||
} // getDescriptor
|
||||
@@ -341,12 +415,12 @@ NimBLEUUID NimBLERemoteCharacteristic::getUUID() {
|
||||
* @return The value of the remote characteristic.
|
||||
*/
|
||||
std::string NimBLERemoteCharacteristic::getValue(time_t *timestamp) {
|
||||
portENTER_CRITICAL(&m_valMux);
|
||||
ble_npl_hw_enter_critical();
|
||||
std::string value = m_value;
|
||||
if(timestamp != nullptr) {
|
||||
*timestamp = m_timestamp;
|
||||
}
|
||||
portEXIT_CRITICAL(&m_valMux);
|
||||
ble_npl_hw_exit_critical(0);
|
||||
|
||||
return value;
|
||||
}
|
||||
@@ -410,7 +484,8 @@ std::string NimBLERemoteCharacteristic::readValue(time_t *timestamp) {
|
||||
|
||||
int rc = 0;
|
||||
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 {
|
||||
rc = ble_gattc_read_long(pClient->getConnId(), m_handle, 0,
|
||||
@@ -422,6 +497,10 @@ std::string NimBLERemoteCharacteristic::readValue(time_t *timestamp) {
|
||||
return value;
|
||||
}
|
||||
|
||||
#ifdef ulTaskNotifyValueClear
|
||||
// Clear the task notification value to ensure we block
|
||||
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
|
||||
#endif
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
rc = taskData.rc;
|
||||
|
||||
@@ -447,13 +526,14 @@ std::string NimBLERemoteCharacteristic::readValue(time_t *timestamp) {
|
||||
}
|
||||
} while(rc != 0 && retryCount--);
|
||||
|
||||
portENTER_CRITICAL(&m_valMux);
|
||||
time_t t = time(nullptr);
|
||||
ble_npl_hw_enter_critical();
|
||||
m_value = value;
|
||||
m_timestamp = time(nullptr);
|
||||
m_timestamp = t;
|
||||
if(timestamp != nullptr) {
|
||||
*timestamp = m_timestamp;
|
||||
}
|
||||
portEXIT_CRITICAL(&m_valMux);
|
||||
ble_npl_hw_exit_critical(0);
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< readValue length: %d rc=%d", value.length(), rc);
|
||||
return value;
|
||||
@@ -483,11 +563,12 @@ int NimBLERemoteCharacteristic::onReadCB(uint16_t conn_handle,
|
||||
|
||||
if(rc == 0) {
|
||||
if(attr) {
|
||||
if(((*strBuf).length() + attr->om->om_len) > BLE_ATT_ATTR_MAX_LEN) {
|
||||
uint32_t data_len = OS_MBUF_PKTLEN(attr->om);
|
||||
if(((*strBuf).length() + data_len) > BLE_ATT_ATTR_MAX_LEN) {
|
||||
rc = BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||
} else {
|
||||
NIMBLE_LOGD(LOG_TAG, "Got %d bytes", attr->om->om_len);
|
||||
(*strBuf) += std::string((char*) attr->om->om_data, attr->om->om_len);
|
||||
NIMBLE_LOGD(LOG_TAG, "Got %d bytes", data_len);
|
||||
(*strBuf) += std::string((char*) attr->om->om_data, data_len);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -506,19 +587,19 @@ int NimBLERemoteCharacteristic::onReadCB(uint16_t conn_handle,
|
||||
* @param [in] notifyCallback A callback to be invoked for a notification.
|
||||
* @param [in] response If write response required set this to true.
|
||||
* If NULL is provided then no callback is performed.
|
||||
* @return true if successful.
|
||||
* @return false if writing to the descriptor failed.
|
||||
*/
|
||||
bool NimBLERemoteCharacteristic::setNotify(uint16_t val, notify_callback notifyCallback, bool response) {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> setNotify(): %s, %02x", toString().c_str(), val);
|
||||
|
||||
m_notifyCallback = notifyCallback;
|
||||
|
||||
NimBLERemoteDescriptor* desc = getDescriptor(NimBLEUUID((uint16_t)0x2902));
|
||||
if(desc == nullptr) {
|
||||
NIMBLE_LOGE(LOG_TAG, "<< setNotify(): Could not get descriptor");
|
||||
return false;
|
||||
NIMBLE_LOGW(LOG_TAG, "<< setNotify(): Callback set, CCCD not found");
|
||||
return true;
|
||||
}
|
||||
|
||||
m_notifyCallback = notifyCallback;
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< setNotify()");
|
||||
|
||||
return desc->writeValue((uint8_t *)&val, 2, response);
|
||||
@@ -531,7 +612,7 @@ bool NimBLERemoteCharacteristic::setNotify(uint16_t val, notify_callback notifyC
|
||||
* @param [in] notifyCallback A callback to be invoked for a notification.
|
||||
* @param [in] response If true, require a write response from the descriptor write operation.
|
||||
* If NULL is provided then no callback is performed.
|
||||
* @return true if successful.
|
||||
* @return false if writing to the descriptor failed.
|
||||
*/
|
||||
bool NimBLERemoteCharacteristic::subscribe(bool notifications, notify_callback notifyCallback, bool response) {
|
||||
if(notifications) {
|
||||
@@ -545,7 +626,7 @@ bool NimBLERemoteCharacteristic::subscribe(bool notifications, notify_callback n
|
||||
/**
|
||||
* @brief Unsubscribe for notifications or indications.
|
||||
* @param [in] response bool if true, require a write response from the descriptor write operation.
|
||||
* @return true if successful.
|
||||
* @return false if writing to the descriptor failed.
|
||||
*/
|
||||
bool NimBLERemoteCharacteristic::unsubscribe(bool response) {
|
||||
return setNotify(0x00, nullptr, response);
|
||||
@@ -644,7 +725,7 @@ std::string NimBLERemoteCharacteristic::toString() {
|
||||
* @return false if not connected or cant perform write for some reason.
|
||||
*/
|
||||
bool NimBLERemoteCharacteristic::writeValue(const std::string &newValue, bool response) {
|
||||
return writeValue((uint8_t*)newValue.c_str(), strlen(newValue.c_str()), response);
|
||||
return writeValue((uint8_t*)newValue.c_str(), newValue.length(), response);
|
||||
} // writeValue
|
||||
|
||||
|
||||
@@ -677,7 +758,8 @@ bool NimBLERemoteCharacteristic::writeValue(const uint8_t* data, size_t length,
|
||||
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 {
|
||||
if(length > mtu) {
|
||||
@@ -697,6 +779,10 @@ bool NimBLERemoteCharacteristic::writeValue(const uint8_t* data, size_t length,
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef ulTaskNotifyValueClear
|
||||
// Clear the task notification value to ensure we block
|
||||
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
|
||||
#endif
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
rc = taskData.rc;
|
||||
|
||||
@@ -751,6 +837,4 @@ int NimBLERemoteCharacteristic::onWriteCB(uint16_t conn_handle,
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#endif // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|
||||
|
||||
@@ -14,11 +14,9 @@
|
||||
|
||||
#ifndef COMPONENTS_NIMBLEREMOTECHARACTERISTIC_H_
|
||||
#define COMPONENTS_NIMBLEREMOTECHARACTERISTIC_H_
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#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 "NimBLERemoteDescriptor.h"
|
||||
@@ -148,22 +146,23 @@ private:
|
||||
static int descriptorDiscCB(uint16_t conn_handle, const struct ble_gatt_error *error,
|
||||
uint16_t chr_val_handle, const struct ble_gatt_dsc *dsc,
|
||||
void *arg);
|
||||
static int nextCharCB(uint16_t conn_handle, const struct ble_gatt_error *error,
|
||||
const struct ble_gatt_chr *chr, void *arg);
|
||||
|
||||
// Private properties
|
||||
NimBLEUUID m_uuid;
|
||||
uint8_t m_charProp;
|
||||
uint16_t m_handle;
|
||||
uint16_t m_defHandle;
|
||||
uint16_t m_endHandle;
|
||||
NimBLERemoteService* m_pRemoteService;
|
||||
std::string m_value;
|
||||
notify_callback m_notifyCallback;
|
||||
time_t m_timestamp;
|
||||
portMUX_TYPE m_valMux;
|
||||
|
||||
// We maintain a vector of descriptors owned by this characteristic.
|
||||
std::vector<NimBLERemoteDescriptor*> m_descriptorVector;
|
||||
}; // NimBLERemoteCharacteristic
|
||||
|
||||
#endif // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|
||||
#endif /* COMPONENTS_NIMBLEREMOTECHARACTERISTIC_H_ */
|
||||
|
||||
@@ -11,16 +11,16 @@
|
||||
* Created on: Jul 8, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#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 "NimBLEUtils.h"
|
||||
#include "NimBLELog.h"
|
||||
|
||||
#include <climits>
|
||||
|
||||
static const char* LOG_TAG = "NimBLERemoteDescriptor";
|
||||
|
||||
/**
|
||||
@@ -31,6 +31,7 @@ static const char* LOG_TAG = "NimBLERemoteDescriptor";
|
||||
NimBLERemoteDescriptor::NimBLERemoteDescriptor(NimBLERemoteCharacteristic* pRemoteCharacteristic,
|
||||
const struct ble_gatt_dsc *dsc)
|
||||
{
|
||||
NIMBLE_LOGD(LOG_TAG, ">> NimBLERemoteDescriptor()");
|
||||
switch (dsc->uuid.u.type) {
|
||||
case BLE_UUID_TYPE_16:
|
||||
m_uuid = NimBLEUUID(dsc->uuid.u16.value);
|
||||
@@ -42,12 +43,13 @@ NimBLERemoteDescriptor::NimBLERemoteDescriptor(NimBLERemoteCharacteristic* pRemo
|
||||
m_uuid = NimBLEUUID(const_cast<ble_uuid128_t*>(&dsc->uuid.u128));
|
||||
break;
|
||||
default:
|
||||
m_uuid = nullptr;
|
||||
break;
|
||||
}
|
||||
|
||||
m_handle = dsc->handle;
|
||||
m_pRemoteCharacteristic = pRemoteCharacteristic;
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< NimBLERemoteDescriptor(): %s", m_uuid.toString().c_str());
|
||||
}
|
||||
|
||||
|
||||
@@ -137,7 +139,8 @@ std::string NimBLERemoteDescriptor::readValue() {
|
||||
|
||||
int rc = 0;
|
||||
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 {
|
||||
rc = ble_gattc_read_long(pClient->getConnId(), m_handle, 0,
|
||||
@@ -149,6 +152,10 @@ std::string NimBLERemoteDescriptor::readValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
#ifdef ulTaskNotifyValueClear
|
||||
// Clear the task notification value to ensure we block
|
||||
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
|
||||
#endif
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
rc = taskData.rc;
|
||||
|
||||
@@ -186,6 +193,7 @@ int NimBLERemoteDescriptor::onReadCB(uint16_t conn_handle,
|
||||
const struct ble_gatt_error *error,
|
||||
struct ble_gatt_attr *attr, void *arg)
|
||||
{
|
||||
(void)attr;
|
||||
ble_task_data_t *pTaskData = (ble_task_data_t*)arg;
|
||||
NimBLERemoteDescriptor* desc = (NimBLERemoteDescriptor*)pTaskData->pATT;
|
||||
uint16_t conn_id = desc->getRemoteCharacteristic()->getRemoteService()->getClient()->getConnId();
|
||||
@@ -201,11 +209,12 @@ int NimBLERemoteDescriptor::onReadCB(uint16_t conn_handle,
|
||||
|
||||
if(rc == 0) {
|
||||
if(attr) {
|
||||
if(((*strBuf).length() + attr->om->om_len) > BLE_ATT_ATTR_MAX_LEN) {
|
||||
uint32_t data_len = OS_MBUF_PKTLEN(attr->om);
|
||||
if(((*strBuf).length() + data_len) > BLE_ATT_ATTR_MAX_LEN) {
|
||||
rc = BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||
} else {
|
||||
NIMBLE_LOGD(LOG_TAG, "Got %d bytes", attr->om->om_len);
|
||||
(*strBuf) += std::string((char*) attr->om->om_data, attr->om->om_len);
|
||||
NIMBLE_LOGD(LOG_TAG, "Got %d bytes", data_len);
|
||||
(*strBuf) += std::string((char*) attr->om->om_data, data_len);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -287,7 +296,8 @@ bool NimBLERemoteDescriptor::writeValue(const uint8_t* data, size_t length, bool
|
||||
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 {
|
||||
if(length > mtu) {
|
||||
@@ -308,6 +318,10 @@ bool NimBLERemoteDescriptor::writeValue(const uint8_t* data, size_t length, bool
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef ulTaskNotifyValueClear
|
||||
// Clear the task notification value to ensure we block
|
||||
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
|
||||
#endif
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
rc = taskData.rc;
|
||||
|
||||
@@ -348,5 +362,4 @@ bool NimBLERemoteDescriptor::writeValue(const std::string &newValue, bool respon
|
||||
return writeValue((uint8_t*) newValue.data(), newValue.length(), response);
|
||||
} // writeValue
|
||||
|
||||
#endif // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|
||||
|
||||
@@ -14,11 +14,9 @@
|
||||
|
||||
#ifndef COMPONENTS_NIMBLEREMOTEDESCRIPTOR_H_
|
||||
#define COMPONENTS_NIMBLEREMOTEDESCRIPTOR_H_
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
|
||||
#include "NimBLERemoteCharacteristic.h"
|
||||
|
||||
@@ -81,6 +79,5 @@ private:
|
||||
NimBLERemoteCharacteristic* m_pRemoteCharacteristic;
|
||||
};
|
||||
|
||||
#endif // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|
||||
#endif /* COMPONENTS_NIMBLEREMOTEDESCRIPTOR_H_ */
|
||||
|
||||
@@ -11,17 +11,17 @@
|
||||
* Created on: Jul 8, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#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 "NimBLEUtils.h"
|
||||
#include "NimBLEDevice.h"
|
||||
#include "NimBLELog.h"
|
||||
|
||||
#include <climits>
|
||||
|
||||
static const char* LOG_TAG = "NimBLERemoteService";
|
||||
|
||||
/**
|
||||
@@ -44,12 +44,11 @@ NimBLERemoteService::NimBLERemoteService(NimBLEClient* pClient, const struct ble
|
||||
m_uuid = NimBLEUUID(const_cast<ble_uuid128_t*>(&service->uuid.u128));
|
||||
break;
|
||||
default:
|
||||
m_uuid = nullptr;
|
||||
break;
|
||||
}
|
||||
m_startHandle = service->start_handle;
|
||||
m_endHandle = service->end_handle;
|
||||
NIMBLE_LOGD(LOG_TAG, "<< NimBLERemoteService()");
|
||||
NIMBLE_LOGD(LOG_TAG, "<< NimBLERemoteService(): %s", m_uuid.toString().c_str());
|
||||
}
|
||||
|
||||
|
||||
@@ -95,8 +94,11 @@ NimBLERemoteCharacteristic* NimBLERemoteService::getCharacteristic(const char* u
|
||||
* @return A pointer to the characteristic object, or nullptr if not found.
|
||||
*/
|
||||
NimBLERemoteCharacteristic* NimBLERemoteService::getCharacteristic(const NimBLEUUID &uuid) {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> getCharacteristic: uuid: %s", uuid.toString().c_str());
|
||||
|
||||
for(auto &it: m_characteristicVector) {
|
||||
if(it->getUUID() == uuid) {
|
||||
NIMBLE_LOGD(LOG_TAG, "<< getCharacteristic: found the characteristic with uuid: %s", uuid.toString().c_str());
|
||||
return it;
|
||||
}
|
||||
}
|
||||
@@ -106,8 +108,19 @@ NimBLERemoteCharacteristic* NimBLERemoteService::getCharacteristic(const NimBLEU
|
||||
if(m_characteristicVector.size() > prev_size) {
|
||||
return m_characteristicVector.back();
|
||||
}
|
||||
|
||||
// If the request was successful but 16/32 bit characteristic not found
|
||||
// try again with the 128 bit uuid.
|
||||
if(uuid.bitSize() == BLE_UUID_TYPE_16 ||
|
||||
uuid.bitSize() == BLE_UUID_TYPE_32)
|
||||
{
|
||||
NimBLEUUID uuid128(uuid);
|
||||
uuid128.to128();
|
||||
return getCharacteristic(uuid128);
|
||||
}
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< getCharacteristic: not found");
|
||||
return nullptr;
|
||||
} // getCharacteristic
|
||||
|
||||
@@ -185,7 +198,8 @@ bool NimBLERemoteService::retrieveCharacteristics(const NimBLEUUID *uuid_filter)
|
||||
NIMBLE_LOGD(LOG_TAG, ">> retrieveCharacteristics() for service: %s", getUUID().toString().c_str());
|
||||
|
||||
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) {
|
||||
rc = ble_gattc_disc_all_chrs(m_pClient->getConnId(),
|
||||
@@ -207,9 +221,27 @@ bool NimBLERemoteService::retrieveCharacteristics(const NimBLEUUID *uuid_filter)
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef ulTaskNotifyValueClear
|
||||
// Clear the task notification value to ensure we block
|
||||
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
|
||||
#endif
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
|
||||
if(taskData.rc == 0){
|
||||
if (uuid_filter == nullptr) {
|
||||
if (m_characteristicVector.size() > 1) {
|
||||
for (auto it = m_characteristicVector.begin(); it != m_characteristicVector.end(); ++it ) {
|
||||
auto nx = std::next(it, 1);
|
||||
if (nx == m_characteristicVector.end()) {
|
||||
break;
|
||||
}
|
||||
(*it)->m_endHandle = (*nx)->m_defHandle - 1;
|
||||
}
|
||||
}
|
||||
|
||||
m_characteristicVector.back()->m_endHandle = getEndHandle();
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< retrieveCharacteristics()");
|
||||
return true;
|
||||
}
|
||||
@@ -359,6 +391,4 @@ std::string NimBLERemoteService::toString() {
|
||||
return res;
|
||||
} // toString
|
||||
|
||||
|
||||
#endif // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|
||||
|
||||
@@ -14,11 +14,9 @@
|
||||
|
||||
#ifndef COMPONENTS_NIMBLEREMOTESERVICE_H_
|
||||
#define COMPONENTS_NIMBLEREMOTESERVICE_H_
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#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 "NimBLEUUID.h"
|
||||
@@ -83,6 +81,5 @@ private:
|
||||
uint16_t m_endHandle;
|
||||
}; // NimBLERemoteService
|
||||
|
||||
#endif // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|
||||
#endif /* COMPONENTS_NIMBLEREMOTESERVICE_H_ */
|
||||
|
||||
@@ -11,17 +11,16 @@
|
||||
* Created on: Jul 1, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#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 "NimBLEDevice.h"
|
||||
#include "NimBLELog.h"
|
||||
|
||||
#include <string>
|
||||
#include <climits>
|
||||
|
||||
static const char* LOG_TAG = "NimBLEScan";
|
||||
|
||||
@@ -30,7 +29,6 @@ static const char* LOG_TAG = "NimBLEScan";
|
||||
* @brief Scan constuctor.
|
||||
*/
|
||||
NimBLEScan::NimBLEScan() {
|
||||
m_own_addr_type = 0;
|
||||
m_scan_params.filter_policy = BLE_HCI_SCAN_FILT_NO_WL;
|
||||
m_scan_params.passive = 1; // If set, don’t send scan requests to advertisers (i.e., don’t request additional advertising data).
|
||||
m_scan_params.itvl = 0; // This is defined as the time interval from when the Controller started its last LE scan until it begins the subsequent LE scan. (units=0.625 msec)
|
||||
@@ -38,9 +36,10 @@ NimBLEScan::NimBLEScan() {
|
||||
m_scan_params.limited = 0; // If set, only discover devices in limited discoverable mode.
|
||||
m_scan_params.filter_duplicates = 0; // If set, the controller ignores all but the first advertisement from each device.
|
||||
m_pAdvertisedDeviceCallbacks = nullptr;
|
||||
m_stopped = true;
|
||||
m_wantDuplicates = false;
|
||||
m_ignoreResults = false;
|
||||
m_pTaskData = nullptr;
|
||||
m_duration = BLE_HS_FOREVER; // make sure this is non-zero in the event of a host reset
|
||||
m_maxResults = 0xFF;
|
||||
}
|
||||
|
||||
|
||||
@@ -63,8 +62,8 @@ NimBLEScan::~NimBLEScan() {
|
||||
switch(event->type) {
|
||||
|
||||
case BLE_GAP_EVENT_DISC: {
|
||||
if(pScan->m_stopped) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Scan stop called, ignoring results.");
|
||||
if(pScan->m_ignoreResults) {
|
||||
NIMBLE_LOGI(LOG_TAG, "Scan op in progress - ignoring results");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -88,34 +87,49 @@ NimBLEScan::~NimBLEScan() {
|
||||
|
||||
// If we haven't seen this device before; create a new instance and insert it in the vector.
|
||||
// Otherwise just update the relevant parameters of the already known device.
|
||||
if(advertisedDevice == nullptr){
|
||||
if(advertisedDevice == nullptr && event->disc.event_type != BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP){
|
||||
// Check if we have reach the scan results limit, ignore this one if so.
|
||||
// We still need to store each device when maxResults is 0 to be able to append the scan results
|
||||
if(pScan->m_maxResults > 0 && pScan->m_maxResults < 0xFF &&
|
||||
(pScan->m_scanResults.m_advertisedDevicesVector.size() >= pScan->m_maxResults))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
advertisedDevice = new NimBLEAdvertisedDevice();
|
||||
advertisedDevice->setAddress(advertisedAddress);
|
||||
advertisedDevice->setAdvType(event->disc.event_type);
|
||||
pScan->m_scanResults.m_advertisedDevicesVector.push_back(advertisedDevice);
|
||||
NIMBLE_LOGI(LOG_TAG, "NEW DEVICE FOUND: %s", advertisedAddress.toString().c_str());
|
||||
}
|
||||
else{
|
||||
NIMBLE_LOGI(LOG_TAG, "UPDATING PREVIOUSLY FOUND DEVICE: %s", advertisedAddress.toString().c_str());
|
||||
}
|
||||
advertisedDevice->setRSSI(event->disc.rssi);
|
||||
if(event->disc.length_data > 0) {
|
||||
advertisedDevice->parseAdvertisement(event->disc.data, event->disc.length_data);
|
||||
NIMBLE_LOGI(LOG_TAG, "New advertiser: %s", advertisedAddress.toString().c_str());
|
||||
} else if(advertisedDevice != nullptr) {
|
||||
NIMBLE_LOGI(LOG_TAG, "Updated advertiser: %s", advertisedAddress.toString().c_str());
|
||||
} else {
|
||||
// Scan response from unknown device
|
||||
return 0;
|
||||
}
|
||||
|
||||
advertisedDevice->m_timestamp = time(nullptr);
|
||||
advertisedDevice->setRSSI(event->disc.rssi);
|
||||
advertisedDevice->setPayload(event->disc.data, event->disc.length_data,
|
||||
event->disc.event_type == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP);
|
||||
|
||||
if (pScan->m_pAdvertisedDeviceCallbacks) {
|
||||
if(pScan->m_wantDuplicates || !advertisedDevice->m_callbackSent) {
|
||||
// If not active scanning report the result to the listener.
|
||||
if(pScan->m_scan_params.passive || event->disc.event_type == BLE_HCI_ADV_TYPE_ADV_NONCONN_IND) {
|
||||
advertisedDevice->m_callbackSent = true;
|
||||
pScan->m_pAdvertisedDeviceCallbacks->onResult(advertisedDevice);
|
||||
// If not active scanning or scan response is not available
|
||||
// report the result to the callback now.
|
||||
if(pScan->m_scan_params.passive ||
|
||||
(advertisedDevice->getAdvType() != BLE_HCI_ADV_TYPE_ADV_IND &&
|
||||
advertisedDevice->getAdvType() != BLE_HCI_ADV_TYPE_ADV_SCAN_IND))
|
||||
{
|
||||
advertisedDevice->m_callbackSent = true;
|
||||
pScan->m_pAdvertisedDeviceCallbacks->onResult(advertisedDevice);
|
||||
|
||||
// Otherwise wait for the scan response so we can report all of the data at once.
|
||||
} else if (event->disc.event_type == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP) {
|
||||
advertisedDevice->m_callbackSent = true;
|
||||
pScan->m_pAdvertisedDeviceCallbacks->onResult(advertisedDevice);
|
||||
}
|
||||
// Otherwise, wait for the scan response so we can report the complete data.
|
||||
} else if (event->disc.event_type == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP) {
|
||||
advertisedDevice->m_callbackSent = true;
|
||||
pScan->m_pAdvertisedDeviceCallbacks->onResult(advertisedDevice);
|
||||
}
|
||||
// If not storing results and we have invoked the callback, delete the device.
|
||||
if(pScan->m_maxResults == 0 && advertisedDevice->m_callbackSent) {
|
||||
pScan->erase(advertisedAddress);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,13 +137,26 @@ NimBLEScan::~NimBLEScan() {
|
||||
}
|
||||
case BLE_GAP_EVENT_DISC_COMPLETE: {
|
||||
NIMBLE_LOGD(LOG_TAG, "discovery complete; reason=%d",
|
||||
event->disc_complete.reason);
|
||||
event->disc_complete.reason);
|
||||
|
||||
// If a device advertised with scan reponse available and it was not received
|
||||
// the callback would not have been invoked, so do it here.
|
||||
if(pScan->m_pAdvertisedDeviceCallbacks) {
|
||||
for(auto &it : pScan->m_scanResults.m_advertisedDevicesVector) {
|
||||
if(!it->m_callbackSent) {
|
||||
pScan->m_pAdvertisedDeviceCallbacks->onResult(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(pScan->m_maxResults == 0) {
|
||||
pScan->clearResults();
|
||||
}
|
||||
|
||||
if (pScan->m_scanCompleteCB != nullptr) {
|
||||
pScan->m_scanCompleteCB(pScan->m_scanResults);
|
||||
}
|
||||
|
||||
pScan->m_stopped = true;
|
||||
if(pScan->m_pTaskData != nullptr) {
|
||||
pScan->m_pTaskData->rc = event->disc_complete.reason;
|
||||
xTaskNotifyGive(pScan->m_pTaskData->task);
|
||||
@@ -146,15 +173,11 @@ NimBLEScan::~NimBLEScan() {
|
||||
|
||||
/**
|
||||
* @brief Should we perform an active or passive scan?
|
||||
* The default is a passive scan. An active scan means that we will wish a scan response.
|
||||
* The default is a passive scan. An active scan means that we will request a scan response.
|
||||
* @param [in] active If true, we perform an active scan otherwise a passive scan.
|
||||
*/
|
||||
void NimBLEScan::setActiveScan(bool active) {
|
||||
if (active) {
|
||||
m_scan_params.passive = 0;
|
||||
} else {
|
||||
m_scan_params.passive = 1;
|
||||
}
|
||||
m_scan_params.passive = !active;
|
||||
} // setActiveScan
|
||||
|
||||
|
||||
@@ -203,6 +226,16 @@ void NimBLEScan::setFilterPolicy(uint8_t filter) {
|
||||
} // setFilterPolicy
|
||||
|
||||
|
||||
/**
|
||||
* @brief Sets the max number of results to store.
|
||||
* @param [in] maxResults The number of results to limit storage to\n
|
||||
* 0 == none (callbacks only) 0xFF == unlimited, any other value is the limit.
|
||||
*/
|
||||
void NimBLEScan::setMaxResults(uint8_t maxResults) {
|
||||
m_maxResults = maxResults;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the call backs to be invoked.
|
||||
* @param [in] pAdvertisedDeviceCallbacks Call backs to be invoked.
|
||||
@@ -210,7 +243,7 @@ void NimBLEScan::setFilterPolicy(uint8_t filter) {
|
||||
*/
|
||||
void NimBLEScan::setAdvertisedDeviceCallbacks(NimBLEAdvertisedDeviceCallbacks* pAdvertisedDeviceCallbacks,
|
||||
bool wantDuplicates) {
|
||||
m_wantDuplicates = wantDuplicates;
|
||||
setDuplicateFilter(!wantDuplicates);
|
||||
m_pAdvertisedDeviceCallbacks = pAdvertisedDeviceCallbacks;
|
||||
} // setAdvertisedDeviceCallbacks
|
||||
|
||||
@@ -238,7 +271,7 @@ void NimBLEScan::setWindow(uint16_t windowMSecs) {
|
||||
* @return true if scanning or scan starting.
|
||||
*/
|
||||
bool NimBLEScan::isScanning() {
|
||||
return !m_stopped;
|
||||
return ble_gap_disc_active();
|
||||
}
|
||||
|
||||
|
||||
@@ -252,25 +285,6 @@ bool NimBLEScan::isScanning() {
|
||||
bool NimBLEScan::start(uint32_t duration, void (*scanCompleteCB)(NimBLEScanResults), bool is_continue) {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> start(duration=%d)", duration);
|
||||
|
||||
// If Host is not synced we cannot start scanning.
|
||||
if(!NimBLEDevice::m_synced) {
|
||||
NIMBLE_LOGC(LOG_TAG, "Host reset, wait for sync.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(ble_gap_conn_active()) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Connection in progress - must wait.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we are already scanning don't start again or we will get stuck on the semaphore.
|
||||
if(!m_stopped || ble_gap_disc_active()) { // double check - can cause host reset.
|
||||
NIMBLE_LOGE(LOG_TAG, "Scan already in progress");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_stopped = false;
|
||||
|
||||
// Save the callback to be invoked when the scan completes.
|
||||
m_scanCompleteCB = scanCompleteCB;
|
||||
// Save the duration in the case that the host is reset so we can reuse it.
|
||||
@@ -281,32 +295,53 @@ bool NimBLEScan::start(uint32_t duration, void (*scanCompleteCB)(NimBLEScanResul
|
||||
duration = BLE_HS_FOREVER;
|
||||
}
|
||||
else{
|
||||
duration = duration*1000; // convert duration to milliseconds
|
||||
// convert duration to milliseconds
|
||||
duration = duration * 1000;
|
||||
}
|
||||
|
||||
// if we are connecting to devices that are advertising even after being connected, multiconnecting peripherals
|
||||
// then we should not clear vector or we will connect the same device few times
|
||||
// Set the flag to ignore the results while we are deleting the vector
|
||||
if(!is_continue) {
|
||||
clearResults();
|
||||
m_ignoreResults = true;
|
||||
}
|
||||
|
||||
int rc = 0;
|
||||
do{
|
||||
rc = ble_gap_disc(m_own_addr_type, duration, &m_scan_params,
|
||||
NimBLEScan::handleGapEvent, this);
|
||||
if(rc == BLE_HS_EBUSY) {
|
||||
vTaskDelay(1 / portTICK_PERIOD_MS);
|
||||
}
|
||||
} while(rc == BLE_HS_EBUSY);
|
||||
int rc = ble_gap_disc(NimBLEDevice::m_own_addr_type, duration, &m_scan_params,
|
||||
NimBLEScan::handleGapEvent, this);
|
||||
|
||||
if (rc != 0 && rc != BLE_HS_EDONE) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Error initiating GAP discovery procedure; rc=%d, %s",
|
||||
rc, NimBLEUtils::returnCodeToString(rc));
|
||||
m_stopped = true;
|
||||
switch(rc) {
|
||||
case 0:
|
||||
if(!is_continue) {
|
||||
clearResults();
|
||||
}
|
||||
break;
|
||||
|
||||
case BLE_HS_EALREADY:
|
||||
// Clear the cache if already scanning in case an advertiser was missed.
|
||||
clearDuplicateCache();
|
||||
break;
|
||||
|
||||
case BLE_HS_EBUSY:
|
||||
NIMBLE_LOGE(LOG_TAG, "Unable to scan - connection in progress.");
|
||||
break;
|
||||
|
||||
case BLE_HS_ETIMEOUT_HCI:
|
||||
case BLE_HS_EOS:
|
||||
case BLE_HS_ECONTROLLER:
|
||||
case BLE_HS_ENOTSYNCED:
|
||||
NIMBLE_LOGC(LOG_TAG, "Unable to scan - Host Reset");
|
||||
break;
|
||||
|
||||
default:
|
||||
NIMBLE_LOGE(LOG_TAG, "Error initiating GAP discovery procedure; rc=%d, %s",
|
||||
rc, NimBLEUtils::returnCodeToString(rc));
|
||||
break;
|
||||
}
|
||||
|
||||
m_ignoreResults = false;
|
||||
NIMBLE_LOGD(LOG_TAG, "<< start()");
|
||||
|
||||
if(rc != 0 && rc != BLE_HS_EALREADY) {
|
||||
return false;
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< start()");
|
||||
return true;
|
||||
} // start
|
||||
|
||||
@@ -322,10 +357,15 @@ NimBLEScanResults NimBLEScan::start(uint32_t duration, bool is_continue) {
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -343,11 +383,13 @@ bool NimBLEScan::stop() {
|
||||
|
||||
int rc = ble_gap_disc_cancel();
|
||||
if (rc != 0 && rc != BLE_HS_EALREADY) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Failed to cancel scan; rc=%d\n", rc);
|
||||
NIMBLE_LOGE(LOG_TAG, "Failed to cancel scan; rc=%d", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_stopped = true;
|
||||
if(m_maxResults == 0) {
|
||||
clearResults();
|
||||
}
|
||||
|
||||
if (rc != BLE_HS_EALREADY && m_scanCompleteCB != nullptr) {
|
||||
m_scanCompleteCB(m_scanResults);
|
||||
@@ -362,13 +404,23 @@ bool NimBLEScan::stop() {
|
||||
} // stop
|
||||
|
||||
|
||||
/**
|
||||
* @brief Clears the duplicate scan filter cache.
|
||||
*/
|
||||
void NimBLEScan::clearDuplicateCache() {
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32 // Not available for ESP32C3
|
||||
esp_ble_scan_dupilcate_list_flush();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Delete peer device from the scan results vector.
|
||||
* @param [in] address The address of the device to delete from the results.
|
||||
* @details After disconnecting, it may be required in the case we were connected to a device without a public address.
|
||||
*/
|
||||
void NimBLEScan::erase(const NimBLEAddress &address) {
|
||||
NIMBLE_LOGI(LOG_TAG, "erase device: %s", address.toString().c_str());
|
||||
NIMBLE_LOGD(LOG_TAG, "erase device: %s", address.toString().c_str());
|
||||
|
||||
for(auto it = m_scanResults.m_advertisedDevicesVector.begin(); it != m_scanResults.m_advertisedDevicesVector.end(); ++it) {
|
||||
if((*it)->getAddress() == address) {
|
||||
@@ -381,13 +433,25 @@ void NimBLEScan::erase(const NimBLEAddress &address) {
|
||||
|
||||
|
||||
/**
|
||||
* @brief If the host reset the scan will have stopped so we should set the flag as stopped.
|
||||
* @brief Called when host reset, we set a flag to stop scanning until synced.
|
||||
*/
|
||||
void NimBLEScan::onHostReset() {
|
||||
m_stopped = true;
|
||||
m_ignoreResults = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief If the host reset and re-synced this is called.
|
||||
* If the application was scanning indefinitely with a callback, restart it.
|
||||
*/
|
||||
void NimBLEScan::onHostSync() {
|
||||
m_ignoreResults = false;
|
||||
|
||||
if(m_duration == 0 && m_pAdvertisedDeviceCallbacks != nullptr) {
|
||||
start(m_duration, m_scanCompleteCB);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the results of the scan.
|
||||
* @return NimBLEScanResults object.
|
||||
@@ -405,6 +469,7 @@ void NimBLEScan::clearResults() {
|
||||
delete it;
|
||||
}
|
||||
m_scanResults.m_advertisedDevicesVector.clear();
|
||||
clearDuplicateCache();
|
||||
}
|
||||
|
||||
|
||||
@@ -473,5 +538,4 @@ NimBLEAdvertisedDevice *NimBLEScanResults::getDevice(const NimBLEAddress &addres
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_OBSERVER */
|
||||
|
||||
@@ -13,16 +13,18 @@
|
||||
*/
|
||||
#ifndef COMPONENTS_NIMBLE_SCAN_H_
|
||||
#define COMPONENTS_NIMBLE_SCAN_H_
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#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 "NimBLEUtils.h"
|
||||
|
||||
#if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
#include "host/ble_gap.h"
|
||||
#else
|
||||
#include "nimble/nimble/host/include/host/ble_gap.h"
|
||||
#endif
|
||||
|
||||
#include <vector>
|
||||
|
||||
@@ -70,9 +72,11 @@ public:
|
||||
void setDuplicateFilter(bool enabled);
|
||||
void setLimitedOnly(bool enabled);
|
||||
void setFilterPolicy(uint8_t filter);
|
||||
void clearDuplicateCache();
|
||||
bool stop();
|
||||
void clearResults();
|
||||
NimBLEScanResults getResults();
|
||||
void setMaxResults(uint8_t maxResults);
|
||||
void erase(const NimBLEAddress &address);
|
||||
|
||||
|
||||
@@ -83,18 +87,17 @@ private:
|
||||
~NimBLEScan();
|
||||
static int handleGapEvent(ble_gap_event* event, void* arg);
|
||||
void onHostReset();
|
||||
void onHostSync();
|
||||
|
||||
NimBLEAdvertisedDeviceCallbacks* m_pAdvertisedDeviceCallbacks = nullptr;
|
||||
void (*m_scanCompleteCB)(NimBLEScanResults scanResults);
|
||||
ble_gap_disc_params m_scan_params;
|
||||
uint8_t m_own_addr_type;
|
||||
bool m_stopped;
|
||||
bool m_wantDuplicates;
|
||||
bool m_ignoreResults;
|
||||
NimBLEScanResults m_scanResults;
|
||||
uint32_t m_duration;
|
||||
ble_task_data_t *m_pTaskData;
|
||||
uint8_t m_maxResults;
|
||||
};
|
||||
|
||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
#endif /* CONFIG_BT_ENABLED CONFIG_BT_NIMBLE_ROLE_OBSERVER */
|
||||
#endif /* COMPONENTS_NIMBLE_SCAN_H_ */
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
* Author: chegewara
|
||||
*/
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include "NimBLESecurity.h"
|
||||
|
||||
@@ -14,10 +14,16 @@
|
||||
|
||||
#ifndef COMPONENTS_NIMBLESECURITY_H_
|
||||
#define COMPONENTS_NIMBLESECURITY_H_
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
#include "host/ble_gap.h"
|
||||
#else
|
||||
#include "nimble/nimble/host/include/host/ble_gap.h"
|
||||
#endif
|
||||
|
||||
/**** FIX COMPILATION ****/
|
||||
#undef min
|
||||
#undef max
|
||||
|
||||
@@ -12,19 +12,20 @@
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#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 "NimBLEDevice.h"
|
||||
#include "NimBLELog.h"
|
||||
|
||||
#if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
#include "services/gap/ble_svc_gap.h"
|
||||
#include "services/gatt/ble_svc_gatt.h"
|
||||
|
||||
#else
|
||||
#include "nimble/nimble/host/services/gap/include/services/gap/ble_svc_gap.h"
|
||||
#include "nimble/nimble/host/services/gatt/include/services/gatt/ble_svc_gatt.h"
|
||||
#endif
|
||||
|
||||
static const char* LOG_TAG = "NimBLEServer";
|
||||
static NimBLEServerCallbacks defaultCallbacks;
|
||||
@@ -37,6 +38,7 @@ static NimBLEServerCallbacks defaultCallbacks;
|
||||
* the NimBLEDevice class.
|
||||
*/
|
||||
NimBLEServer::NimBLEServer() {
|
||||
memset(m_indWait, BLE_HS_CONN_HANDLE_NONE, sizeof(m_indWait));
|
||||
// m_svcChgChrHdl = 0xffff; // Future Use
|
||||
m_pServerCallbacks = &defaultCallbacks;
|
||||
m_gattsStarted = false;
|
||||
@@ -78,24 +80,18 @@ NimBLEService* NimBLEServer::createService(const char* uuid) {
|
||||
* to provide inst_id value different for each service.
|
||||
* @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());
|
||||
// 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.
|
||||
if(getServiceByUUID(uuid) != nullptr) {
|
||||
NIMBLE_LOGW(LOG_TAG, "Warning creating a duplicate service UUID: %s",
|
||||
std::string(uuid).c_str());
|
||||
}
|
||||
|
||||
NimBLEService* pService = new NimBLEService(uuid, numHandles, this);
|
||||
m_svcVec.push_back(pService); // Save a reference to this service being on this server.
|
||||
|
||||
if(m_gattsStarted) {
|
||||
ble_svc_gatt_changed(0x0001, 0xffff);
|
||||
m_svcChanged = true;
|
||||
resetGATT();
|
||||
}
|
||||
NimBLEService* pService = new NimBLEService(uuid);
|
||||
m_svcVec.push_back(pService);
|
||||
serviceChanged();
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< createService");
|
||||
return pService;
|
||||
@@ -104,28 +100,47 @@ NimBLEService* NimBLEServer::createService(const NimBLEUUID &uuid, uint32_t numH
|
||||
|
||||
/**
|
||||
* @brief Get a %BLE Service by its UUID
|
||||
* @param [in] uuid The UUID of the new service.
|
||||
* @return A reference to the service object.
|
||||
* @param [in] uuid The UUID of the service.
|
||||
* @param instanceId The index of the service to return (used when multiple services have the same UUID).
|
||||
* @return A pointer to the service object or nullptr if not found.
|
||||
*/
|
||||
NimBLEService* NimBLEServer::getServiceByUUID(const char* uuid) {
|
||||
return getServiceByUUID(NimBLEUUID(uuid));
|
||||
NimBLEService* NimBLEServer::getServiceByUUID(const char* uuid, uint16_t instanceId) {
|
||||
return getServiceByUUID(NimBLEUUID(uuid), instanceId);
|
||||
} // getServiceByUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get a %BLE Service by its UUID
|
||||
* @param [in] uuid The UUID of the new service.
|
||||
* @return A reference to the service object.
|
||||
* @param [in] uuid The UUID of the service.
|
||||
* @param instanceId The index of the service to return (used when multiple services have the same UUID).
|
||||
* @return A pointer to the service object or nullptr if not found.
|
||||
*/
|
||||
NimBLEService* NimBLEServer::getServiceByUUID(const NimBLEUUID &uuid) {
|
||||
NimBLEService* NimBLEServer::getServiceByUUID(const NimBLEUUID &uuid, uint16_t instanceId) {
|
||||
uint16_t position = 0;
|
||||
for (auto &it : m_svcVec) {
|
||||
if (it->getUUID() == uuid) {
|
||||
return it;
|
||||
if (position == instanceId){
|
||||
return it;
|
||||
}
|
||||
position++;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
} // getServiceByUUID
|
||||
|
||||
/**
|
||||
* @brief Get a %BLE Service by its handle
|
||||
* @param handle The handle of the service.
|
||||
* @return A pointer to the service object or nullptr if not found.
|
||||
*/
|
||||
NimBLEService *NimBLEServer::getServiceByHandle(uint16_t handle) {
|
||||
for (auto &it : m_svcVec) {
|
||||
if (it->getHandle() == handle) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Retrieve the advertising object that can be used to advertise the existence of the server.
|
||||
@@ -137,6 +152,18 @@ NimBLEAdvertising* NimBLEServer::getAdvertising() {
|
||||
} // getAdvertising
|
||||
|
||||
|
||||
/**
|
||||
* @brief Sends a service changed notification and resets the GATT server.
|
||||
*/
|
||||
void NimBLEServer::serviceChanged() {
|
||||
if(m_gattsStarted) {
|
||||
m_svcChanged = true;
|
||||
ble_svc_gatt_changed(0x0001, 0xffff);
|
||||
resetGATT();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Start the GATT server. Required to be called after setup of all
|
||||
* services and characteristics / descriptors for the NimBLE host to register them.
|
||||
@@ -154,7 +181,7 @@ void NimBLEServer::start() {
|
||||
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();
|
||||
#endif
|
||||
/*** Future use ***
|
||||
@@ -234,6 +261,63 @@ size_t NimBLEServer::getConnectedCount() {
|
||||
} // getConnectedCount
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the vector of the connected client ID's.
|
||||
*/
|
||||
std::vector<uint16_t> NimBLEServer::getPeerDevices() {
|
||||
return m_connectedPeersVec;
|
||||
} // getPeerDevices
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the connection information of a connected peer by vector index.
|
||||
* @param [in] index The vector index of the peer.
|
||||
*/
|
||||
NimBLEConnInfo NimBLEServer::getPeerInfo(size_t index) {
|
||||
if (index >= m_connectedPeersVec.size()) {
|
||||
NIMBLE_LOGE(LOG_TAG, "No peer at index %u", index);
|
||||
return NimBLEConnInfo();
|
||||
}
|
||||
|
||||
return getPeerIDInfo(m_connectedPeersVec[index]);
|
||||
} // getPeerInfo
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the connection information of a connected peer by address.
|
||||
* @param [in] address The address of the peer.
|
||||
*/
|
||||
NimBLEConnInfo NimBLEServer::getPeerInfo(const NimBLEAddress& address) {
|
||||
ble_addr_t peerAddr;
|
||||
memcpy(&peerAddr.val, address.getNative(),6);
|
||||
peerAddr.type = address.getType();
|
||||
|
||||
NimBLEConnInfo peerInfo;
|
||||
int rc = ble_gap_conn_find_by_addr(&peerAddr, &peerInfo.m_desc);
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Peer info not found");
|
||||
}
|
||||
|
||||
return peerInfo;
|
||||
} // getPeerInfo
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the connection information of a connected peer by connection ID.
|
||||
* @param [in] id The connection id of the peer.
|
||||
*/
|
||||
NimBLEConnInfo NimBLEServer::getPeerIDInfo(uint16_t id) {
|
||||
NimBLEConnInfo peerInfo;
|
||||
|
||||
int rc = ble_gap_conn_find(id, &peerInfo.m_desc);
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Peer info not found");
|
||||
}
|
||||
|
||||
return peerInfo;
|
||||
} // getPeerIDInfo
|
||||
|
||||
|
||||
/**
|
||||
* @brief Handle a GATT Server Event.
|
||||
*
|
||||
@@ -261,7 +345,9 @@ size_t NimBLEServer::getConnectedCount() {
|
||||
server->m_connectedPeersVec.push_back(event->connect.conn_handle);
|
||||
|
||||
rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
|
||||
assert(rc == 0);
|
||||
if (rc != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
server->m_pServerCallbacks->onConnect(server);
|
||||
server->m_pServerCallbacks->onConnect(server, &desc);
|
||||
@@ -296,6 +382,7 @@ size_t NimBLEServer::getConnectedCount() {
|
||||
}
|
||||
|
||||
server->m_pServerCallbacks->onDisconnect(server);
|
||||
server->m_pServerCallbacks->onDisconnect(server, &event->disconnect.conn);
|
||||
|
||||
if(server->m_advertiseOnDisconnect) {
|
||||
server->startAdvertising();
|
||||
@@ -315,7 +402,9 @@ size_t NimBLEServer::getConnectedCount() {
|
||||
(it->getProperties() & BLE_GATT_CHR_F_READ_ENC))
|
||||
{
|
||||
rc = ble_gap_conn_find(event->subscribe.conn_handle, &desc);
|
||||
assert(rc == 0);
|
||||
if (rc != 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(!desc.sec_state.encrypted) {
|
||||
NimBLEDevice::startSecurity(event->subscribe.conn_handle);
|
||||
@@ -334,25 +423,63 @@ size_t NimBLEServer::getConnectedCount() {
|
||||
NIMBLE_LOGI(LOG_TAG, "mtu update event; conn_handle=%d mtu=%d",
|
||||
event->mtu.conn_handle,
|
||||
event->mtu.value);
|
||||
rc = ble_gap_conn_find(event->mtu.conn_handle, &desc);
|
||||
if (rc != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
server->m_pServerCallbacks->onMTUChange(event->mtu.value, &desc);
|
||||
return 0;
|
||||
} // BLE_GAP_EVENT_MTU
|
||||
|
||||
case BLE_GAP_EVENT_NOTIFY_TX: {
|
||||
if(event->notify_tx.indication && event->notify_tx.status != 0) {
|
||||
for(auto &it : server->m_notifyChrVec) {
|
||||
if(it->getHandle() == event->notify_tx.attr_handle) {
|
||||
if(it->m_pTaskData != nullptr) {
|
||||
it->m_pTaskData->rc = event->notify_tx.status;
|
||||
xTaskNotifyGive(it->m_pTaskData->task);
|
||||
}
|
||||
break;
|
||||
}
|
||||
NimBLECharacteristic *pChar = nullptr;
|
||||
|
||||
for(auto &it : server->m_notifyChrVec) {
|
||||
if(it->getHandle() == event->notify_tx.attr_handle) {
|
||||
pChar = it;
|
||||
}
|
||||
}
|
||||
|
||||
if(pChar == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
NimBLECharacteristicCallbacks::Status statusRC;
|
||||
|
||||
if(event->notify_tx.indication) {
|
||||
if(event->notify_tx.status != 0) {
|
||||
if(event->notify_tx.status == BLE_HS_EDONE) {
|
||||
statusRC = NimBLECharacteristicCallbacks::Status::SUCCESS_INDICATE;
|
||||
} else if(rc == BLE_HS_ETIMEOUT) {
|
||||
statusRC = NimBLECharacteristicCallbacks::Status::ERROR_INDICATE_TIMEOUT;
|
||||
} else {
|
||||
statusRC = NimBLECharacteristicCallbacks::Status::ERROR_INDICATE_FAILURE;
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
server->clearIndicateWait(event->notify_tx.conn_handle);
|
||||
} else {
|
||||
if(event->notify_tx.status == 0) {
|
||||
statusRC = NimBLECharacteristicCallbacks::Status::SUCCESS_NOTIFY;
|
||||
} else {
|
||||
statusRC = NimBLECharacteristicCallbacks::Status::ERROR_GATT;
|
||||
}
|
||||
}
|
||||
|
||||
pChar->m_pCallbacks->onStatus(pChar, statusRC, event->notify_tx.status);
|
||||
|
||||
return 0;
|
||||
} // BLE_GAP_EVENT_NOTIFY_TX
|
||||
|
||||
case BLE_GAP_EVENT_ADV_COMPLETE: {
|
||||
NIMBLE_LOGD(LOG_TAG, "Advertising Complete");
|
||||
NimBLEDevice::getAdvertising()->advCompleteCB();
|
||||
return 0;
|
||||
}
|
||||
|
||||
case BLE_GAP_EVENT_CONN_UPDATE: {
|
||||
NIMBLE_LOGD(LOG_TAG, "Connection parameters updated.");
|
||||
return 0;
|
||||
@@ -366,7 +493,10 @@ size_t NimBLEServer::getConnectedCount() {
|
||||
|
||||
/* Delete the old bond. */
|
||||
rc = ble_gap_conn_find(event->repeat_pairing.conn_handle, &desc);
|
||||
assert(rc == 0);
|
||||
if (rc != 0){
|
||||
return BLE_GAP_REPEAT_PAIRING_IGNORE;
|
||||
}
|
||||
|
||||
ble_store_util_delete_peer(&desc.peer_id_addr);
|
||||
|
||||
/* Return BLE_GAP_REPEAT_PAIRING_RETRY to indicate that the host should
|
||||
@@ -507,7 +637,7 @@ void NimBLEServer::removeService(NimBLEService* service, bool deleteSvc) {
|
||||
if(service->m_removed > 0) {
|
||||
if(deleteSvc) {
|
||||
for(auto it = m_svcVec.begin(); it != m_svcVec.end(); ++it) {
|
||||
if ((*it)->getUUID() == service->getUUID()) {
|
||||
if ((*it) == service) {
|
||||
delete *it;
|
||||
m_svcVec.erase(it);
|
||||
break;
|
||||
@@ -523,32 +653,35 @@ void NimBLEServer::removeService(NimBLEService* service, bool deleteSvc) {
|
||||
return;
|
||||
}
|
||||
|
||||
service->m_removed = deleteSvc ? 2 : 1;
|
||||
m_svcChanged = true;
|
||||
|
||||
ble_svc_gatt_changed(0x0001, 0xffff);
|
||||
resetGATT();
|
||||
service->m_removed = deleteSvc ? NIMBLE_ATT_REMOVE_DELETE : NIMBLE_ATT_REMOVE_HIDE;
|
||||
serviceChanged();
|
||||
NimBLEDevice::getAdvertising()->removeServiceUUID(service->getUUID());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Adds a service which was already created, but removed from availability.
|
||||
* @brief Adds a service which was either already created but removed from availability,\n
|
||||
* or created and later added to services list.
|
||||
* @param [in] service The service object to add.
|
||||
* @note If it is desired to advertise the service it must be added by
|
||||
* calling NimBLEAdvertising::addServiceUUID.
|
||||
*/
|
||||
void NimBLEServer::addService(NimBLEService* service) {
|
||||
// If adding a service that was not removed just return.
|
||||
// Check that a service with the supplied UUID does not already exist.
|
||||
if(getServiceByUUID(service->getUUID()) != nullptr) {
|
||||
NIMBLE_LOGW(LOG_TAG, "Warning creating a duplicate service UUID: %s",
|
||||
std::string(service->getUUID()).c_str());
|
||||
}
|
||||
|
||||
// If adding a service that was not removed add it and return.
|
||||
// Else reset GATT and send service changed notification.
|
||||
if(service->m_removed == 0) {
|
||||
m_svcVec.push_back(service);
|
||||
return;
|
||||
}
|
||||
|
||||
service->m_removed = 0;
|
||||
m_svcChanged = true;
|
||||
|
||||
ble_svc_gatt_changed(0x0001, 0xffff);
|
||||
resetGATT();
|
||||
serviceChanged();
|
||||
}
|
||||
|
||||
|
||||
@@ -567,7 +700,7 @@ void NimBLEServer::resetGATT() {
|
||||
|
||||
for(auto it = m_svcVec.begin(); it != m_svcVec.end(); ) {
|
||||
if ((*it)->m_removed > 0) {
|
||||
if ((*it)->m_removed == 2) {
|
||||
if ((*it)->m_removed == NIMBLE_ATT_REMOVE_DELETE) {
|
||||
delete *it;
|
||||
it = m_svcVec.erase(it);
|
||||
} else {
|
||||
@@ -601,7 +734,7 @@ void NimBLEServer::startAdvertising() {
|
||||
*/
|
||||
void NimBLEServer::stopAdvertising() {
|
||||
NimBLEDevice::stopAdvertising();
|
||||
} // startAdvertising
|
||||
} // stopAdvertising
|
||||
|
||||
|
||||
/**
|
||||
@@ -614,7 +747,13 @@ uint16_t NimBLEServer::getPeerMTU(uint16_t conn_id) {
|
||||
|
||||
|
||||
/**
|
||||
* Update connection parameters can be called only after connection has been established
|
||||
* @brief Request an Update the connection parameters:
|
||||
* * Can only be used after a connection has been established.
|
||||
* @param [in] conn_handle The connection handle of the peer to send the request to.
|
||||
* @param [in] minInterval The minimum connection interval in 1.25ms units.
|
||||
* @param [in] maxInterval The maximum connection interval in 1.25ms units.
|
||||
* @param [in] latency The number of packets allowed to skip (extends max interval).
|
||||
* @param [in] timeout The timeout time in 10ms units before disconnecting.
|
||||
*/
|
||||
void NimBLEServer::updateConnParams(uint16_t conn_handle,
|
||||
uint16_t minInterval, uint16_t maxInterval,
|
||||
@@ -636,6 +775,51 @@ void NimBLEServer::updateConnParams(uint16_t conn_handle,
|
||||
} // 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 <= ESP_IDF_VERSION_VAL(4,3,2)
|
||||
return;
|
||||
#else
|
||||
uint16_t tx_time = (tx_octets + 14) * 8;
|
||||
|
||||
int rc = ble_gap_set_data_len(conn_handle, tx_octets, tx_time);
|
||||
if(rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Set data length error: %d, %s", rc, NimBLEUtils::returnCodeToString(rc));
|
||||
}
|
||||
#endif
|
||||
} // setDataLen
|
||||
|
||||
|
||||
bool NimBLEServer::setIndicateWait(uint16_t conn_handle) {
|
||||
for(auto i = 0; i < CONFIG_BT_NIMBLE_MAX_CONNECTIONS; i++) {
|
||||
if(m_indWait[i] == conn_handle) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void NimBLEServer::clearIndicateWait(uint16_t conn_handle) {
|
||||
for(auto i = 0; i < CONFIG_BT_NIMBLE_MAX_CONNECTIONS; i++) {
|
||||
if(m_indWait[i] == conn_handle) {
|
||||
m_indWait[i] = BLE_HS_CONN_HANDLE_NONE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Default callback handlers */
|
||||
|
||||
void NimBLEServerCallbacks::onConnect(NimBLEServer* pServer) {
|
||||
@@ -652,6 +836,14 @@ void NimBLEServerCallbacks::onDisconnect(NimBLEServer* pServer) {
|
||||
NIMBLE_LOGD("NimBLEServerCallbacks", "onDisconnect(): Default");
|
||||
} // onDisconnect
|
||||
|
||||
void NimBLEServerCallbacks::onDisconnect(NimBLEServer* pServer, ble_gap_conn_desc* desc) {
|
||||
NIMBLE_LOGD("NimBLEServerCallbacks", "onDisconnect(): Default");
|
||||
} // onDisconnect
|
||||
|
||||
void NimBLEServerCallbacks::onMTUChange(uint16_t MTU, ble_gap_conn_desc* desc) {
|
||||
NIMBLE_LOGD("NimBLEServerCallbacks", "onMTUChange(): Default");
|
||||
} // onMTUChange
|
||||
|
||||
uint32_t NimBLEServerCallbacks::onPassKeyRequest(){
|
||||
NIMBLE_LOGD("NimBLEServerCallbacks", "onPassKeyRequest: default: 123456");
|
||||
return 123456;
|
||||
@@ -674,6 +866,4 @@ bool NimBLEServerCallbacks::onConfirmPIN(uint32_t pin){
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
#endif // CONFIG_BT_ENABLED
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||
|
||||
@@ -14,17 +14,21 @@
|
||||
|
||||
#ifndef MAIN_NIMBLESERVER_H_
|
||||
#define MAIN_NIMBLESERVER_H_
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#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_DELETE 2
|
||||
|
||||
#define onMtuChanged onMTUChange
|
||||
|
||||
#include "NimBLEUtils.h"
|
||||
#include "NimBLEAddress.h"
|
||||
#include "NimBLEAdvertising.h"
|
||||
#include "NimBLEService.h"
|
||||
#include "NimBLESecurity.h"
|
||||
#include "NimBLEConnInfo.h"
|
||||
|
||||
|
||||
class NimBLEService;
|
||||
@@ -39,8 +43,7 @@ class NimBLEServer {
|
||||
public:
|
||||
size_t getConnectedCount();
|
||||
NimBLEService* createService(const char* uuid);
|
||||
NimBLEService* createService(const NimBLEUUID &uuid, uint32_t numHandles=15,
|
||||
uint8_t inst_id=0);
|
||||
NimBLEService* createService(const NimBLEUUID &uuid);
|
||||
void removeService(NimBLEService* service, bool deleteSvc = false);
|
||||
void addService(NimBLEService* service);
|
||||
NimBLEAdvertising* getAdvertising();
|
||||
@@ -49,21 +52,27 @@ public:
|
||||
void startAdvertising();
|
||||
void stopAdvertising();
|
||||
void start();
|
||||
NimBLEService* getServiceByUUID(const char* uuid);
|
||||
NimBLEService* getServiceByUUID(const NimBLEUUID &uuid);
|
||||
NimBLEService* getServiceByUUID(const char* uuid, uint16_t instanceId = 0);
|
||||
NimBLEService* getServiceByUUID(const NimBLEUUID &uuid, uint16_t instanceId = 0);
|
||||
NimBLEService* getServiceByHandle(uint16_t handle);
|
||||
int disconnect(uint16_t connID,
|
||||
uint8_t reason = BLE_ERR_REM_USER_CONN_TERM);
|
||||
void updateConnParams(uint16_t conn_handle,
|
||||
uint16_t minInterval, uint16_t maxInterval,
|
||||
uint16_t latency, uint16_t timeout);
|
||||
void setDataLen(uint16_t conn_handle, uint16_t tx_octets);
|
||||
uint16_t getPeerMTU(uint16_t conn_id);
|
||||
// std::vector<uint16_t> getPeerDevices();
|
||||
std::vector<uint16_t> getPeerDevices();
|
||||
NimBLEConnInfo getPeerInfo(size_t index);
|
||||
NimBLEConnInfo getPeerInfo(const NimBLEAddress& address);
|
||||
NimBLEConnInfo getPeerIDInfo(uint16_t id);
|
||||
void advertiseOnDisconnect(bool);
|
||||
|
||||
private:
|
||||
NimBLEServer();
|
||||
~NimBLEServer();
|
||||
friend class NimBLECharacteristic;
|
||||
friend class NimBLEService;
|
||||
friend class NimBLEDevice;
|
||||
friend class NimBLEAdvertising;
|
||||
|
||||
@@ -72,6 +81,7 @@ private:
|
||||
bool m_svcChanged;
|
||||
NimBLEServerCallbacks* m_pServerCallbacks;
|
||||
bool m_deleteCallbacks;
|
||||
uint16_t m_indWait[CONFIG_BT_NIMBLE_MAX_CONNECTIONS];
|
||||
std::vector<uint16_t> m_connectedPeersVec;
|
||||
|
||||
// uint16_t m_svcChgChrHdl; // Future use
|
||||
@@ -80,7 +90,10 @@ private:
|
||||
std::vector<NimBLECharacteristic*> m_notifyChrVec;
|
||||
|
||||
static int handleGapEvent(struct ble_gap_event *event, void *arg);
|
||||
void serviceChanged();
|
||||
void resetGATT();
|
||||
bool setIndicateWait(uint16_t conn_handle);
|
||||
void clearIndicateWait(uint16_t conn_handle);
|
||||
}; // NimBLEServer
|
||||
|
||||
|
||||
@@ -114,6 +127,23 @@ public:
|
||||
*/
|
||||
virtual void onDisconnect(NimBLEServer* pServer);
|
||||
|
||||
/**
|
||||
* @brief Handle a client disconnection.
|
||||
* This is called when a client discconnects.
|
||||
* @param [in] pServer A pointer to the %BLE server that received the client disconnection.
|
||||
* @param [in] desc A pointer to the connection description structure containig information
|
||||
* about the connection.
|
||||
*/
|
||||
virtual void onDisconnect(NimBLEServer* pServer, ble_gap_conn_desc* desc);
|
||||
|
||||
/**
|
||||
* @brief Called when the connection MTU changes.
|
||||
* @param [in] MTU The new MTU value.
|
||||
* @param [in] desc A pointer to the connection description structure containig information
|
||||
* about the connection.
|
||||
*/
|
||||
virtual void onMTUChange(uint16_t MTU, ble_gap_conn_desc* desc);
|
||||
|
||||
/**
|
||||
* @brief Called when a client requests a passkey for pairing.
|
||||
* @return The passkey to be sent to the client.
|
||||
@@ -138,7 +168,5 @@ public:
|
||||
virtual bool onConfirmPIN(uint32_t pin);
|
||||
}; // NimBLEServerCallbacks
|
||||
|
||||
|
||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||
#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.
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#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 "NimBLEUtils.h"
|
||||
#include "NimBLELog.h"
|
||||
@@ -34,25 +32,19 @@ static const char* LOG_TAG = "NimBLEService"; // Tag for logging.
|
||||
/**
|
||||
* @brief Construct an instance of the NimBLEService
|
||||
* @param [in] uuid The UUID of the service.
|
||||
* @param [in] numHandles The maximum number of handles associated with the service.
|
||||
* @param [in] a pointer to the server instance that this service belongs to.
|
||||
*/
|
||||
NimBLEService::NimBLEService(const char* uuid, uint16_t numHandles, NimBLEServer* pServer)
|
||||
: NimBLEService(NimBLEUUID(uuid), numHandles, pServer) {
|
||||
NimBLEService::NimBLEService(const char* uuid)
|
||||
: NimBLEService(NimBLEUUID(uuid)) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Construct an instance of the BLEService
|
||||
* @param [in] uuid The UUID of the service.
|
||||
* @param [in] numHandles The maximum number of handles associated with the service.
|
||||
* @param [in] 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_handle = NULL_HANDLE;
|
||||
m_pServer = pServer;
|
||||
m_numHandles = numHandles;
|
||||
m_pSvcDef = nullptr;
|
||||
m_removed = 0;
|
||||
|
||||
@@ -118,7 +110,12 @@ NimBLEUUID NimBLEService::getUUID() {
|
||||
*/
|
||||
bool NimBLEService::start() {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> start(): Starting service: %s", toString().c_str());
|
||||
int rc = 0;
|
||||
|
||||
// Rebuild the service definition if the server attributes have changed.
|
||||
if(getServer()->m_svcChanged && m_pSvcDef != nullptr) {
|
||||
delete(m_pSvcDef);
|
||||
m_pSvcDef = nullptr;
|
||||
}
|
||||
|
||||
if(m_pSvcDef == nullptr) {
|
||||
// Nimble requires an array of services to be sent to the api
|
||||
@@ -132,8 +129,23 @@ bool NimBLEService::start() {
|
||||
svc[0].uuid = &m_uuid.getNative()->u;
|
||||
svc[0].includes = NULL;
|
||||
|
||||
size_t numChrs = m_chrVec.size();
|
||||
int removedCount = 0;
|
||||
for(auto it = m_chrVec.begin(); it != m_chrVec.end(); ) {
|
||||
if ((*it)->m_removed > 0) {
|
||||
if ((*it)->m_removed == NIMBLE_ATT_REMOVE_DELETE) {
|
||||
delete *it;
|
||||
it = m_chrVec.erase(it);
|
||||
} else {
|
||||
++removedCount;
|
||||
++it;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
++it;
|
||||
}
|
||||
|
||||
size_t numChrs = m_chrVec.size() - removedCount;
|
||||
NIMBLE_LOGD(LOG_TAG,"Adding %d characteristics for service %s", numChrs, toString().c_str());
|
||||
|
||||
if(!numChrs){
|
||||
@@ -142,40 +154,60 @@ bool NimBLEService::start() {
|
||||
// Nimble requires the last characteristic to have it's uuid = 0 to indicate the end
|
||||
// of the characteristics for the service. We create 1 extra and set it to null
|
||||
// for this purpose.
|
||||
pChr_a = new ble_gatt_chr_def[numChrs+1];
|
||||
NimBLECharacteristic* pCharacteristic = *m_chrVec.begin();
|
||||
pChr_a = new ble_gatt_chr_def[numChrs + 1];
|
||||
uint8_t i = 0;
|
||||
for(auto chr_it = m_chrVec.begin(); chr_it != m_chrVec.end(); ++chr_it) {
|
||||
if((*chr_it)->m_removed > 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for(uint8_t i=0; i < numChrs;) {
|
||||
uint8_t numDscs = pCharacteristic->m_dscVec.size();
|
||||
removedCount = 0;
|
||||
for(auto it = (*chr_it)->m_dscVec.begin(); it != (*chr_it)->m_dscVec.end(); ) {
|
||||
if ((*it)->m_removed > 0) {
|
||||
if ((*it)->m_removed == NIMBLE_ATT_REMOVE_DELETE) {
|
||||
delete *it;
|
||||
it = (*chr_it)->m_dscVec.erase(it);
|
||||
} else {
|
||||
++removedCount;
|
||||
++it;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
++it;
|
||||
}
|
||||
|
||||
size_t numDscs = (*chr_it)->m_dscVec.size() - removedCount;
|
||||
|
||||
if(!numDscs){
|
||||
pChr_a[i].descriptors = NULL;
|
||||
} else {
|
||||
// Must have last descriptor uuid = 0 so we have to create 1 extra
|
||||
pDsc_a = new ble_gatt_dsc_def[numDscs+1];
|
||||
NimBLEDescriptor* pDescriptor = *pCharacteristic->m_dscVec.begin();
|
||||
for(uint8_t d=0; d < numDscs;) {
|
||||
pDsc_a[d].uuid = &pDescriptor->m_uuid.getNative()->u;
|
||||
pDsc_a[d].att_flags = pDescriptor->m_properties;
|
||||
uint8_t d = 0;
|
||||
for(auto dsc_it = (*chr_it)->m_dscVec.begin(); dsc_it != (*chr_it)->m_dscVec.end(); ++dsc_it ) {
|
||||
if((*dsc_it)->m_removed > 0) {
|
||||
continue;
|
||||
}
|
||||
pDsc_a[d].uuid = &(*dsc_it)->m_uuid.getNative()->u;
|
||||
pDsc_a[d].att_flags = (*dsc_it)->m_properties;
|
||||
pDsc_a[d].min_key_size = 0;
|
||||
pDsc_a[d].access_cb = NimBLEDescriptor::handleGapEvent;
|
||||
pDsc_a[d].arg = pDescriptor;
|
||||
d++;
|
||||
pDescriptor = *(pCharacteristic->m_dscVec.begin() + d);
|
||||
pDsc_a[d].arg = (*dsc_it);
|
||||
++d;
|
||||
}
|
||||
|
||||
pDsc_a[numDscs].uuid = NULL;
|
||||
pChr_a[i].descriptors = pDsc_a;
|
||||
}
|
||||
|
||||
pChr_a[i].uuid = &pCharacteristic->m_uuid.getNative()->u;
|
||||
pChr_a[i].uuid = &(*chr_it)->m_uuid.getNative()->u;
|
||||
pChr_a[i].access_cb = NimBLECharacteristic::handleGapEvent;
|
||||
pChr_a[i].arg = pCharacteristic;
|
||||
pChr_a[i].flags = pCharacteristic->m_properties;
|
||||
pChr_a[i].arg = (*chr_it);
|
||||
pChr_a[i].flags = (*chr_it)->m_properties;
|
||||
pChr_a[i].min_key_size = 0;
|
||||
pChr_a[i].val_handle = &pCharacteristic->m_handle;
|
||||
i++;
|
||||
pCharacteristic = *(m_chrVec.begin() + i);
|
||||
pChr_a[i].val_handle = &(*chr_it)->m_handle;
|
||||
++i;
|
||||
}
|
||||
|
||||
pChr_a[numChrs].uuid = NULL;
|
||||
@@ -187,7 +219,7 @@ bool NimBLEService::start() {
|
||||
m_pSvcDef = svc;
|
||||
}
|
||||
|
||||
rc = ble_gatts_count_cfg((const ble_gatt_svc_def*)m_pSvcDef);
|
||||
int rc = ble_gatts_count_cfg((const ble_gatt_svc_def*)m_pSvcDef);
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "ble_gatts_count_cfg failed, rc= %d, %s", rc, NimBLEUtils::returnCodeToString(rc));
|
||||
return false;
|
||||
@@ -233,44 +265,139 @@ NimBLECharacteristic* NimBLEService::createCharacteristic(const char* uuid, uint
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEService::createCharacteristic(const NimBLEUUID &uuid, uint32_t properties) {
|
||||
NimBLECharacteristic* pCharacteristic = new NimBLECharacteristic(uuid, properties, this);
|
||||
// Check that we don't add the same characteristic twice.
|
||||
|
||||
if (getCharacteristic(uuid) != nullptr) {
|
||||
NIMBLE_LOGW(LOG_TAG, "<< Adding a duplicate characteristic with UUID: %s",
|
||||
NIMBLE_LOGD(LOG_TAG, "<< Adding a duplicate characteristic with UUID: %s",
|
||||
std::string(uuid).c_str());
|
||||
}
|
||||
|
||||
// Remember this characteristic in our vector of characteristics.
|
||||
m_chrVec.push_back(pCharacteristic);
|
||||
|
||||
addCharacteristic(pCharacteristic);
|
||||
return pCharacteristic;
|
||||
} // createCharacteristic
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get a pointer to the characteristic object with the specified UUID.
|
||||
* @param [in] uuid The UUID of the characteristic.
|
||||
* @return A pointer to the characteristic object or nullptr if not found.
|
||||
* @brief Add a characteristic to the service.
|
||||
* @param[in] pCharacteristic A pointer to the characteristic instance to add to the service.
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEService::getCharacteristic(const char* uuid) {
|
||||
return getCharacteristic(NimBLEUUID(uuid));
|
||||
}
|
||||
void NimBLEService::addCharacteristic(NimBLECharacteristic* pCharacteristic) {
|
||||
bool foundRemoved = false;
|
||||
|
||||
if(pCharacteristic->m_removed > 0) {
|
||||
for(auto& it : m_chrVec) {
|
||||
if(it == pCharacteristic) {
|
||||
foundRemoved = true;
|
||||
pCharacteristic->m_removed = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!foundRemoved) {
|
||||
m_chrVec.push_back(pCharacteristic);
|
||||
}
|
||||
|
||||
pCharacteristic->setService(this);
|
||||
getServer()->serviceChanged();
|
||||
} // addCharacteristic
|
||||
|
||||
|
||||
/**
|
||||
* @brief Remove a characteristic from the service.
|
||||
* @param[in] pCharacteristic A pointer to the characteristic instance to remove from the service.
|
||||
* @param[in] deleteChr If true it will delete the characteristic instance and free it's resources.
|
||||
*/
|
||||
void NimBLEService::removeCharacteristic(NimBLECharacteristic* pCharacteristic, bool deleteChr) {
|
||||
// Check if the characteristic was already removed and if so, check if this
|
||||
// is being called to delete the object and do so if requested.
|
||||
// Otherwise, ignore the call and return.
|
||||
if(pCharacteristic->m_removed > 0) {
|
||||
if(deleteChr) {
|
||||
for(auto it = m_chrVec.begin(); it != m_chrVec.end(); ++it) {
|
||||
if ((*it) == pCharacteristic) {
|
||||
m_chrVec.erase(it);
|
||||
delete *it;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
pCharacteristic->m_removed = deleteChr ? NIMBLE_ATT_REMOVE_DELETE : NIMBLE_ATT_REMOVE_HIDE;
|
||||
getServer()->serviceChanged();
|
||||
} // removeCharacteristic
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get a pointer to the characteristic object with the specified UUID.
|
||||
* @param [in] uuid The UUID of the characteristic.
|
||||
* @param instanceId The index of the characteristic to return (used when multiple characteristics have the same UUID).
|
||||
* @return A pointer to the characteristic object or nullptr if not found.
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEService::getCharacteristic(const NimBLEUUID &uuid) {
|
||||
NimBLECharacteristic* NimBLEService::getCharacteristic(const char* uuid, uint16_t instanceId) {
|
||||
return getCharacteristic(NimBLEUUID(uuid), instanceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a pointer to the characteristic object with the specified UUID.
|
||||
* @param [in] uuid The UUID of the characteristic.
|
||||
* @param instanceId The index of the characteristic to return (used when multiple characteristics have the same UUID).
|
||||
* @return A pointer to the characteristic object or nullptr if not found.
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEService::getCharacteristic(const NimBLEUUID &uuid, uint16_t instanceId) {
|
||||
uint16_t position = 0;
|
||||
for (auto &it : m_chrVec) {
|
||||
if (it->getUUID() == uuid) {
|
||||
return it;
|
||||
if (position == instanceId) {
|
||||
return it;
|
||||
}
|
||||
position++;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a pointer to the characteristic object with the specified handle.
|
||||
* @param handle The handle of the characteristic.
|
||||
* @return A pointer to the characteristic object or nullptr if not found.
|
||||
*/
|
||||
NimBLECharacteristic *NimBLEService::getCharacteristicByHandle(uint16_t handle) {
|
||||
for (auto &it : m_chrVec) {
|
||||
if (it->getHandle() == handle) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A vector containing pointers to each characteristic associated with this service.
|
||||
*/
|
||||
std::vector<NimBLECharacteristic *> NimBLEService::getCharacteristics() {
|
||||
return m_chrVec;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A vector containing pointers to each characteristic with the provided UUID associated with this service.
|
||||
*/
|
||||
std::vector<NimBLECharacteristic *> NimBLEService::getCharacteristics(const char *uuid) {
|
||||
return getCharacteristics(NimBLEUUID(uuid));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A vector containing pointers to each characteristic with the provided UUID associated with this service.
|
||||
*/
|
||||
std::vector<NimBLECharacteristic *> NimBLEService::getCharacteristics(const NimBLEUUID &uuid) {
|
||||
std::vector<NimBLECharacteristic*> result;
|
||||
for (auto &it : m_chrVec) {
|
||||
if (it->getUUID() == uuid) {
|
||||
result.push_back(it);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return a string representation of this service.
|
||||
@@ -294,8 +421,7 @@ std::string NimBLEService::toString() {
|
||||
* @return The BLEServer associated with this service.
|
||||
*/
|
||||
NimBLEServer* NimBLEService::getServer() {
|
||||
return m_pServer;
|
||||
} // getServer
|
||||
return NimBLEDevice::getServer();
|
||||
}// getServer
|
||||
|
||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
#endif // CONFIG_BT_ENABLED
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||
|
||||
@@ -14,11 +14,9 @@
|
||||
|
||||
#ifndef MAIN_NIMBLESERVICE_H_
|
||||
#define MAIN_NIMBLESERVICE_H_
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#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 "NimBLECharacteristic.h"
|
||||
@@ -35,6 +33,20 @@ class NimBLECharacteristic;
|
||||
*/
|
||||
class NimBLEService {
|
||||
public:
|
||||
|
||||
NimBLEService(const char* uuid);
|
||||
NimBLEService(const NimBLEUUID &uuid);
|
||||
~NimBLEService();
|
||||
|
||||
NimBLEServer* getServer();
|
||||
|
||||
NimBLEUUID getUUID();
|
||||
uint16_t getHandle();
|
||||
std::string toString();
|
||||
void dump();
|
||||
|
||||
bool start();
|
||||
|
||||
NimBLECharacteristic* createCharacteristic(const char* uuid,
|
||||
uint32_t properties =
|
||||
NIMBLE_PROPERTY::READ |
|
||||
@@ -45,34 +57,29 @@ public:
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE);
|
||||
|
||||
void dump();
|
||||
NimBLECharacteristic* getCharacteristic(const char* uuid);
|
||||
NimBLECharacteristic* getCharacteristic(const NimBLEUUID &uuid);
|
||||
NimBLEUUID getUUID();
|
||||
NimBLEServer* getServer();
|
||||
bool start();
|
||||
std::string toString();
|
||||
uint16_t getHandle();
|
||||
void addCharacteristic(NimBLECharacteristic* pCharacteristic);
|
||||
void removeCharacteristic(NimBLECharacteristic* pCharacteristic, bool deleteChr = false);
|
||||
NimBLECharacteristic* getCharacteristic(const char* uuid, uint16_t instanceId = 0);
|
||||
NimBLECharacteristic* getCharacteristic(const NimBLEUUID &uuid, uint16_t instanceId = 0);
|
||||
NimBLECharacteristic* getCharacteristicByHandle(uint16_t handle);
|
||||
|
||||
std::vector<NimBLECharacteristic*> getCharacteristics();
|
||||
std::vector<NimBLECharacteristic*> getCharacteristics(const char* uuid);
|
||||
std::vector<NimBLECharacteristic*> getCharacteristics(const NimBLEUUID &uuid);
|
||||
|
||||
|
||||
private:
|
||||
NimBLEService(const char* uuid, uint16_t numHandles, NimBLEServer* pServer);
|
||||
NimBLEService(const NimBLEUUID &uuid, uint16_t numHandles, NimBLEServer* pServer);
|
||||
~NimBLEService();
|
||||
|
||||
friend class NimBLEServer;
|
||||
friend class NimBLEDevice;
|
||||
|
||||
uint16_t m_handle;
|
||||
NimBLEServer* m_pServer;
|
||||
NimBLEUUID m_uuid;
|
||||
uint16_t m_numHandles;
|
||||
ble_gatt_svc_def* m_pSvcDef;
|
||||
uint8_t m_removed;
|
||||
std::vector<NimBLECharacteristic*> m_chrVec;
|
||||
|
||||
}; // NimBLEService
|
||||
|
||||
|
||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
#endif // CONFIG_BT_ENABLED
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||
#endif /* MAIN_NIMBLESERVICE_H_ */
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
* Created on: Jun 21, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include "NimBLEUtils.h"
|
||||
@@ -65,29 +66,42 @@ static const char* LOG_TAG = "NimBLEUUID";
|
||||
*this = NimBLEUUID(first, second, third, (uint64_t(fourth) << 48) + fifth);
|
||||
}
|
||||
else {
|
||||
NIMBLE_LOGE(LOG_TAG,"ERROR: UUID value not 2, 4, 16 or 36 bytes");
|
||||
m_valueSet = false;
|
||||
}
|
||||
} // NimBLEUUID(std::string)
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a UUID from 16 bytes of memory.
|
||||
* @brief Create a UUID from 2, 4, 16 bytes of memory.
|
||||
* @param [in] pData The pointer to the start of the UUID.
|
||||
* @param [in] size The size of the data.
|
||||
* @param [in] msbFirst Is the MSB first in pData memory?
|
||||
*/
|
||||
NimBLEUUID::NimBLEUUID(const uint8_t* pData, size_t size, bool msbFirst) {
|
||||
if (size != 16) {
|
||||
NIMBLE_LOGE(LOG_TAG,"ERROR: UUID length not 16 bytes");
|
||||
return;
|
||||
}
|
||||
m_uuid.u.type = BLE_UUID_TYPE_128;
|
||||
uint8_t *uuidValue = nullptr;
|
||||
|
||||
switch(size) {
|
||||
case 2:
|
||||
uuidValue = (uint8_t*)&m_uuid.u16.value;
|
||||
m_uuid.u.type = BLE_UUID_TYPE_16;
|
||||
break;
|
||||
case 4:
|
||||
uuidValue = (uint8_t*)&m_uuid.u32.value;
|
||||
m_uuid.u.type = BLE_UUID_TYPE_32;
|
||||
break;
|
||||
case 16:
|
||||
uuidValue = m_uuid.u128.value;
|
||||
m_uuid.u.type = BLE_UUID_TYPE_128;
|
||||
break;
|
||||
default:
|
||||
m_valueSet = false;
|
||||
NIMBLE_LOGE(LOG_TAG, "Invalid UUID size");
|
||||
return;
|
||||
}
|
||||
if (msbFirst) {
|
||||
std::reverse_copy(pData, pData + 16, m_uuid.u128.value);
|
||||
std::reverse_copy(pData, pData + size, uuidValue);
|
||||
} else {
|
||||
memcpy(m_uuid.u128.value, pData, 16);
|
||||
memcpy(uuidValue, pData, size);
|
||||
}
|
||||
m_valueSet = true;
|
||||
} // NimBLEUUID
|
||||
@@ -264,6 +278,33 @@ std::string NimBLEUUID::toString() const {
|
||||
*/
|
||||
bool NimBLEUUID::operator ==(const NimBLEUUID & rhs) const {
|
||||
if(m_valueSet && rhs.m_valueSet) {
|
||||
if(m_uuid.u.type != rhs.m_uuid.u.type) {
|
||||
uint8_t uuidBase[16] = {
|
||||
0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
|
||||
0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
if(m_uuid.u.type == BLE_UUID_TYPE_128){
|
||||
if(rhs.m_uuid.u.type == BLE_UUID_TYPE_16){
|
||||
memcpy(uuidBase+12, &rhs.m_uuid.u16.value, 2);
|
||||
} else if (rhs.m_uuid.u.type == BLE_UUID_TYPE_32){
|
||||
memcpy(uuidBase+12, &rhs.m_uuid.u32.value, 4);
|
||||
}
|
||||
return memcmp(m_uuid.u128.value,uuidBase,16) == 0;
|
||||
|
||||
} else if(rhs.m_uuid.u.type == BLE_UUID_TYPE_128) {
|
||||
if(m_uuid.u.type == BLE_UUID_TYPE_16){
|
||||
memcpy(uuidBase+12, &m_uuid.u16.value, 2);
|
||||
} else if (m_uuid.u.type == BLE_UUID_TYPE_32){
|
||||
memcpy(uuidBase+12, &m_uuid.u32.value, 4);
|
||||
}
|
||||
return memcmp(rhs.m_uuid.u128.value,uuidBase,16) == 0;
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return ble_uuid_cmp(&m_uuid.u, &rhs.m_uuid.u) == 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,10 +14,16 @@
|
||||
|
||||
#ifndef COMPONENTS_NIMBLEUUID_H_
|
||||
#define COMPONENTS_NIMBLEUUID_H_
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
#include "host/ble_uuid.h"
|
||||
#else
|
||||
#include "nimble/nimble/host/include/host/ble_uuid.h"
|
||||
#endif
|
||||
|
||||
/**** FIX COMPILATION ****/
|
||||
#undef min
|
||||
#undef max
|
||||
|
||||
@@ -6,12 +6,13 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include "NimBLEUtils.h"
|
||||
#include "NimBLELog.h"
|
||||
#include "nimconfig.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
static const char* LOG_TAG = "NimBLEUtils";
|
||||
|
||||
@@ -342,6 +343,7 @@ const char* NimBLEUtils::returnCodeToString(int rc) {
|
||||
return "Unknown";
|
||||
}
|
||||
#else // #if defined(CONFIG_NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT)
|
||||
(void)rc;
|
||||
return "";
|
||||
#endif // #if defined(CONFIG_NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT)
|
||||
}
|
||||
@@ -369,6 +371,7 @@ const char* NimBLEUtils::advTypeToString(uint8_t advType) {
|
||||
return "Unknown flag";
|
||||
}
|
||||
#else // #if defined(CONFIG_NIMBLE_CPP_ENABLE_ADVERTISMENT_TYPE_TEXT)
|
||||
(void)advType;
|
||||
return "";
|
||||
#endif // #if defined(CONFIG_NIMBLE_CPP_ENABLE_ADVERTISMENT_TYPE_TEXT)
|
||||
} // adFlagsToString
|
||||
@@ -416,8 +419,11 @@ char* NimBLEUtils::buildHexData(uint8_t* target, const uint8_t* source, uint8_t
|
||||
* @param [in] arg Unused.
|
||||
*/
|
||||
void NimBLEUtils::dumpGapEvent(ble_gap_event *event, void *arg){
|
||||
(void)arg;
|
||||
#if defined(CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT)
|
||||
NIMBLE_LOGD(LOG_TAG, "Received a GAP event: %s", gapEventToString(event->type));
|
||||
#else
|
||||
(void)event;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -504,6 +510,7 @@ const char* NimBLEUtils::gapEventToString(uint8_t eventType) {
|
||||
return "Unknown event type";
|
||||
}
|
||||
#else // #if defined(CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT)
|
||||
(void)eventType;
|
||||
return "";
|
||||
#endif // #if defined(CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT)
|
||||
} // gapEventToString
|
||||
|
||||
@@ -8,10 +8,15 @@
|
||||
|
||||
#ifndef COMPONENTS_NIMBLEUTILS_H_
|
||||
#define COMPONENTS_NIMBLEUTILS_H_
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
#include "host/ble_gap.h"
|
||||
#else
|
||||
#include "nimble/nimble/host/include/host/ble_gap.h"
|
||||
#endif
|
||||
|
||||
/**** FIX COMPILATION ****/
|
||||
#undef min
|
||||
|
||||
270
src/nimconfig.h
270
src/nimconfig.h
@@ -1,194 +1,19 @@
|
||||
/** @file
|
||||
*
|
||||
/** @file
|
||||
*
|
||||
* IGNORE THIS FILE IF USING ESP-IDF, USE MENUCONFIG TO SET NIMBLE OPTIONS.
|
||||
*
|
||||
* The config options here are for Arduino use only.
|
||||
* The config options here are for doxygen documentation only.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "nimconfig_rename.h"
|
||||
|
||||
/*
|
||||
* For ESP-IDF compatibility
|
||||
* Some versions of ESP-IDF used the config name format "CONFIG_NIMBLE_".
|
||||
* This converts them to "CONFIG_BT_NIMBLE_" format used in the latest IDF.
|
||||
*/
|
||||
|
||||
/* Detect if using ESP-IDF or Arduino (Arduino won't have these defines in sdkconfig) */
|
||||
#if defined(CONFIG_BT_NIMBLE_TASK_STACK_SIZE) || defined(CONFIG_NIMBLE_TASK_STACK_SIZE)
|
||||
|
||||
#if defined(CONFIG_NIMBLE_ENABLED) && !defined(CONFIG_BT_NIMBLE_ENABLED)
|
||||
#define CONFIG_BT_NIMBLE_ENABLED
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_NIMBLE_ROLE_OBSERVER) && !defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||
#define CONFIG_BT_NIMBLE_ROLE_OBSERVER
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_NIMBLE_ROLE_BROADCASTER) && !defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||
#define CONFIG_BT_NIMBLE_ROLE_BROADCASTER
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_NIMBLE_ROLE_CENTRAL) && !defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
#define CONFIG_BT_NIMBLE_ROLE_CENTRAL
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_NIMBLE_ROLE_PERIPHERAL) && !defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
#define CONFIG_BT_NIMBLE_ROLE_PERIPHERAL
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_NIMBLE_DEBUG) && !defined(CONFIG_BT_NIMBLE_DEBUG)
|
||||
#define CONFIG_BT_NIMBLE_DEBUG
|
||||
#endif
|
||||
|
||||
#else // Using Arduino
|
||||
|
||||
/***********************************************
|
||||
* Arduino config options start here
|
||||
**********************************************/
|
||||
|
||||
/** @brief Comment out if not using NimBLE Client functions \n
|
||||
* Reduces flash size by approx. 7kB.
|
||||
*/
|
||||
#define CONFIG_BT_NIMBLE_ROLE_CENTRAL
|
||||
|
||||
/** @brief Comment out if not using NimBLE Scan functions \n
|
||||
* Reduces flash size by approx. 26kB.
|
||||
*/
|
||||
#define CONFIG_BT_NIMBLE_ROLE_OBSERVER
|
||||
|
||||
/** @brief Comment out if not using NimBLE Server functions \n
|
||||
* Reduces flash size by approx. 16kB.
|
||||
*/
|
||||
#define CONFIG_BT_NIMBLE_ROLE_PERIPHERAL
|
||||
|
||||
/** @brief Comment out if not using NimBLE Advertising functions \n
|
||||
* Reduces flash size by approx. 5kB.
|
||||
*/
|
||||
#define CONFIG_BT_NIMBLE_ROLE_BROADCASTER
|
||||
|
||||
/* Uncomment to see debug log messages from the NimBLE host
|
||||
* Uses approx. 32kB of flash memory.
|
||||
*/
|
||||
// #define CONFIG_BT_NIMBLE_DEBUG
|
||||
|
||||
/* Uncomment to see NimBLE host return codes as text debug log messages.
|
||||
* Uses approx. 7kB of flash memory.
|
||||
*/
|
||||
// #define CONFIG_NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT
|
||||
|
||||
/* Uncomment to see GAP event codes as text in debug log messages.
|
||||
* Uses approx. 1kB of flash memory.
|
||||
*/
|
||||
// #define CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT
|
||||
|
||||
/* Uncomment to see advertisment types as text while scanning in debug log messages.
|
||||
* Uses approx. 250 bytes of flash memory.
|
||||
*/
|
||||
// #define CONFIG_NIMBLE_CPP_ENABLE_ADVERTISMENT_TYPE_TEXT
|
||||
|
||||
/** @brief Sets the core NimBLE host runs on */
|
||||
#define CONFIG_BT_NIMBLE_PINNED_TO_CORE 0
|
||||
|
||||
/** @brief Sets the stack size for the NimBLE host task */
|
||||
#define CONFIG_BT_NIMBLE_TASK_STACK_SIZE 4096
|
||||
|
||||
/**
|
||||
* @brief Sets the memory pool where NimBLE will be loaded
|
||||
* @details By default NimBLE is loaded in internal ram.\n
|
||||
* To use external PSRAM you must change this to `#define CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL 1`
|
||||
*/
|
||||
#define CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_INTERNAL 1
|
||||
|
||||
/**
|
||||
* @brief Sets the number of simultaneous connections (esp controller max is 9)
|
||||
* @details To increase max connections in Arduino it is also required to change the
|
||||
* controller max connections defined in sdkconfig.h.\n
|
||||
*
|
||||
* This is located in your Arduino/hardware/espressif/esp32/tools/sdk/include/config folder.\n\n
|
||||
*
|
||||
* The values in sdkconfig.h you will need to change are:\n\n
|
||||
* `CONFIG_BTDM_CONTROLLER_BLE_MAX_CONN 3`\n
|
||||
* `CONFIG_BTDM_CONTROLLER_BLE_MAX_CONN_EFF 3`
|
||||
*/
|
||||
#define CONFIG_BT_NIMBLE_MAX_CONNECTIONS 3
|
||||
|
||||
/** @brief Sets the number of devices allowed to store/bond with */
|
||||
#define CONFIG_BT_NIMBLE_MAX_BONDS 3
|
||||
|
||||
/** @brief Sets the maximum number of CCCD subscriptions to store */
|
||||
#define CONFIG_BT_NIMBLE_MAX_CCCDS 8
|
||||
|
||||
/** @brief Set if CCCD's and bond data should be stored in NVS */
|
||||
#define CONFIG_BT_NIMBLE_NVS_PERSIST 1
|
||||
|
||||
/** @brief Allow legacy paring */
|
||||
#define CONFIG_BT_NIMBLE_SM_LEGACY 1
|
||||
|
||||
/** @brief Allow BLE secure connections */
|
||||
#define CONFIG_BT_NIMBLE_SM_SC 1
|
||||
|
||||
/** @brief Default device name */
|
||||
#define CONFIG_BT_NIMBLE_SVC_GAP_DEVICE_NAME "nimble"
|
||||
|
||||
/** @brief Max device name length (bytes) */
|
||||
#define CONFIG_BT_NIMBLE_GAP_DEVICE_NAME_MAX_LEN 31
|
||||
|
||||
/** @brief Default MTU size */
|
||||
#define CONFIG_BT_NIMBLE_ATT_PREFERRED_MTU 256
|
||||
|
||||
/** @brief Default GAP appearance */
|
||||
#define CONFIG_BT_NIMBLE_SVC_GAP_APPEARANCE 0x0
|
||||
|
||||
/** @brief ACL Buffer count */
|
||||
#define CONFIG_BT_NIMBLE_ACL_BUF_COUNT 12
|
||||
|
||||
/** @brief ACL Buffer size */
|
||||
#define CONFIG_BT_NIMBLE_ACL_BUF_SIZE 255
|
||||
|
||||
/** @brief HCI Event Buffer size */
|
||||
#define CONFIG_BT_NIMBLE_HCI_EVT_BUF_SIZE 70
|
||||
|
||||
/** @brief Number of high priority HCI event buffers */
|
||||
#define CONFIG_BT_NIMBLE_HCI_EVT_HI_BUF_COUNT 30
|
||||
|
||||
/** @brief Number of low priority HCI event buffers */
|
||||
#define CONFIG_BT_NIMBLE_HCI_EVT_LO_BUF_COUNT 8
|
||||
|
||||
/**
|
||||
* @brief Sets the number of MSYS buffers available.
|
||||
* @details MSYS is a system level mbuf registry. For prepare write & prepare \n
|
||||
* responses MBUFs are allocated out of msys_1 pool. This may need to be increased if\n
|
||||
* you are sending large blocks of data with a low MTU. E.g: 512 bytes with 23 MTU will fail.
|
||||
*/
|
||||
#define CONFIG_BT_NIMBLE_MSYS1_BLOCK_COUNT 12
|
||||
|
||||
|
||||
/** @brief Random address refresh time in seconds */
|
||||
#define CONFIG_BT_NIMBLE_RPA_TIMEOUT 900
|
||||
|
||||
/** @brief Maximum number of connection oriented channels */
|
||||
#define CONFIG_BT_NIMBLE_L2CAP_COC_MAX_NUM 0
|
||||
|
||||
/* These should not be altered */
|
||||
#define CONFIG_BT_NIMBLE_HS_FLOW_CTRL 1
|
||||
#define CONFIG_BT_NIMBLE_HS_FLOW_CTRL_ITVL 1000
|
||||
#define CONFIG_BT_NIMBLE_HS_FLOW_CTRL_THRESH 2
|
||||
#define CONFIG_BT_NIMBLE_HS_FLOW_CTRL_TX_ON_DISCONNECT 1
|
||||
|
||||
#ifndef CONFIG_BT_ENABLED
|
||||
#define CONFIG_BT_ENABLED
|
||||
#endif
|
||||
|
||||
#define CONFIG_BTDM_CONTROLLER_MODE_BLE_ONLY
|
||||
|
||||
#endif // #if defined(CONFIG_BT_NIMBLE_TASK_STACK_SIZE) || defined(CONFIG_NIMBLE_TASK_STACK_SIZE)
|
||||
|
||||
/**********************************
|
||||
End Arduino config
|
||||
**********************************/
|
||||
#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)
|
||||
@@ -200,26 +25,93 @@
|
||||
#define CONFIG_BT_NIMBLE_ROLE_BROADCASTER
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
|
||||
#ifdef _DOXYGEN_
|
||||
/** @brief Uncomment to see debug log messages from the NimBLE host \n
|
||||
|
||||
/** @brief Un-comment to change the number of simultaneous connections (esp controller max is 9) */
|
||||
#define CONFIG_BT_NIMBLE_MAX_CONNECTIONS 3
|
||||
|
||||
/** @brief Un-comment to change the default MTU size */
|
||||
#define CONFIG_BT_NIMBLE_ATT_PREFERRED_MTU 255
|
||||
|
||||
/** @brief Un-comment to change default device name */
|
||||
#define CONFIG_BT_NIMBLE_SVC_GAP_DEVICE_NAME "nimble"
|
||||
|
||||
/** @brief Un-comment to set the debug log messages level from the NimBLE host stack.\n
|
||||
* Values: 0 = DEBUG, 1 = INFO, 2 = WARNING, 3 = ERROR, 4 = CRITICAL, 5+ = NONE\n
|
||||
* Uses approx. 32kB of flash memory.
|
||||
*/
|
||||
#define CONFIG_BT_NIMBLE_DEBUG
|
||||
#define CONFIG_BT_NIMBLE_LOG_LEVEL 5
|
||||
|
||||
/** @brief Uncomment to see NimBLE host return codes as text debug log messages. \n
|
||||
/** @brief Un-comment to set the debug log messages level from the NimBLE CPP Wrapper.\n
|
||||
* Values: 0 = NONE, 1 = ERROR, 2 = WARNING, 3 = INFO, 4+ = DEBUG\n
|
||||
* Uses approx. 32kB of flash memory.
|
||||
*/
|
||||
#define CONFIG_NIMBLE_CPP_LOG_LEVEL 0
|
||||
|
||||
/** @brief Un-comment to see NimBLE host return codes as text debug log messages.
|
||||
* Uses approx. 7kB of flash memory.
|
||||
*/
|
||||
#define CONFIG_NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT
|
||||
|
||||
/** @brief Uncomment to see GAP event codes as text in debug log messages. \n
|
||||
/** @brief Un-comment to see GAP event codes as text in debug log messages.
|
||||
* Uses approx. 1kB of flash memory.
|
||||
*/
|
||||
#define CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT
|
||||
|
||||
/** @brief Uncomment to see advertisment types as text while scanning in debug log messages. \n
|
||||
/** @brief Un-comment to see advertisment types as text while scanning in debug log messages.
|
||||
* Uses approx. 250 bytes of flash memory.
|
||||
*/
|
||||
#define CONFIG_NIMBLE_CPP_ENABLE_ADVERTISMENT_TYPE_TEXT
|
||||
|
||||
/** @brief Un-comment to change the default GAP appearance */
|
||||
#define CONFIG_BT_NIMBLE_SVC_GAP_APPEARANCE 0x0
|
||||
|
||||
/** @brief Un-comment if not using NimBLE Client functions \n
|
||||
* Reduces flash size by approx. 7kB.
|
||||
*/
|
||||
#define CONFIG_BT_NIMBLE_ROLE_CENTRAL_DISABLED
|
||||
|
||||
/** @brief Un-comment if not using NimBLE Scan functions \n
|
||||
* Reduces flash size by approx. 26kB.
|
||||
*/
|
||||
#define CONFIG_BT_NIMBLE_ROLE_OBSERVER_DISABLED
|
||||
|
||||
/** @brief Un-comment if not using NimBLE Server functions \n
|
||||
* Reduces flash size by approx. 16kB.
|
||||
*/
|
||||
#define CONFIG_BT_NIMBLE_ROLE_PERIPHERAL_DISABLED
|
||||
|
||||
/** @brief Un-comment if not using NimBLE Advertising functions \n
|
||||
* Reduces flash size by approx. 5kB.
|
||||
*/
|
||||
#define CONFIG_BT_NIMBLE_ROLE_BROADCASTER_DISABLED
|
||||
|
||||
/** @brief Un-comment to change the number of devices allowed to store/bond with */
|
||||
#define CONFIG_BT_NIMBLE_MAX_BONDS 3
|
||||
|
||||
/** @brief Un-comment to change the maximum number of CCCD subscriptions to store */
|
||||
#define CONFIG_BT_NIMBLE_MAX_CCCDS 8
|
||||
|
||||
/** @brief Un-comment to change the random address refresh time (in seconds) */
|
||||
#define CONFIG_BT_NIMBLE_RPA_TIMEOUT 900
|
||||
|
||||
/**
|
||||
* @brief Un-comment to change the number of MSYS buffers available.
|
||||
* @details MSYS is a system level mbuf registry. For prepare write & prepare \n
|
||||
* responses MBUFs are allocated out of msys_1 pool. This may need to be increased if\n
|
||||
* you are sending large blocks of data with a low MTU. E.g: 512 bytes with 23 MTU will fail.
|
||||
*/
|
||||
#define CONFIG_BT_NIMBLE_MSYS1_BLOCK_COUNT 12
|
||||
|
||||
/** @brief Un-comment to use external PSRAM for the NimBLE host */
|
||||
#define CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL 1
|
||||
|
||||
/** @brief Un-comment to change the core NimBLE host runs on */
|
||||
#define CONFIG_BT_NIMBLE_PINNED_TO_CORE 0
|
||||
|
||||
/** @brief Un-comment to change the stack size for the NimBLE host task */
|
||||
#define CONFIG_BT_NIMBLE_TASK_STACK_SIZE 4096
|
||||
|
||||
#endif // _DOXYGEN_
|
||||
|
||||
61
src/nimconfig_rename.h
Normal file
61
src/nimconfig_rename.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* For ESP-IDF compatibility
|
||||
* Some versions of ESP-IDF used the config name format "CONFIG_NIMBLE_".
|
||||
* This converts them to "CONFIG_BT_NIMBLE_" format used in the latest IDF.
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_NIMBLE_ENABLED) && !defined(CONFIG_BT_NIMBLE_ENABLED)
|
||||
#define CONFIG_BT_NIMBLE_ENABLED
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_NIMBLE_ROLE_OBSERVER) && !defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||
#define CONFIG_BT_NIMBLE_ROLE_OBSERVER
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_NIMBLE_ROLE_BROADCASTER) && !defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||
#define CONFIG_BT_NIMBLE_ROLE_BROADCASTER
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_NIMBLE_ROLE_CENTRAL) && !defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
#define CONFIG_BT_NIMBLE_ROLE_CENTRAL
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_NIMBLE_ROLE_PERIPHERAL) && !defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
#define CONFIG_BT_NIMBLE_ROLE_PERIPHERAL
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_NIMBLE_DEBUG) && !defined(CONFIG_BT_NIMBLE_DEBUG)
|
||||
#define CONFIG_BT_NIMBLE_DEBUG
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SCAN_DUPLICATE_BY_DEVICE_ADDR) && !defined(CONFIG_BTDM_SCAN_DUPL_TYPE_DEVICE)
|
||||
#define CONFIG_BTDM_SCAN_DUPL_TYPE_DEVICE CONFIG_SCAN_DUPLICATE_BY_DEVICE_ADDR
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SCAN_DUPLICATE_BY_ADV_DATA ) && !defined(CONFIG_BTDM_SCAN_DUPL_TYPE_DATA)
|
||||
#define CONFIG_BTDM_SCAN_DUPL_TYPE_DATA CONFIG_SCAN_DUPLICATE_BY_ADV_DATA
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SCAN_DUPLICATE_BY_ADV_DATA_AND_DEVICE_ADDR) && !defined(CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE)
|
||||
#define CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE CONFIG_SCAN_DUPLICATE_BY_ADV_DATA_AND_DEVICE_ADDR
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SCAN_DUPLICATE_TYPE) && !defined(CONFIG_BTDM_SCAN_DUPL_TYPE)
|
||||
#define CONFIG_BTDM_SCAN_DUPL_TYPE CONFIG_SCAN_DUPLICATE_TYPE
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BT_CTRL_SCAN_DUPL_TYPE) && !defined(CONFIG_BTDM_SCAN_DUPL_TYPE)
|
||||
#define CONFIG_BTDM_SCAN_DUPL_TYPE CONFIG_BT_CTRL_SCAN_DUPL_TYPE
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_DUPLICATE_SCAN_CACHE_SIZE) && !defined(CONFIG_BTDM_SCAN_DUPL_CACHE_SIZE)
|
||||
#define CONFIG_BTDM_SCAN_DUPL_CACHE_SIZE CONFIG_DUPLICATE_SCAN_CACHE_SIZE
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BT_CTRL_SCAN_DUPL_CACHE_SIZE) && !defined(CONFIG_BTDM_SCAN_DUPL_CACHE_SIZE)
|
||||
#define CONFIG_BTDM_SCAN_DUPL_CACHE_SIZE CONFIG_BT_CTRL_SCAN_DUPL_CACHE_SIZE
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_NIMBLE_MAX_CONNECTIONS ) && !defined(CONFIG_BT_NIMBLE_MAX_CONNECTIONS)
|
||||
#define CONFIG_BT_NIMBLE_MAX_CONNECTIONS CONFIG_NIMBLE_MAX_CONNECTIONS
|
||||
#endif
|
||||
Reference in New Issue
Block a user