mirror of
https://github.com/h2zero/esp-nimble-cpp.git
synced 2025-12-23 15:18:16 +01:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4786960902 | ||
|
|
507f146477 | ||
|
|
1dedff342b | ||
|
|
d47281f40f | ||
|
|
123825d483 | ||
|
|
5b206b97a3 | ||
|
|
08a3e676f8 | ||
|
|
356459d352 | ||
|
|
06e2d188b1 | ||
|
|
afb76b8cb6 | ||
|
|
56c68d7eea | ||
|
|
bceda5a8cf | ||
|
|
799a7a84db | ||
|
|
6de87945e7 | ||
|
|
dc7d9d5b73 | ||
|
|
06037f8bf6 | ||
|
|
4d78c3013b | ||
|
|
bc2e11637e | ||
|
|
8efa7d2acc | ||
|
|
bc2cecd2db |
58
.github/workflows/build.yml
vendored
58
.github/workflows/build.yml
vendored
@@ -1,58 +0,0 @@
|
||||
name: Build
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build-esp-idf-component:
|
||||
name: Build with ESP-IDF ${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
# The version names here correspond to the versions of espressif/idf Docker image.
|
||||
# See https://hub.docker.com/r/espressif/idf/tags and
|
||||
# https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-docker-image.html
|
||||
# for details.
|
||||
idf_ver: ["release-v4.4"]
|
||||
idf_target: ["esp32", "esp32s3", "esp32c3"]
|
||||
example:
|
||||
- Advanced/NimBLE_Client
|
||||
- Advanced/NimBLE_Server
|
||||
- basic/BLE_client
|
||||
- basic/BLE_notify
|
||||
- basic/BLE_scan
|
||||
- basic/BLE_server
|
||||
- basic/BLE_uart
|
||||
- Bluetooth_5/NimBLE_extended_client
|
||||
- Bluetooth_5/NimBLE_extended_server
|
||||
- Bluetooth_5/NimBLE_multi_advertiser
|
||||
exclude:
|
||||
- idf_target: "esp32"
|
||||
example: Bluetooth_5/NimBLE_extended_client
|
||||
- idf_target: "esp32"
|
||||
example: Bluetooth_5/NimBLE_extended_server
|
||||
- idf_target: "esp32"
|
||||
example: Bluetooth_5/NimBLE_multi_advertiser
|
||||
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: components/esp-nimble-cpp
|
||||
- name: Build examples
|
||||
env:
|
||||
IDF_TARGET: ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
cp -r components/esp-nimble-cpp/examples/* .
|
||||
idf.py -C ${{ matrix.example }} -DEXTRA_COMPONENT_DIRS=$PWD/components build
|
||||
|
||||
build_docs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Doxygen Action
|
||||
uses: mattnotmitt/doxygen-action@v1.9.1
|
||||
with:
|
||||
working-directory: 'docs/'
|
||||
22
.github/workflows/release.yml
vendored
22
.github/workflows/release.yml
vendored
@@ -1,22 +0,0 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build_docs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Doxygen Action
|
||||
uses: mattnotmitt/doxygen-action@v1.9.1
|
||||
with:
|
||||
working-directory: 'docs/'
|
||||
|
||||
- name: Deploy
|
||||
uses: peaceiris/actions-gh-pages@v3
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
publish_dir: ./docs/doxydocs/html
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +0,0 @@
|
||||
docs/doxydocs
|
||||
127
CHANGELOG.md
127
CHANGELOG.md
@@ -2,41 +2,6 @@
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [1.4.1] - 2022-10-30
|
||||
|
||||
### Fixed
|
||||
- NimBLEDevice::getPower incorrect value when power level is -3db.
|
||||
- Failed pairing when already in progress.
|
||||
|
||||
### Changed
|
||||
- Revert previous change that forced writing with response when subscribing in favor of allowing the application to decide.
|
||||
|
||||
### Added
|
||||
- Added NimBLEHIDDevice::batteryLevel.
|
||||
- Added NimBLEDevice::setDeviceName allowing for changing the device name while the BLE stack is active.
|
||||
- CI Builds
|
||||
|
||||
## [1.4.0] - 2022-07-31
|
||||
|
||||
### Fixed
|
||||
- Fixed missing data from long notification values.
|
||||
- Fixed NimbleCharacteristicCallbacks::onRead not being called when a non-long read command is received.
|
||||
- Prevent a potential crash when retrieving characteristics from a service if the result was successful but no characteristics found.
|
||||
- logs/typos.
|
||||
|
||||
### Changed
|
||||
- AD flags are no longer set in the advertisements of non-connectable beacons, freeing up 3 bytes of advertisement room.
|
||||
- Save resources when retrieving descriptors if the characteristic handle is the same as the end handle (no descriptors).
|
||||
- Subscribing to characteristic notifications/indications will now always use write with response, as per BLE specifications.
|
||||
- `NimBLEClient::discoverAttributes` now returns a bool value to indicate success/failure.
|
||||
- Scan result callbacks are no longer called when the scan response data is updated in order to reduce duplicates.
|
||||
|
||||
### Added
|
||||
- Preliminary support for non-esp devices, NRF51 and NRF52 devices supported with [n-able arduino core](https://github.com/h2zero/n-able-Arduino)
|
||||
- Alias added for `NimBLEServerCallbacks::onMTUChange` to `onMtuChanged` in order to support porting code from original library.
|
||||
- `NimBLEAttValue` Class added to reduce and control RAM footprint of characteristic/descriptor values and support conversions from Arduino Strings and many other data types.
|
||||
- Bluetooth 5 extended advertising support for capable devices. CODED Phy, 2M Phy, extended advertising data, and multi-advertising are supported, periodic advertising will be implemented in the future.
|
||||
|
||||
## [1.3.3] - 2022-02-15
|
||||
|
||||
### Changed
|
||||
@@ -126,7 +91,7 @@ All notable changes to this project will be documented in this file.
|
||||
|
||||
- `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.
|
||||
- `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)`
|
||||
@@ -170,10 +135,10 @@ Overloads to get a vector containing pointers to all the characteristics in a se
|
||||
|
||||
- `NimBLEAdvertising` Custom scan response data can now be used without custom advertisment.
|
||||
|
||||
- `NimBLEScan` Now uses the controller duplicate filter.
|
||||
- `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.
|
||||
- `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.
|
||||
@@ -182,84 +147,84 @@ Instead the data will be parsed on-demand when the user application asks for spe
|
||||
## [1.1.0] - 2021-01-20
|
||||
|
||||
### Added
|
||||
- `NimBLEDevice::setOwnAddrType` added to enable the use of random and random-resolvable addresses, by asukiaaa
|
||||
- `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.
|
||||
- New examples for securing and authenticating client/server connections, by mblasee.
|
||||
|
||||
- `NimBLEAdvertising::SetMinPreferred` and `NimBLEAdvertising::SetMinPreferred` re-added.
|
||||
- `NimBLEAdvertising::SetMinPreferred` and `NimBLEAdvertising::SetMinPreferred` re-added.
|
||||
|
||||
- Conditional checks added for command line config options in `nimconfig.h` to support custom configuration in platformio.
|
||||
- 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::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.
|
||||
- `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.
|
||||
- `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.
|
||||
- `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.
|
||||
- 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.
|
||||
- `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.
|
||||
- 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.
|
||||
- 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.
|
||||
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.
|
||||
- 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.
|
||||
- `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.
|
||||
- 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.
|
||||
- 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 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.
|
||||
|
||||
- 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.
|
||||
- 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.
|
||||
|
||||
- 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.
|
||||
- Multiple instances of `time()` called inside critical sections caused sporadic crashes, these have been moved out of critical regions.
|
||||
|
||||
- Occasionally the call to start scanning would get stuck in a loop on BLE_HS_EBUSY, this loop has been removed.
|
||||
- Advertisement type now correctly set when using non-connectable (advertiser only) mode.
|
||||
|
||||
- 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.
|
||||
- Advertising payload length correction, now accounts for appearance.
|
||||
|
||||
- `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.
|
||||
- (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
|
||||
- `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
|
||||
- (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.
|
||||
|
||||
|
||||
|
||||
@@ -12,6 +12,10 @@ elseif("nimble" IN_LIST BUILD_COMPONENTS OR "__nimble" IN_LIST __hack_component_
|
||||
list(APPEND ESP_NIMBLE_PRIV_REQUIRES
|
||||
nimble
|
||||
)
|
||||
elseif("bt" IN_LIST BUILD_COMPONENTS OR "__bt" IN_LIST __hack_component_targets)
|
||||
list(APPEND ESP_NIMBLE_PRIV_REQUIRES
|
||||
bt
|
||||
)
|
||||
endif()
|
||||
|
||||
if("arduino" IN_LIST BUILD_COMPONENTS OR __hack_component_targets MATCHES "__idf_arduino")
|
||||
@@ -20,15 +24,7 @@ if("arduino" IN_LIST BUILD_COMPONENTS OR __hack_component_targets MATCHES "__idf
|
||||
)
|
||||
endif()
|
||||
|
||||
idf_component_register(
|
||||
REQUIRED_IDF_TARGETS
|
||||
"esp32"
|
||||
"esp32s3"
|
||||
"esp32c3"
|
||||
INCLUDE_DIRS
|
||||
"src"
|
||||
SRCS
|
||||
"src/NimBLE2904.cpp"
|
||||
set(srcs "src/NimBLE2904.cpp"
|
||||
"src/NimBLEAddress.cpp"
|
||||
"src/NimBLEAdvertisedDevice.cpp"
|
||||
"src/NimBLEAdvertising.cpp"
|
||||
@@ -49,7 +45,28 @@ idf_component_register(
|
||||
"src/NimBLEServer.cpp"
|
||||
"src/NimBLEService.cpp"
|
||||
"src/NimBLEUtils.cpp"
|
||||
"src/NimBLEUUID.cpp"
|
||||
"src/NimBLEUUID.cpp")
|
||||
|
||||
if(CONFIG_BT_NIMBLE_MESH)
|
||||
list(APPEND srcs "src/NimBLEMeshCreateModel.c"
|
||||
"src/NimBLEMeshElement.cpp"
|
||||
"src/NimBLEMeshModel.cpp"
|
||||
"src/NimBLEMeshNode.cpp")
|
||||
endif()
|
||||
|
||||
if(CONFIG_NIMBLE_CPP_PERSIST_MESH_SETTINGS)
|
||||
list(APPEND srcs "src/mesh_config_store/config/config_store.c")
|
||||
endif()
|
||||
|
||||
idf_component_register(
|
||||
REQUIRED_IDF_TARGETS
|
||||
"esp32"
|
||||
"esp32s3"
|
||||
"esp32c3"
|
||||
INCLUDE_DIRS
|
||||
"src"
|
||||
SRCS "${srcs}"
|
||||
|
||||
REQUIRES
|
||||
bt
|
||||
nvs_flash
|
||||
@@ -57,3 +74,7 @@ idf_component_register(
|
||||
${ESP_NIMBLE_PRIV_REQUIRES}
|
||||
)
|
||||
|
||||
if(CONFIG_BT_NIMBLE_MESH AND CONFIG_NIMBLE_CPP_PERSIST_MESH_SETTINGS)
|
||||
idf_build_set_property(COMPILE_OPTIONS "-DMYNEWT_VAL_BLE_MESH_SETTINGS=1" APPEND)
|
||||
idf_build_set_property(COMPILE_OPTIONS "-I${COMPONENT_DIR}/src/mesh_config_store" APPEND)
|
||||
endif()
|
||||
|
||||
16
Kconfig
16
Kconfig
@@ -33,7 +33,7 @@ config NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT
|
||||
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"
|
||||
@@ -42,12 +42,12 @@ config NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT
|
||||
messages in the debug log. This will use approximately 1kB
|
||||
of flash memory.
|
||||
|
||||
config NIMBLE_CPP_ENABLE_ADVERTISEMENT_TYPE_TEXT
|
||||
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.
|
||||
while scanning as text messages in the debug log.
|
||||
This will use approximately 250 bytes of flash memory.
|
||||
|
||||
config NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
|
||||
@@ -68,5 +68,13 @@ config NIMBLE_CPP_ATT_VALUE_INIT_LENGTH
|
||||
when the constructor is called. This is also the size used when a remote
|
||||
characteristic or descriptor is constructed before a value is read/notifed.
|
||||
Increasing this will reduce reallocations but increase memory footprint.
|
||||
|
||||
|
||||
config NIMBLE_CPP_PERSIST_MESH_SETTINGS
|
||||
bool "Enable persistent storage of mesh config settings."
|
||||
default "n"
|
||||
depends on BT_NIMBLE_MESH
|
||||
help
|
||||
Enabling this option will store the provisioning and app key settings
|
||||
in non-volatile storage when using NimBLE Mesh.
|
||||
|
||||
endmenu
|
||||
|
||||
@@ -7,11 +7,12 @@ Extended advertising allows for much more capability and flexibility.
|
||||
|
||||
* New PHY's (physical layers) that allow for faster data rate (2M PHY) or long range/slower data rates (CODED PHY) as well as the original 1M PHY.
|
||||
|
||||
* New periodic advertising, allowing the scanning device to sync with the advertisements of a beacon. This allows for the scanning device to sleep or perform other tasks before the next expected advertisement is sent, preserving cpu cycles and power (To be implemented).
|
||||
<br/>
|
||||
* New periodic advertising, allowing the scanning device to sync with the advertisements of a beacon. This allows for the scanning device to sleep or perform other tasks before the next expected advertisement is sent, preserving cpu cycles and power (To be implemented).
|
||||
<br>
|
||||
|
||||
## Enabling extended advertising
|
||||
Extended advertising is supported when enabled with the config option `CONFIG_BT_NIMBLE_EXT_ADV` set to a value of 1. This is done in menuconfig under `Component config > Bluetooth > NimBLE options > Enable extended advertising`, or set in `nimconfig.h` for Arduino, or in `build_flags` in PlatformIO.
|
||||
Extended advertising is supported when enabled with the config option `CONFIG_BT_NIMBLE_EXT_ADV` set to a value of 1. This is done in menuconfig under `Component config > Bluetooth > NimBLE options >
|
||||
Enable extended advertising`.
|
||||
|
||||
When enabled the following will occur:
|
||||
* `NimBLEScan::start` method will scan on both the 1M PHY and the coded PHY standards automatically.
|
||||
|
||||
142
docs/Command_line_config.md
Normal file
142
docs/Command_line_config.md
Normal file
@@ -0,0 +1,142 @@
|
||||
# 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_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED`
|
||||
|
||||
Enable/disable storing the timestamp when an attribute value is updated
|
||||
This allows for checking the last update time using getTimeStamp() or getValue(time_t*)
|
||||
If disabled, the timestamp returned from these functions will be 0.
|
||||
Disabling timestamps will reduce the memory used for each value.
|
||||
1 = Enabled, 0 = Disabled; Default = Disabled
|
||||
<br/>
|
||||
|
||||
`CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH`
|
||||
|
||||
Set the default allocation size (bytes) for each attribute.
|
||||
If not specified when the constructor is called. This is also the size used when a remote
|
||||
characteristic or descriptor is constructed before a value is read/notifed.
|
||||
Increasing this will reduce reallocations but increase memory footprint.
|
||||
Default value is 20. Range: 1 : 512 (BLE_ATT_ATTR_MAX_LEN)
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_ATT_PREFERRED_MTU`
|
||||
|
||||
Sets the default MTU size.
|
||||
- Default value is 255
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_SVC_GAP_DEVICE_NAME`
|
||||
|
||||
Set the default device name
|
||||
- Default value is "nimble"
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_DEBUG`
|
||||
|
||||
If defined, enables debug log messages from the NimBLE host
|
||||
- Uses approx. 32kB of flash memory.
|
||||
<br/>
|
||||
|
||||
`CONFIG_NIMBLE_CPP_LOG_LEVEL`
|
||||
|
||||
Define to set the debug log message level from the NimBLE CPP Wrapper.
|
||||
If not defined it will use the same value as the Arduino core debug level.
|
||||
Values: 0 = NONE, 1 = ERROR, 2 = WARNING, 3 = INFO, 4+ = DEBUG
|
||||
<br/>
|
||||
|
||||
`CONFIG_NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT`
|
||||
|
||||
If defined, NimBLE host return codes will be printed as text in debug log messages.
|
||||
- Uses approx. 7kB of flash memory.
|
||||
<br/>
|
||||
|
||||
`CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT`
|
||||
|
||||
If defined, GAP event codes will be printed as text in debug log messages.
|
||||
- Uses approx. 1kB of flash memory.
|
||||
<br/>
|
||||
|
||||
`CONFIG_NIMBLE_CPP_ENABLE_ADVERTISMENT_TYPE_TEXT`
|
||||
|
||||
If defined, advertisment types will be printed as text while scanning in debug log messages.
|
||||
- Uses approx. 250 bytes of flash memory.
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_SVC_GAP_APPEARANCE`
|
||||
|
||||
Set the default appearance.
|
||||
- Default value is 0x00
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_ROLE_CENTRAL_DISABLED`
|
||||
|
||||
If defined, NimBLE Client functions will not be included.
|
||||
- Reduces flash size by approx. 7kB.
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_ROLE_OBSERVER_DISABLED`
|
||||
|
||||
If defined, NimBLE Scan functions will not be included.
|
||||
- Reduces flash size by approx. 26kB.
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_ROLE_PERIPHERAL_DISABLED`
|
||||
|
||||
If defined NimBLE Server functions will not be included.
|
||||
- Reduces flash size by approx. 16kB.
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_ROLE_BROADCASTER_DISABLED`
|
||||
|
||||
If defined, NimBLE Advertising functions will not be included.
|
||||
- Reduces flash size by approx. 5kB.
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_MAX_BONDS`
|
||||
|
||||
Sets the number of devices allowed to store/bond with
|
||||
- Default value is 3
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_MAX_CCCDS`
|
||||
|
||||
Sets the maximum number of CCCD subscriptions to store
|
||||
- Default value is 8
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_RPA_TIMEOUT`
|
||||
|
||||
Sets the random address refresh time in seconds.
|
||||
- Default value is 900
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_MSYS1_BLOCK_COUNT`
|
||||
|
||||
Set the number of msys blocks For prepare write & prepare responses. This may need to be increased if
|
||||
you are sending large blocks of data with a low MTU. E.g: 512 bytes with 23 MTU will fail.
|
||||
- Default value is 12
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL`
|
||||
|
||||
Sets the NimBLE stack to use external PSRAM will be loaded
|
||||
- Must be defined with a value of 1; Default is CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_INTERNAL 1
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_PINNED_TO_CORE`
|
||||
|
||||
Sets the core the NimBLE host stack will run on
|
||||
- Options: 0 or 1
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_TASK_STACK_SIZE`
|
||||
|
||||
Set the task stack size for the NimBLE core.
|
||||
- Default is 4096
|
||||
<br/>
|
||||
|
||||
@@ -38,7 +38,7 @@ PROJECT_NAME = esp-nimble-cpp
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER = 1.4.1
|
||||
PROJECT_NUMBER = 1.3.2
|
||||
|
||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||
# for a project that appears at the top of each page and should give viewer a
|
||||
@@ -58,7 +58,7 @@ PROJECT_LOGO =
|
||||
# entered, it will be relative to the location where doxygen was started. If
|
||||
# left blank the current directory will be used.
|
||||
|
||||
OUTPUT_DIRECTORY = doxydocs
|
||||
OUTPUT_DIRECTORY = .
|
||||
|
||||
# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
|
||||
# directories (in 2 levels) under the output directory of each output format and
|
||||
@@ -836,7 +836,7 @@ WARN_NO_PARAMDOC = NO
|
||||
# Possible values are: NO, YES and FAIL_ON_WARNINGS.
|
||||
# The default value is: NO.
|
||||
|
||||
WARN_AS_ERROR = YES
|
||||
WARN_AS_ERROR = NO
|
||||
|
||||
# The WARN_FORMAT tag determines the format of the warning messages that doxygen
|
||||
# can produce. The string should contain the $file, $line, and $text tags, which
|
||||
@@ -2267,8 +2267,7 @@ PREDEFINED = _DOXYGEN_ \
|
||||
CONFIG_BT_NIMBLE_ROLE_CENTRAL \
|
||||
CONFIG_BT_NIMBLE_ROLE_OBSERVER \
|
||||
CONFIG_BT_NIMBLE_ROLE_PERIPHERAL \
|
||||
CONFIG_BT_NIMBLE_ROLE_BROADCASTER \
|
||||
CONFIG_BT_NIMBLE_EXT_ADV
|
||||
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
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# Improvements and updates
|
||||
|
||||
Many improvements have been made to this library vs the original, this is a brief overview of the most significant changes. Refer to the [class documentation](https://h2zero.github.io/esp-nimble-cpp/annotated.html) for further information on class specifics.
|
||||
Many improvements have been made to this library vs the original, this is a brief overview of the most significant changes.
|
||||
Refer to the [class documentation](https://h2zero.github.io/esp-nimble-cpp/annotated.html) for futher information on class specifics.
|
||||
|
||||
* [Server](#server)
|
||||
* [Advertising](#advertising)
|
||||
@@ -9,26 +10,23 @@ Many improvements have been made to this library vs the original, this is a brie
|
||||
<br/>
|
||||
|
||||
<a name="server"></a>
|
||||
# Server
|
||||
# Server
|
||||
|
||||
`NimBLEService::NimBLEService::createCharacteristic` takes a 3rd parameter to specify the maximum data size that can be stored by the characteristic. This allows for limiting the RAM use of the characteristic in cases where small amounts of data are expected.
|
||||
<br/>
|
||||
`NimBLECharacteristic::setValue(const T &s)`
|
||||
`NimBLEDescriptor::setValue(const T &s)`
|
||||
|
||||
`NimBLECharacteristic::setValue(const T &s)`
|
||||
`NimBLEDescriptor::setValue(const T &s)`
|
||||
|
||||
Now use the `NimbleAttValue` class and templates to accommodate standard and custom types/values.
|
||||
Now use a template to accomodate standard and custom types/values.
|
||||
|
||||
**Example**
|
||||
```
|
||||
struct my_struct {
|
||||
struct my_struct{
|
||||
uint8_t one;
|
||||
uint16_t two;
|
||||
uint32_t four;
|
||||
uint64_t eight;
|
||||
float flt;
|
||||
} myStruct;
|
||||
|
||||
}myStruct;
|
||||
|
||||
myStruct.one = 1;
|
||||
myStruct.two = 2;
|
||||
myStruct.four = 4;
|
||||
@@ -36,14 +34,12 @@ struct my_struct {
|
||||
myStruct.flt = 1234.56;
|
||||
|
||||
pCharacteristic->setValue(myStruct);
|
||||
|
||||
// Arduino String support
|
||||
String myString = "Hello";
|
||||
pCharacteristic->setValue(myString);
|
||||
```
|
||||
This will send the struct to the receiving client when read or a notification sent.
|
||||
This will send the struct to the recieving client when read or a notification sent.
|
||||
|
||||
`NimBLECharacteristic::getValue` now takes an optional timestamp parameter which will update it's value with the time the last value was received. In addition an overloaded template has been added to retrieve the value as a type specified by the user.
|
||||
`NimBLECharacteristic::getValue` now takes an optional timestamp parameter which will update it's value with
|
||||
the time the last value was recieved. In addition an overloaded template has been added to retrieve the value
|
||||
as a type specified by the user.
|
||||
|
||||
**Example**
|
||||
```
|
||||
@@ -52,34 +48,38 @@ This will send the struct to the receiving client when read or a notification se
|
||||
```
|
||||
<br/>
|
||||
|
||||
**Advertising will automatically start when a client disconnects.**
|
||||
**Advertising will automatically start when a client disconnects.**
|
||||
|
||||
A new method `NimBLEServer::advertiseOnDisconnect(bool)` has been implemented to control this, true(default) = enabled.
|
||||
<br/>
|
||||
|
||||
`NimBLEServer::removeService` takes an additional parameter `bool deleteSvc` that if true will delete the service and all characteristics / descriptors belonging to it and invalidating any pointers to them.
|
||||
`NimBLEServer::removeService` takes an additional parameter `bool deleteSvc` that if true will delete the service
|
||||
and all characteristics / descriptors belonging to it and invalidating any pointers to them.
|
||||
|
||||
If false the service is only removed from visibility by clients. The pointers to the service and it's characteristics / descriptors will remain valid and the service can be re-added in the future using `NimBLEServer::addService`.
|
||||
If false the service is only removed from visibility by clients. The pointers to the service and
|
||||
it's characteristics / descriptors will remain valid and the service can be re-added in the future
|
||||
using `NimBLEServer::addService`.
|
||||
<br/>
|
||||
|
||||
<a name="advertising"></a>
|
||||
# Advertising
|
||||
`NimBLEAdvertising::start`
|
||||
|
||||
Now takes 2 optional parameters, the first is the duration to advertise for (in seconds), the second is a callback that is invoked when advertising ends and takes a pointer to a `NimBLEAdvertising` object (similar to the `NimBLEScan::start` API).
|
||||
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 advertisement data if desired.
|
||||
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/>
|
||||
Also now returns a bool value to indicate if advertising successfully started or not.
|
||||
<br/>
|
||||
|
||||
<a name="client"></a>
|
||||
# Client
|
||||
# Client
|
||||
|
||||
`NimBLERemoteCharacteristic::readValue(time_t\*, bool)`
|
||||
`NimBLERemoteDescriptor::readValue(bool)`
|
||||
`NimBLERemoteCharacteristic::readValue(time_t\*, bool)`
|
||||
`NimBLERemoteDescriptor::readValue(bool)`
|
||||
|
||||
Have been added as templates to allow reading the values as any specified type.
|
||||
Have been added as templates to allow reading the values as any specified type.
|
||||
|
||||
**Example**
|
||||
```
|
||||
@@ -93,56 +93,56 @@ struct my_struct{
|
||||
|
||||
time_t timestamp;
|
||||
myStruct = pRemoteCharacteristic->readValue<myStruct>(×tamp); // timestamp optional
|
||||
```
|
||||
```
|
||||
<br/>
|
||||
|
||||
`NimBLERemoteCharacteristic::registerForNotify`
|
||||
Has been **deprecated** as now the internally stored characteristic value is updated when notification/indication is received.
|
||||
`NimBLERemoteCharacteristic::registerForNotify`
|
||||
Has been **deprecated** as now the internally stored characteristic value is updated when notification/indication is recieved.
|
||||
|
||||
`NimBLERemoteCharacteristic::subscribe` and `NimBLERemoteCharacteristic::unsubscribe` have been implemented to replace it.
|
||||
A callback is no longer required 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/>
|
||||
`NimBLERemoteCharacteristic::subscribe` and `NimBLERemoteCharacteristic::unsubscribe` have been implemented to replace it.
|
||||
A callback is no longer requred to get the most recent value unless timing is important. Instead, the application can call `NimBLERemoteCharacteristic::getValue` to
|
||||
get the last updated value any time.
|
||||
<br/>
|
||||
|
||||
The `notify_callback` function is now defined as a `std::function` to take advantage of using `std::bind` to specify a class member function for the callback.
|
||||
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:
|
||||
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 received.
|
||||
`NimBLERemoteCharacteristic::readValue` and `NimBLERemoteCharacteristic::getValue` take an optional timestamp parameter which will update it's value with
|
||||
the time the last value was recieved.
|
||||
|
||||
> NimBLEClient::getService
|
||||
> NimBLERemoteService::getCharacteristic
|
||||
> NimBLERemoteCharacteristic::getDescriptor
|
||||
> NimBLERemoteCharacteristic::getDescriptor
|
||||
|
||||
These methods will now check the respective vectors for the attribute object and, if not found, will retrieve (only)
|
||||
the specified attribute from the peripheral.
|
||||
These methods will now check the respective vectors for the attribute object and, if not found, will retrieve (only)
|
||||
the specified attribute from the peripheral.
|
||||
|
||||
These changes allow more control for the user to manage the resources used for the attributes.
|
||||
These changes allow more control for the user to manage the resources used for the attributes.
|
||||
<br/>
|
||||
|
||||
`NimBLEClient::connect()` can now be called without an address or advertised device parameter. This will connect to the device with the address previously set when last connected or set with `NimBLEDevice::setPeerAddress()`.
|
||||
`NimBLEClient::connect()` can now be called without an address or advertised device parameter. This will connect to the
|
||||
device with the address previously set when last connected or set with `NimBLEDevice::setPeerAddress()`.
|
||||
|
||||
<a name="general"></a>
|
||||
# General
|
||||
To reduce resource use all instances of `std::map` have been replaced with `std::vector`.
|
||||
# General
|
||||
To reduce resource use all instances of `std::map` have been replaced with `std::vector`.
|
||||
|
||||
Use of `FreeRTOS::Semaphore` has been removed as it was consuming too much ram, the related files have been left in place to accomodate application use.
|
||||
Use of `FreeRTOS::Semaphore` has been removed as it was consuming too much ram, the related files have been left in place to accomodate application use.
|
||||
|
||||
Operators `==`, `!=` and `std::string` have been added to `NimBLEAddress` and `NimBLEUUID` for easier comparison and logging.
|
||||
Operators `==`, `!=` and `std::string` have been added to `NimBLEAddress` and `NimBLEUUID` for easier comparison and logging.
|
||||
|
||||
New constructor for `NimBLEUUID(uint32_t, uint16_t, uint16_t, uint64_t)` added to lower memory use vs string construction. See: [#21](https://github.com/h2zero/NimBLE-Arduino/pull/21).
|
||||
New constructor for `NimBLEUUID(uint32_t, uint16_t, uint16_t, uint64_t)` added to lower memory use vs string construction. See: [#21](https://github.com/h2zero/NimBLE-Arduino/pull/21).
|
||||
|
||||
Security/pairing operations are now handled in the respective `NimBLEClientCallbacks` and `NimBLEServerCallbacks` classes, `NimBLESecurity`(deprecated) remains for backward compatibility.
|
||||
Security/pairing operations are now handled in the respective `NimBLEClientCallbacks` and `NimBLEServerCallbacks` classes, `NimBLESecurity`(deprecated) remains for backward compatibility.
|
||||
|
||||
Configuration options have been added to add or remove debugging information, when disabled (default) significantly reduces binary size.
|
||||
Configuration options have been added to add or remove debugging information, when disabled (default) significatly reduces binary size.
|
||||
In ESP-IDF the options are in menuconfig: `Main menu -> ESP-NimBLE-cpp configuration`.
|
||||
For Arduino the options must be commented / uncommented in nimconfig.h.
|
||||
|
||||
Characteristics and descriptors now use the `NimBLEAttValue` class to store their data. This is a polymorphic container class capable of converting to/from many different types efficiently. See: [#286](https://github.com/h2zero/NimBLE-Arduino/pull/286)
|
||||
For Arduino the options must be commented / uncommented in nimconfig.h.
|
||||
<br/>
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# Migrating from Bluedroid to NimBLE
|
||||
|
||||
This guide describes the required changes to existing projects migrating from the original bluedroid API to NimBLE.
|
||||
This guide describes the required changes to existing projects migrating from the original bluedroid API to NimBLE.
|
||||
|
||||
**The changes listed here are only the required changes that must be made**, and a short overview of options for migrating existing applications.
|
||||
**The changes listed here are only the required changes that must be made**, and a short overview of options for migrating existing applications.
|
||||
|
||||
For more information on the improvements and additions please refer to the [class documentation](https://h2zero.github.io/NimBLE-Arduino/annotated.html) and [Improvements and updates](Improvements_and_updates.md)
|
||||
For more information on the improvements and additions please refer to the [class documentation](https://h2zero.github.io/esp-nimble-cpp/annotated.html) and [Improvements and updates](Improvements_and_updates.md)
|
||||
|
||||
* [General Changes](#general-information)
|
||||
* [Server](#server-api)
|
||||
@@ -19,78 +19,82 @@ For more information on the improvements and additions please refer to the [clas
|
||||
* [Security](#client-security)
|
||||
* [General Security](#security-api)
|
||||
* [Configuration](#arduino-configuration)
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<a name="general-information"></a>
|
||||
## General Information
|
||||
|
||||
### Header Files
|
||||
All classes are accessible by including `NimBLEDevice.h` in your application, no further headers need to be included.
|
||||
All classes are accessible by including `NimBLEDevice.h` in your application, no further headers need to be included.
|
||||
|
||||
(Mainly for Arduino) You may choose to include `NimBLELog.h` in your application if you want to use the `NIMBLE_LOGx` macros for debugging. These macros are used the same way as the `ESP_LOGx` macros.
|
||||
(Mainly for Arduino) You may choose to include `NimBLELog.h` in your appplication if you want to use the `NIMBLE_LOGx` macros for debugging.
|
||||
These macros are used the same way as the `ESP_LOGx` macros.
|
||||
<br/>
|
||||
|
||||
### Class Names
|
||||
Class names remain the same as the original with the addition of a "Nim" prefix.
|
||||
For example `BLEDevice` is now `NimBLEDevice` and `BLEServer` is now `NimBLEServer` etc.
|
||||
Class names remain the same as the original with the addition of a "Nim" prefix.
|
||||
For example `BLEDevice` is now `NimBLEDevice` and `BLEServer` is now `NimBLEServer` etc.
|
||||
|
||||
For convenience definitions have been added to allow applications to use either name for all classes this means **no class names need to be changed in existing code** and makes migrating easier.
|
||||
For convienience definitions have been added to allow applications to use either name for all classes
|
||||
this means **no class names need to be changed in existing code** and makes migrating easier.
|
||||
<br/>
|
||||
|
||||
### BLE Addresses
|
||||
`BLEAddress` (`NimBLEAddress`) When constructing an address the constructor now takes an *(optional)* `uint8_t type` parameter to specify the address type. Default is (0) Public static address.
|
||||
`BLEAddress` (`NimBLEAddress`) When constructing an address the constructor now takes an *(optional)* `uint8_t type` paramameter
|
||||
to specify the address type. Default is (0) Public static address.
|
||||
|
||||
For example `BLEAddress addr(11:22:33:44:55:66, 1)` will create the address object with an address type of: 1 (Random).
|
||||
For example `BLEAddress addr(11:22:33:44:55:66, 1)` will create the address object with an address type of: 1 (Random).
|
||||
|
||||
As this parameter is optional no changes to existing code are needed, it is mentioned here for information.
|
||||
|
||||
`BLEAddress::getNative` (`NimBLEAddress::getNative`) returns a uint8_t pointer to the native address byte array. In this library the address bytes are stored in reverse order from the original library. This is due to the way the NimBLE stack expects addresses to be presented to it. All other functions such as `toString` are
|
||||
not affected as the endian change is made within them.
|
||||
As this paramameter is optional no changes to existing code are needed, it is mentioned here for information.
|
||||
<br/>
|
||||
`BLEAddress::getNative` (`NimBLEAddress::getNative`) returns a uint8_t pointer to the native address byte array.
|
||||
In this library the address bytes are stored in reverse order from the original library. This is due to the way
|
||||
the NimBLE stack expects addresses to be presented to it. All other functions such as `toString` are
|
||||
not affected as the endian change is made within them.
|
||||
<br/>
|
||||
|
||||
<a name="server-api"></a>
|
||||
## Server API
|
||||
Creating a `BLEServer` instance is the same as original, no changes required.
|
||||
For example `BLEDevice::createServer()` will work just as it did before.
|
||||
For example `BLEDevice::createServer()` will work just as it did before.
|
||||
|
||||
`BLEServerCallbacks` (`NimBLEServerCallbacks`) has new methods for handling security operations.
|
||||
**Note:** All callback methods have default implementations which allows the application to implement only the methods applicable.
|
||||
`BLEServerCallbacks` (`NimBLEServerCallbacks`) has new methods for handling security operations.
|
||||
**Note:** All callback methods have default implementations which allows the application to implement only the methods applicable.
|
||||
<br/>
|
||||
|
||||
<a name="services"></a>
|
||||
### Services
|
||||
Creating a `BLEService` (`NimBLEService`) instance is the same as original, no changes required.
|
||||
For example `BLEServer::createService(SERVICE_UUID)` will work just as it did before.
|
||||
Creating a `BLEService` (`NimBLEService`) instance is the same as original, no changes required.
|
||||
For example `BLEServer::createService(SERVICE_UUID)` will work just as it did before.
|
||||
|
||||
<a name="characteristics"></a>
|
||||
### Characteristics
|
||||
`BLEService::createCharacteristic` (`NimBLEService::createCharacteristic`) is used the same way as originally except the properties parameter has changed.
|
||||
`BLEService::createCharacteristic` (`NimBLEService::createCharacteristic`) is used the same way as originally except the properties parameter has changed.
|
||||
|
||||
When creating a characteristic the properties are now set with `NIMBLE_PROPERTY::XXXX` instead of `BLECharacteristic::XXXX`.
|
||||
|
||||
#### Originally
|
||||
> BLECharacteristic::PROPERTY_READ |
|
||||
> BLECharacteristic::PROPERTY_WRITE
|
||||
> BLECharacteristic::PROPERTY_READ |
|
||||
> BLECharacteristic::PROPERTY_WRITE
|
||||
|
||||
#### Is Now
|
||||
> NIMBLE_PROPERTY::READ |
|
||||
> NIMBLE_PROPERTY::WRITE
|
||||
> NIMBLE_PROPERTY::READ |
|
||||
> NIMBLE_PROPERTY::WRITE
|
||||
<br/>
|
||||
|
||||
#### The full list of properties
|
||||
> NIMBLE_PROPERTY::READ
|
||||
> NIMBLE_PROPERTY::READ_ENC
|
||||
> NIMBLE_PROPERTY::READ_AUTHEN
|
||||
> NIMBLE_PROPERTY::READ_AUTHOR
|
||||
> NIMBLE_PROPERTY::WRITE
|
||||
> NIMBLE_PROPERTY::WRITE_NR
|
||||
> NIMBLE_PROPERTY::WRITE_ENC
|
||||
> NIMBLE_PROPERTY::WRITE_AUTHEN
|
||||
> NIMBLE_PROPERTY::WRITE_AUTHOR
|
||||
> NIMBLE_PROPERTY::BROADCAST
|
||||
> NIMBLE_PROPERTY::NOTIFY
|
||||
> NIMBLE_PROPERTY::INDICATE
|
||||
|
||||
> NIMBLE_PROPERTY::READ
|
||||
> NIMBLE_PROPERTY::READ_ENC
|
||||
> NIMBLE_PROPERTY::READ_AUTHEN
|
||||
> NIMBLE_PROPERTY::READ_AUTHOR
|
||||
> NIMBLE_PROPERTY::WRITE
|
||||
> NIMBLE_PROPERTY::WRITE_NR
|
||||
> NIMBLE_PROPERTY::WRITE_ENC
|
||||
> NIMBLE_PROPERTY::WRITE_AUTHEN
|
||||
> NIMBLE_PROPERTY::WRITE_AUTHOR
|
||||
> NIMBLE_PROPERTY::BROADCAST
|
||||
> NIMBLE_PROPERTY::NOTIFY
|
||||
> NIMBLE_PROPERTY::INDICATE
|
||||
<br/>
|
||||
|
||||
**Example:**
|
||||
@@ -98,7 +102,7 @@ When creating a characteristic the properties are now set with `NIMBLE_PROPERTY:
|
||||
BLECharacteristic *pCharacteristic = pService->createCharacteristic(
|
||||
CHARACTERISTIC_UUID,
|
||||
BLECharacteristic::PROPERTY_READ |
|
||||
BLECharacteristic::PROPERTY_WRITE
|
||||
BLECharacteristic::PROPERTY_WRITE
|
||||
);
|
||||
|
||||
```
|
||||
@@ -107,22 +111,23 @@ Needs to be changed to:
|
||||
BLECharacteristic *pCharacteristic = pService->createCharacteristic(
|
||||
CHARACTERISTIC_UUID,
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE
|
||||
NIMBLE_PROPERTY::WRITE
|
||||
);
|
||||
```
|
||||
<br/>
|
||||
|
||||
`BLECharacteristicCallbacks` (`NimBLECharacteristicCallbacks`) has a new method `NimBLECharacteristicCallbacks::onSubscribe` which is called when a client subscribes to notifications/indications.
|
||||
`BLECharacteristicCallbacks` (`NimBLECharacteristicCallbacks`) has a new method `NimBLECharacteristicCallbacks::onSubscribe`
|
||||
which is called when a client subscribes to notifications/indications.
|
||||
|
||||
**Note:** All callback methods have default implementations which allows the application to implement only the methods applicable.
|
||||
**Note:** All callback methods have default implementations which allows the application to implement only the methods applicable.
|
||||
<br/>
|
||||
|
||||
> BLECharacteristic::getData
|
||||
> BLECharacteristic::getData
|
||||
|
||||
**Has been removed from the API.**
|
||||
Originally this returned a `uint8_t*` to the internal data, which is volatile.
|
||||
To prevent possibly throwing exceptions this has been removed and `NimBLECharacteristic::getValue` should be used
|
||||
to get a copy of the data first which can then safely be accessed via pointer.
|
||||
**Has been removed from the API.**
|
||||
Originally this returned a `uint8_t*` to the internal data, which is volatile.
|
||||
To prevent possibly throwing exceptions this has been removed and `NimBLECharacteristic::getValue` should be used
|
||||
to get a copy of the data first which can then safely be accessed via pointer.
|
||||
|
||||
**Example:**
|
||||
```
|
||||
@@ -137,47 +142,48 @@ my_struct_t myStruct = pChr->getValue<my_struct_t>();
|
||||
|
||||
<a name="descriptors"></a>
|
||||
### Descriptors
|
||||
The previous method `BLECharacteristic::addDescriptor()` has been removed.
|
||||
|
||||
Descriptors are now created using the `NimBLECharacteristic::createDescriptor` method.
|
||||
|
||||
BLE2902 or NimBLE2902 class has been removed.
|
||||
NimBLE automatically creates the 0x2902 descriptor if a characteristic has a notification or indication property assigned to it.
|
||||
|
||||
BLE2902 or NimBLE2902 class has been removed.
|
||||
NimBLE automatically creates the 0x2902 descriptor if a characteristic has a notification or indication property assigned to it.
|
||||
It was no longer useful to have a class for the 0x2902 descriptor as a new callback `NimBLECharacteristicCallbacks::onSubscribe` was added
|
||||
to handle callback functionality and the client subscription status is handled internally.
|
||||
|
||||
It was no longer useful to have a class for the 0x2902 descriptor as a new callback `NimBLECharacteristicCallbacks::onSubscribe` was added
|
||||
to handle callback functionality and the client subscription status is handled internally.
|
||||
|
||||
**Note:** Attempting to create a 0x2902 descriptor will trigger an assert to notify the error,
|
||||
**Note:** Attempting to create a 0x2902 descriptor will trigger an assert to notify the error,
|
||||
allowing the creation of it would cause a fault in the NimBLE stack.
|
||||
|
||||
All other descriptors are now created just as characteristics are by using the `NimBLECharacteristic::createDescriptor` method (except 0x2904, see below).
|
||||
All other descriptors are now created just as characteristics are by using the `NimBLECharacteristic::createDescriptor` method (except 0x2904, see below).
|
||||
Which are defined as:
|
||||
```
|
||||
NimBLEDescriptor* createDescriptor(const char* uuid,
|
||||
uint32_t properties =
|
||||
uint32_t properties =
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE,
|
||||
uint16_t max_len = 100);
|
||||
|
||||
|
||||
NimBLEDescriptor* createDescriptor(NimBLEUUID uuid,
|
||||
uint32_t properties =
|
||||
uint32_t properties =
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE,
|
||||
uint16_t max_len = 100);
|
||||
```
|
||||
##### Example
|
||||
```
|
||||
pDescriptor = pCharacteristic->createDescriptor("ABCD",
|
||||
NIMBLE_PROPERTY::READ |
|
||||
pDescriptor = pCharacteristic->createDescriptor("ABCD",
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE |
|
||||
NIMBLE_PROPERTY::WRITE_ENC,
|
||||
25);
|
||||
```
|
||||
Would create a descriptor with the UUID 0xABCD, publicly readable but only writable if paired/bonded (encrypted) and has a max value length of 25 bytes.
|
||||
Would create a descriptor with the UUID 0xABCD, publicly readable but only writable if paired/bonded (encrypted) and has a max value length of 25 bytes.
|
||||
<br/>
|
||||
|
||||
For the 0x2904, there is a special class that is created when you call `createDescriptor("2904").
|
||||
|
||||
The pointer returned is of the base class `NimBLEDescriptor` but the call will create the derived class of `NimBLE2904` so you must cast the returned pointer to
|
||||
The pointer returned is of the base class `NimBLEDescriptor` but the call will create the derived class of `NimBLE2904` so you must cast the returned pointer to
|
||||
`NimBLE2904` to access the specific class methods.
|
||||
|
||||
##### Example
|
||||
@@ -189,115 +195,127 @@ p2904 = (NimBLE2904*)pCharacteristic->createDescriptor("2904");
|
||||
<a name="server-security"></a>
|
||||
### Server Security
|
||||
Security is set on the characteristic or descriptor properties by applying one of the following:
|
||||
> NIMBLE_PROPERTY::READ_ENC
|
||||
> NIMBLE_PROPERTY::READ_AUTHEN
|
||||
> NIMBLE_PROPERTY::READ_AUTHOR
|
||||
> NIMBLE_PROPERTY::WRITE_ENC
|
||||
> NIMBLE_PROPERTY::WRITE_AUTHEN
|
||||
> NIMBLE_PROPERTY::WRITE_AUTHOR
|
||||
> NIMBLE_PROPERTY::READ_ENC
|
||||
> NIMBLE_PROPERTY::READ_AUTHEN
|
||||
> NIMBLE_PROPERTY::READ_AUTHOR
|
||||
> NIMBLE_PROPERTY::WRITE_ENC
|
||||
> NIMBLE_PROPERTY::WRITE_AUTHEN
|
||||
> NIMBLE_PROPERTY::WRITE_AUTHOR
|
||||
|
||||
<br/>
|
||||
|
||||
When a peer wants to read or write a characteristic or descriptor with any of these properties applied it will trigger the pairing process. By default the "just-works" pairing will be performed automatically.
|
||||
|
||||
This can be changed to use passkey authentication or numeric comparison. See [Security API](#security-api) for details.
|
||||
When a peer wants to read or write a characteristic or descriptor with any of these properties applied
|
||||
it will trigger the pairing process. By default the "just-works" pairing will be performed automatically.
|
||||
This can be changed to use passkey authentication or numeric comparison. See [Security API](#security-api) for details.
|
||||
<br/>
|
||||
|
||||
<a name="advertising-api"></a>
|
||||
## Advertising API
|
||||
Advertising works the same as the original API except:
|
||||
Advertising works the same as the original API except:
|
||||
> BLEAdvertising::setMinPreferred
|
||||
> BLEAdvertising::setMaxPreferred
|
||||
|
||||
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.
|
||||
These methods were found to not provide useful functionality and consumed valuable advertising space (6 bytes of 31) if used unknowingly.
|
||||
If you wish to advertise these parameters you can still do so manually via `BLEAdvertisementData::addData` (`NimBLEAdvertisementData::addData`).
|
||||
<br/>
|
||||
|
||||
Calling `NimBLEAdvertising::setAdvertisementData` will entirely replace any data set with `NimBLEAdvertising::addServiceUUID`, or
|
||||
`NimBLEAdvertising::setAppearance` or similar methods. You should set all the data you wish to advertise within the `NimBLEAdvertisementData` instead.
|
||||
|
||||
~~Calling `NimBLEAdvertising::setScanResponseData` without also calling `NimBLEAdvertising::setAdvertisementData` will have no effect.
|
||||
When using custom scan response data you must also use custom advertisement data.~~
|
||||
No longer true as of release 1.2.0 and above, custom scan response is now supported without custom advertisement data.
|
||||
<br/>
|
||||
|
||||
> BLEAdvertising::start (NimBLEAdvertising::start)
|
||||
|
||||
Now takes 2 optional parameters, the first is the duration to advertise for (in seconds), the second is a callback that is invoked when advertising ends and takes a pointer to a `NimBLEAdvertising` object (similar to the `NimBLEScan::start` API).
|
||||
This provides an opportunity to update the advertisement data if desired.
|
||||
Now takes 2 optional parameters, the first is the duration to advertise for (in seconds), the second is a callback
|
||||
that is invoked when advertsing ends and takes a pointer to a `NimBLEAdvertising` object (similar to the `NimBLEScan::start` API).
|
||||
|
||||
This provides an opportunity to update the advertisment data if desired.
|
||||
<br/>
|
||||
|
||||
<a name="client-api"></a>
|
||||
## Client API
|
||||
|
||||
Client instances are created just as before with `BLEDevice::createClient` (`NimBLEDevice::createClient`).
|
||||
Client instances are created just as before with `BLEDevice::createClient` (`NimBLEDevice::createClient`).
|
||||
|
||||
Multiple client instances can be created, up to the maximum number of connections set in the config file (default: 3). To delete a client instance you must use `NimBLEDevice::deleteClient`.
|
||||
Multiple client instances can be created, up to the maximum number of connections set in the config file (default: 3).
|
||||
To delete a client instance you must use `NimBLEDevice::deleteClient`.
|
||||
|
||||
`BLEClient::connect`(`NimBLEClient::connect`) Has had it's parameters altered.
|
||||
`BLEClient::connect`(`NimBLEClient::connect`) Has had it's parameters altered.
|
||||
Defined as:
|
||||
> NimBLEClient::connect(bool deleteServices = true);
|
||||
> NimBLEClient::connect(NimBLEAdvertisedDevice\* device, bool deleteServices = true);
|
||||
> NimBLEClient::connect(NimBLEAddress address, bool deleteServices = true);
|
||||
> NimBLEClient::connect(bool deleteServices = true);
|
||||
> NimBLEClient::connect(NimBLEAdvertisedDevice\* device, bool deleteServices = true);
|
||||
> NimBLEClient::connect(NimBLEAddress address, bool deleteServices = true);
|
||||
|
||||
The type parameter has been removed and a new bool parameter has been added to indicate if the client should delete the attribute database previously retrieved (if applicable) for the peripheral, default value is true.
|
||||
|
||||
If set to false the client will use the attribute database it retrieved from the peripheral when previously connected.
|
||||
|
||||
This allows for faster connections and power saving if the devices dropped connection and are reconnecting.
|
||||
The type parameter has been removed and a new bool parameter has been added to indicate if the client should
|
||||
delete the attribute database previously retrieved (if applicable) for the peripheral, default value is true.
|
||||
If set to false the client will use the attribute database it retrieved from the peripheral when previously connected.
|
||||
This allows for faster connections and power saving if the devices dropped connection and are reconnecting.
|
||||
<br/>
|
||||
|
||||
> `BLEClient::getServices` (`NimBLEClient::getServices`)
|
||||
> `BLEClient::getServices` (`NimBLEClient::getServices`)
|
||||
|
||||
This method now takes an optional (bool) parameter to indicate if the services should be retrieved from the server (true) or the currently known database returned (false : default).
|
||||
Also now returns a pointer to `std::vector` instead of `std::map`.
|
||||
This method now takes an optional (bool) parameter to indicate if the services should be retrieved from the server (true) or
|
||||
the currently known database returned (false : default).
|
||||
Also now returns a pointer to `std::vector` instead of `std::map`.
|
||||
<br/>
|
||||
|
||||
**Removed:** the automatic discovery of all peripheral attributes as they consumed time and resources for data the user may not be interested in.
|
||||
|
||||
**Added:** `NimBLEClient::discoverAttributes` for the user to discover all the peripheral attributes to replace the the removed automatic functionality.
|
||||
**Removed:** the automatic discovery of all peripheral attributes as they consumed time and resources for data
|
||||
the user may not be interested in.
|
||||
|
||||
**Added:** `NimBLEClient::discoverAttributes` for the user to discover all the peripheral attributes
|
||||
to replace the the removed automatic functionality.
|
||||
<br/>
|
||||
|
||||
<a name="remote-services"></a>
|
||||
### Remote Services
|
||||
`BLERemoteService` (`NimBLERemoteService`) Methods remain mostly unchanged with the exceptions of:
|
||||
`BLERemoteService` (`NimBLERemoteService`) Methods remain mostly unchanged with the exceptions of:
|
||||
|
||||
> BLERemoteService::getCharacteristicsByHandle
|
||||
|
||||
This method has been removed.
|
||||
This method has been removed.
|
||||
<br/>
|
||||
|
||||
> `BLERemoteService::getCharacteristics` (`NimBLERemoteService::getCharacteristics`)
|
||||
> `BLERemoteService::getCharacteristics` (`NimBLERemoteService::getCharacteristics`)
|
||||
|
||||
This method now takes an optional (bool) parameter to indicate if the characteristics should be retrieved from the server (true) or
|
||||
the currently known database returned (false : default).
|
||||
Also now returns a pointer to `std::vector` instead of `std::map`.
|
||||
This method now takes an optional (bool) parameter to indicate if the characteristics should be retrieved from the server (true) or
|
||||
the currently known database returned (false : default).
|
||||
Also now returns a pointer to `std::vector` instead of `std::map`.
|
||||
<br/>
|
||||
|
||||
<a name="remote-characteristics"></a>
|
||||
### Remote Characteristics
|
||||
`BLERemoteCharacteristic` (`NimBLERemoteCharacteristic`)
|
||||
There have been a few changes to the methods in this class:
|
||||
`BLERemoteCharacteristic` (`NimBLERemoteCharacteristic`) There have been a few changes to the methods in this class:
|
||||
|
||||
> `BLERemoteCharacteristic::writeValue` (`NimBLERemoteCharacteristic::writeValue`)
|
||||
> `BLERemoteCharacteristic::registerForNotify` (`NimBLERemoteCharacteristic::registerForNotify`)
|
||||
> `BLERemoteCharacteristic::writeValue` (`NimBLERemoteCharacteristic::writeValue`)
|
||||
> `BLERemoteCharacteristic::registerForNotify` (`NimBLERemoteCharacteristic::registerForNotify`)
|
||||
|
||||
Now return true or false to indicate success or failure so you can choose to disconnect or try again.
|
||||
Now return true or false to indicate success or failure so you can choose to disconnect or try again.
|
||||
<br/>
|
||||
|
||||
> `BLERemoteCharacteristic::registerForNotify` (`NimBLERemoteCharacteristic::registerForNotify`)
|
||||
> `BLERemoteCharacteristic::registerForNotify` (`NimBLERemoteCharacteristic::registerForNotify`)
|
||||
|
||||
Is now **deprecated**.
|
||||
> `NimBLERemoteCharacteristic::subscribe`
|
||||
> `NimBLERemoteCharacteristic::unsubscribe`
|
||||
Is now **deprecated**.
|
||||
> `NimBLERemoteCharacteristic::subscribe`
|
||||
> `NimBLERemoteCharacteristic::unsubscribe`
|
||||
|
||||
Are the new methods added to replace it.
|
||||
Are the new methods added to replace it.
|
||||
<br/>
|
||||
|
||||
> `BLERemoteCharacteristic::readUInt8` (`NimBLERemoteCharacteristic::readUInt8`)
|
||||
> `BLERemoteCharacteristic::readUInt16` (`NimBLERemoteCharacteristic::readUInt16`)
|
||||
> `BLERemoteCharacteristic::readUInt32` (`NimBLERemoteCharacteristic::readUInt32`)
|
||||
> `BLERemoteCharacteristic::readFloat` (`NimBLERemoteCharacteristic::readFloat`)
|
||||
> `BLERemoteCharacteristic::readUInt8` (`NimBLERemoteCharacteristic::readUInt8`)
|
||||
> `BLERemoteCharacteristic::readUInt16` (`NimBLERemoteCharacteristic::readUInt16`)
|
||||
> `BLERemoteCharacteristic::readUInt32` (`NimBLERemoteCharacteristic::readUInt32`)
|
||||
> `BLERemoteCharacteristic::readFloat` (`NimBLERemoteCharacteristic::readFloat`)
|
||||
|
||||
Are **deprecated** a template: `NimBLERemoteCharacteristic::readValue<type\>(time_t\*, bool)` has been added to replace them.
|
||||
Are **deprecated** a template: NimBLERemoteCharacteristic::readValue<type\>(time_t\*, bool) has been added to replace them.
|
||||
<br/>
|
||||
|
||||
> `BLERemoteCharacteristic::readRawData`
|
||||
> `BLERemoteCharacteristic::readRawData`
|
||||
|
||||
**Has been removed from the API**
|
||||
Originally it stored an unnecessary copy of the data and was returning a `uint8_t` pointer to volatile internal data.
|
||||
The user application should use `NimBLERemoteCharacteristic::readValue` or `NimBLERemoteCharacteristic::getValue`.
|
||||
To obtain a copy of the data, then cast the returned std::string to the type required such as:
|
||||
**Has been removed from the API**
|
||||
Originally it stored an unnecessary copy of the data and was returning a `uint8_t` pointer to volatile internal data.
|
||||
The user application should use `NimBLERemoteCharacteristic::readValue` or `NimBLERemoteCharacteristic::getValue`.
|
||||
To obatain a copy of the data, then cast the returned std::string to the type required such as:
|
||||
```
|
||||
std::string value = pChr->readValue();
|
||||
uint8_t *data = (uint8_t*)value.data();
|
||||
@@ -307,73 +325,75 @@ Alternatively use the `readValue` template:
|
||||
my_struct_t myStruct = pChr->readValue<my_struct_t>();
|
||||
```
|
||||
<br/>
|
||||
|
||||
> `BLERemoteCharacteristic::getDescriptors` (`NimBLERemoteCharacteristic::getDescriptors`)
|
||||
|
||||
> `BLERemoteCharacteristic::getDescriptors` (`NimBLERemoteCharacteristic::getDescriptors`)
|
||||
|
||||
This method now takes an optional (bool) parameter to indicate if the descriptors should be retrieved from the server (true) or
|
||||
the currently known database returned (false : default).
|
||||
Also now returns a pointer to `std::vector` instead of `std::map`.
|
||||
This method now takes an optional (bool) parameter to indicate if the descriptors should be retrieved from the server (true) or
|
||||
the currently known database returned (false : default).
|
||||
Also now returns a pointer to `std::vector` instead of `std::map`.
|
||||
<br/>
|
||||
|
||||
<a name="client-security"></a>
|
||||
### Client Security
|
||||
The client will automatically initiate security when the peripheral responds that it's required.
|
||||
The default configuration will use "just-works" pairing with no bonding, if you wish to enable bonding see below.
|
||||
The client will automatically initiate security when the peripheral responds that it's required.
|
||||
The default configuration will use "just-works" pairing with no bonding, if you wish to enable bonding see below.
|
||||
<br/>
|
||||
|
||||
<a name="security-api"></a>
|
||||
## Security API
|
||||
Security operations have been moved to `BLEDevice` (`NimBLEDevice`).
|
||||
|
||||
Also security callback methods are now incorporated in the `NimBLEServerCallbacks` / `NimBLEClientCallbacks` classes.
|
||||
However backward compatibility with the original `BLESecurity` (`NimBLESecurity`) class is retained to minimize application code changes.
|
||||
Also security callback methods are now incorporated in the `NimBLEServerCallbacks` / `NimBLEClientCallbacks` classes.
|
||||
However backward compatibility with the original `BLESecurity` (`NimBLESecurity`) class is retained to minimize application code changes.
|
||||
|
||||
The callback methods are:
|
||||
|
||||
> `bool onConfirmPIN(uint32_t pin)`
|
||||
> `bool onConfirmPIN(uint32_t pin)`
|
||||
|
||||
Receives the pin when using numeric comparison authentication, `return true;` to accept.
|
||||
Receives the pin when using numeric comparison authentication, `return true;` to accept.
|
||||
<br/>
|
||||
|
||||
> `uint32_t onPassKeyRequest()`
|
||||
> `uint32_t onPassKeyRequest()`
|
||||
|
||||
For server callback; return the passkey expected from the client.
|
||||
For client callback; return the passkey to send to the server.
|
||||
For server callback; return the passkey expected from the client.
|
||||
For client callback; return the passkey to send to the server.
|
||||
<br/>
|
||||
|
||||
> `void onAuthenticationComplete(ble_gap_conn_desc\* desc)`
|
||||
> `void onAuthenticationComplete(ble_gap_conn_desc\* desc)`
|
||||
|
||||
Authentication complete, success or failed information is in `desc`.
|
||||
Authentication complete, success or failed information is in `desc`.
|
||||
<br/>
|
||||
|
||||
Security settings and IO capabilities are now set by the following methods of NimBLEDevice.
|
||||
> `NimBLEDevice::setSecurityAuth(bool bonding, bool mitm, bool sc)`
|
||||
> `NimBLEDevice::setSecurityAuth(uint8_t auth_req)`
|
||||
> `NimBLEDevice::setSecurityAuth(bool bonding, bool mitm, bool sc)`
|
||||
> `NimBLEDevice::setSecurityAuth(uint8_t auth_req)`
|
||||
|
||||
Sets the authorization mode for this device.
|
||||
Sets the authorization mode for this device.
|
||||
<br/>
|
||||
|
||||
> `NimBLEDevice::setSecurityIOCap(uint8_t iocap)`
|
||||
> `NimBLEDevice::setSecurityIOCap(uint8_t iocap)`
|
||||
|
||||
Sets the Input/Output capabilities of this device.
|
||||
Sets the Input/Output capabilities of this device.
|
||||
<br/>
|
||||
|
||||
> `NimBLEDevice::setSecurityInitKey(uint8_t init_key)`
|
||||
> `NimBLEDevice::setSecurityInitKey(uint8_t init_key)`
|
||||
|
||||
If we are the initiator of the security procedure this sets the keys we will distribute.
|
||||
If we are the initiator of the security procedure this sets the keys we will distribute.
|
||||
<br/>
|
||||
|
||||
> `NimBLEDevice::setSecurityRespKey(uint8_t resp_key)`
|
||||
> `NimBLEDevice::setSecurityRespKey(uint8_t resp_key)`
|
||||
|
||||
Sets the keys we are willing to accept from the peer during pairing.
|
||||
Sets the keys we are willing to accept from the peer during pairing.
|
||||
<br/>
|
||||
|
||||
<a name="arduino-configuration"></a>
|
||||
## Arduino Configuration
|
||||
|
||||
Unlike the original library pre-packaged in the esp32-arduino, this library has all the configuration options that are normally set in menuconfig available in the *src/nimconfig.h* file.
|
||||
Unlike the original library pre-packaged in the esp32-arduino, this library has all the configuration
|
||||
options that are normally set in menuconfig available in the *src/nimconfig.h* file.
|
||||
|
||||
This allows Arduino users to fully customize the build, such as increasing max connections or loading the BLE stack into external PSRAM.
|
||||
This allows Arduino users to fully customize the build, such as increasing max connections
|
||||
or loading the BLE stack into external PSRAM.
|
||||
|
||||
For details on the options, they are fully commented in *nimconfig.h*
|
||||
For details on the options, they are fully commented in *nimconfig.h*
|
||||
<br/>
|
||||
|
||||
@@ -23,7 +23,7 @@ This can be called any time you wish to use BLE functions and does not need to b
|
||||
|
||||
<a name="creating-a-server"></a>
|
||||
## Creating a Server
|
||||
BLE servers perform 2 tasks, they advertise their existence for clients to find them and they provide services which contain information for the connecting client.
|
||||
BLE servers perform 2 tasks, they advertise their existance for clients to find them and they provide services which contain information for the connecting client.
|
||||
|
||||
After initializing the NimBLE stack we create a server by calling `NimBLEDevice::createServer()`, this will create a server instance and return a pointer to it.
|
||||
|
||||
@@ -91,7 +91,7 @@ void app_main(void)
|
||||
}
|
||||
```
|
||||
|
||||
All that's left to do now is start the service, give the characteristic a value and start advertising for clients.
|
||||
All that's left to do now is start the sevice, give the characteristic a value and start advertising for clients.
|
||||
|
||||
Fist we start the service by calling `NimBLEService::start()`.
|
||||
|
||||
@@ -214,7 +214,7 @@ for(int i = 0; i < results.getCount(); i++) {
|
||||
}
|
||||
}
|
||||
```
|
||||
As shown, the call to `NimBLEClient::connect` should have it's return value tested to make sure it succeeded before proceeding to get data.
|
||||
As shown, the call to `NimBLEClient::connect` should have it's eturn value tested to make sure it succeeded before proceeding to get data.
|
||||
<br/>
|
||||
|
||||
Next we need to access the servers data by asking it for the service and the characteristic we are interested in, then read the characteristic value.
|
||||
@@ -222,7 +222,7 @@ Next we need to access the servers data by asking it for the service and the cha
|
||||
To do this we call `NimBLEClient::getService`, which takes as a parameter the UUID of the service and returns
|
||||
a pointer an instance to `NimBLERemoteService` or `nullptr` if the service was not found.
|
||||
|
||||
Next we will call `NimBLERemoteService::getCharacteristic` which takes as a parameter the UUID of the service and returns
|
||||
Next we will call `NimBLERemoteService::getCharateristic` which takes as a parameter the UUID of the service and returns
|
||||
a pointer to an instance of `NimBLERemoteCharacteristic` or `nullptr` if not found.
|
||||
|
||||
Finally we will read the characteristic value with `NimBLERemoteCharacteristic::readValue()`.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## Put BLE functions in a task running on the NimBLE stack core
|
||||
|
||||
When commands are sent to the stack from a different core they can experience delays in execution.
|
||||
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/>
|
||||
@@ -13,12 +13,12 @@ When a client instance has been created and has connected to a peer device and i
|
||||
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, deleting them will provide much less gain than it did before.
|
||||
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 characteristics needed
|
||||
## 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.
|
||||
|
||||
@@ -13,6 +13,18 @@ NimBLE is a completely open source Bluetooth Low Energy stack produced by [Apach
|
||||
It is more suited to resource constrained devices than bluedroid and has now been ported to the ESP32 by Espressif.
|
||||
<br/>
|
||||
|
||||
# Arduino Installation
|
||||
**Arduino Library manager:** Go to `sketch` -> `Include Library` -> `Manage Libraries` and search for NimBLE and install.
|
||||
|
||||
**Alternatively:** Download as .zip and extract to Arduino/libraries folder, or in Arduino IDE from Sketch menu -> Include library -> Add .Zip library.
|
||||
|
||||
`#include "NimBLEDevice.h"` at the beginning of your sketch.
|
||||
|
||||
Call `NimBLEDevice::init` in `setup`.
|
||||
|
||||
Tested and working with esp32-arduino in Arduino IDE and platform IO.
|
||||
<br/>
|
||||
|
||||
# ESP-IDF Installation
|
||||
### v4.0+
|
||||
Download as .zip and extract or clone into the components folder in your esp-idf project.
|
||||
@@ -45,6 +57,21 @@ Also see [Improvements and updates](Improvements_and_updates.md) for information
|
||||
For more advanced usage see [Usage tips](Usage_tips.md) for more performance and optimization.
|
||||
<br/>
|
||||
|
||||
### Arduino specific
|
||||
See the Refactored_original_examples in the examples folder for highlights of the differences with the original library.
|
||||
|
||||
More advanced examples highlighting many available features are in examples/NimBLE_Server, NimBLE_Client.
|
||||
|
||||
Beacon examples provided by [beegee-tokyo](https://github.com/beegee-tokyo) are in examples/BLE_Beacon_Scanner, BLE_EddystoneTLM_Beacon, BLE_EddystoneURL_Beacon.
|
||||
|
||||
Change the settings in the nimconfig.h file to customize NimBLE to your project, such as increasing max connections (default is 3).
|
||||
<br/>
|
||||
|
||||
### Arduino command line and platformio
|
||||
As an alternative to changing the configuration in nimconfig.h, Arduino command line and platformio.ini options are available.
|
||||
See the command line configuration options available in [Command line config](Command_line_config.md).
|
||||
<br/>
|
||||
|
||||
# Need help? Have a question or suggestion?
|
||||
Come chat on [gitter](https://gitter.im/NimBLE-Arduino/community?utm_source=share-link&utm_medium=link&utm_campaign=share-link) or open an issue at [NimBLE-Arduino](https://github.com/h2zero/NimBLE-Arduino/issues) or [esp-nimble-cpp](https://github.com/h2zero/esp-nimble-cpp/issues)
|
||||
<br/>
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
# Override some defaults so BT stack is enabled
|
||||
# in this example
|
||||
|
||||
#
|
||||
# BT config
|
||||
#
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
|
||||
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||
CONFIG_BT_BLUEDROID_ENABLED=n
|
||||
CONFIG_BT_NIMBLE_ENABLED=y
|
||||
@@ -2,10 +2,10 @@
|
||||
/** NimBLE_Server Demo:
|
||||
*
|
||||
* Demonstrates many of the available features of the NimBLE server library.
|
||||
*
|
||||
*
|
||||
* Created: on March 22 2020
|
||||
* Author: H2zero
|
||||
*
|
||||
*
|
||||
*/
|
||||
#include "NimBLEDevice.h"
|
||||
#include "NimBLELog.h"
|
||||
@@ -17,15 +17,15 @@ extern "C" {void app_main(void);}
|
||||
static NimBLEServer* pServer;
|
||||
|
||||
/** None of these are required as they will be handled by the library with defaults. **
|
||||
** Remove as you see fit for your needs */
|
||||
** Remove as you see fit for your needs */
|
||||
class ServerCallbacks: public NimBLEServerCallbacks {
|
||||
void onConnect(NimBLEServer* pServer) {
|
||||
printf("Client connected\n");
|
||||
NimBLEDevice::startAdvertising();
|
||||
};
|
||||
/** Alternative onConnect() method to extract details of the connection.
|
||||
/** Alternative onConnect() method to extract details of the connection.
|
||||
* See: src/ble_gap.h for the details of the ble_gap_conn_desc struct.
|
||||
*/
|
||||
*/
|
||||
void onConnect(NimBLEServer* pServer, ble_gap_conn_desc* desc) {
|
||||
printf("Client address: %s\n", NimBLEAddress(desc->peer_ota_addr).toString().c_str());
|
||||
/** We can use the connection handle here to ask for different connection parameters.
|
||||
@@ -33,7 +33,7 @@ class ServerCallbacks: public NimBLEServerCallbacks {
|
||||
* latency, supervision timeout.
|
||||
* Units; Min/Max Intervals: 1.25 millisecond increments.
|
||||
* Latency: number of intervals allowed to skip.
|
||||
* Timeout: 10 millisecond increments, try for 3x interval time for best results.
|
||||
* Timeout: 10 millisecond increments, try for 3x interval time for best results.
|
||||
*/
|
||||
pServer->updateConnParams(desc->conn_handle, 24, 48, 0, 18);
|
||||
};
|
||||
@@ -44,25 +44,25 @@ class ServerCallbacks: public NimBLEServerCallbacks {
|
||||
void onMTUChange(uint16_t MTU, ble_gap_conn_desc* desc) {
|
||||
printf("MTU updated: %u for connection ID: %u\n", MTU, desc->conn_handle);
|
||||
};
|
||||
|
||||
|
||||
/********************* Security handled here **********************
|
||||
****** Note: these are the same return values as defaults ********/
|
||||
uint32_t onPassKeyRequest(){
|
||||
printf("Server Passkey Request\n");
|
||||
/** This should return a random 6 digit number for security
|
||||
/** This should return a random 6 digit number for security
|
||||
* or make your own static passkey as done here.
|
||||
*/
|
||||
return 123456;
|
||||
return 123456;
|
||||
};
|
||||
|
||||
bool onConfirmPIN(uint32_t pass_key){
|
||||
printf("The passkey YES/NO number: %d\n", pass_key);
|
||||
/** Return false if passkeys don't match. */
|
||||
return true;
|
||||
return true;
|
||||
};
|
||||
|
||||
void onAuthenticationComplete(ble_gap_conn_desc* desc){
|
||||
/** Check that encryption was successful, if not we disconnect the client */
|
||||
/** Check that encryption was successful, if not we disconnect the client */
|
||||
if(!desc->sec_state.encrypted) {
|
||||
/** NOTE: createServer returns the current server reference unless one is not already created */
|
||||
NimBLEDevice::createServer()->disconnect(desc->conn_handle);
|
||||
@@ -76,17 +76,17 @@ class ServerCallbacks: public NimBLEServerCallbacks {
|
||||
/** Handler class for characteristic actions */
|
||||
class CharacteristicCallbacks: public NimBLECharacteristicCallbacks {
|
||||
void onRead(NimBLECharacteristic* pCharacteristic){
|
||||
printf("%s : onRead(), value: %s\n",
|
||||
printf("%s : onRead(), value: %s\n",
|
||||
pCharacteristic->getUUID().toString().c_str(),
|
||||
pCharacteristic->getValue().c_str());
|
||||
};
|
||||
|
||||
void onWrite(NimBLECharacteristic* pCharacteristic) {
|
||||
printf("%s : onWrite(), value: %s\n",
|
||||
printf("%s : onWrite(), value: %s\n",
|
||||
pCharacteristic->getUUID().toString().c_str(),
|
||||
pCharacteristic->getValue().c_str());
|
||||
};
|
||||
/** Called before notification or indication is sent,
|
||||
/** Called before notification or indication is sent,
|
||||
* the value can be changed here before sending if desired.
|
||||
*/
|
||||
void onNotify(NimBLECharacteristic* pCharacteristic) {
|
||||
@@ -104,11 +104,11 @@ class CharacteristicCallbacks: public NimBLECharacteristicCallbacks {
|
||||
NimBLEUtils::returnCodeToString(code));
|
||||
};
|
||||
};
|
||||
|
||||
/** Handler class for descriptor actions */
|
||||
|
||||
/** Handler class for descriptor actions */
|
||||
class DescriptorCallbacks : public NimBLEDescriptorCallbacks {
|
||||
void onWrite(NimBLEDescriptor* pDescriptor) {
|
||||
std::string dscVal = pDescriptor->getValue();
|
||||
std::string dscVal((char*)pDescriptor->getValue(), pDescriptor->getLength());
|
||||
printf("Descriptor witten value: %s\n", dscVal.c_str());
|
||||
};
|
||||
|
||||
@@ -118,7 +118,7 @@ class DescriptorCallbacks : public NimBLEDescriptorCallbacks {
|
||||
};
|
||||
|
||||
|
||||
/** Define callback instances globally to use for multiple Charateristics \ Descriptors */
|
||||
/** Define callback instances globally to use for multiple Charateristics \ Descriptors */
|
||||
static DescriptorCallbacks dscCallbacks;
|
||||
static CharacteristicCallbacks chrCallbacks;
|
||||
|
||||
@@ -135,7 +135,7 @@ void notifyTask(void * parameter){
|
||||
}
|
||||
vTaskDelay(2000/portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
@@ -155,10 +155,10 @@ void app_main(void) {
|
||||
|
||||
/** 2 different ways to set security - both calls achieve the same result.
|
||||
* no bonding, no man in the middle protection, secure connections.
|
||||
*
|
||||
* These are the default values, only shown here for demonstration.
|
||||
*/
|
||||
//NimBLEDevice::setSecurityAuth(false, false, true);
|
||||
*
|
||||
* These are the default values, only shown here for demonstration.
|
||||
*/
|
||||
//NimBLEDevice::setSecurityAuth(false, false, true);
|
||||
NimBLEDevice::setSecurityAuth(/*BLE_SM_PAIR_AUTHREQ_BOND | BLE_SM_PAIR_AUTHREQ_MITM |*/ BLE_SM_PAIR_AUTHREQ_SC);
|
||||
|
||||
pServer = NimBLEDevice::createServer();
|
||||
@@ -173,7 +173,7 @@ void app_main(void) {
|
||||
NIMBLE_PROPERTY::READ_ENC | // only allow reading if paired / encrypted
|
||||
NIMBLE_PROPERTY::WRITE_ENC // only allow writing if paired / encrypted
|
||||
);
|
||||
|
||||
|
||||
pBeefCharacteristic->setValue("Burger");
|
||||
pBeefCharacteristic->setCallbacks(&chrCallbacks);
|
||||
|
||||
@@ -182,10 +182,10 @@ void app_main(void) {
|
||||
* and sizes. However we must cast the returned reference to the correct type as the method
|
||||
* only returns a pointer to the base NimBLEDescriptor class.
|
||||
*/
|
||||
NimBLE2904* pBeef2904 = (NimBLE2904*)pBeefCharacteristic->createDescriptor("2904");
|
||||
NimBLE2904* pBeef2904 = (NimBLE2904*)pBeefCharacteristic->createDescriptor("2904");
|
||||
pBeef2904->setFormat(NimBLE2904::FORMAT_UTF8);
|
||||
pBeef2904->setCallbacks(&dscCallbacks);
|
||||
|
||||
|
||||
|
||||
NimBLEService* pBaadService = pServer->createService("BAAD");
|
||||
NimBLECharacteristic* pFoodCharacteristic = pBaadService->createCharacteristic(
|
||||
@@ -201,7 +201,7 @@ void app_main(void) {
|
||||
/** Custom descriptor: Arguments are UUID, Properties, max length in bytes of the value */
|
||||
NimBLEDescriptor* pC01Ddsc = pFoodCharacteristic->createDescriptor(
|
||||
"C01D",
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE|
|
||||
NIMBLE_PROPERTY::WRITE_ENC, // only allow writing if paired / encrypted
|
||||
20
|
||||
@@ -209,7 +209,7 @@ void app_main(void) {
|
||||
pC01Ddsc->setValue("Send it back!");
|
||||
pC01Ddsc->setCallbacks(&dscCallbacks);
|
||||
|
||||
/** Start the services when finished creating all Characteristics and Descriptors */
|
||||
/** Start the services when finished creating all Characteristics and Descriptors */
|
||||
pDeadService->start();
|
||||
pBaadService->start();
|
||||
|
||||
@@ -224,6 +224,6 @@ void app_main(void) {
|
||||
pAdvertising->start();
|
||||
|
||||
printf("Advertising Started\n");
|
||||
|
||||
|
||||
xTaskCreate(notifyTask, "notifyTask", 5000, NULL, 1, NULL);
|
||||
}
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
# Override some defaults so BT stack is enabled
|
||||
# in this example
|
||||
|
||||
#
|
||||
# BT config
|
||||
#
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
|
||||
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||
CONFIG_BT_BLUEDROID_ENABLED=n
|
||||
CONFIG_BT_NIMBLE_ENABLED=y
|
||||
@@ -1,13 +0,0 @@
|
||||
# Override some defaults so BT stack is enabled
|
||||
# in this example
|
||||
|
||||
#
|
||||
# BT config
|
||||
#
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
|
||||
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||
CONFIG_BT_BLUEDROID_ENABLED=n
|
||||
CONFIG_BT_NIMBLE_ENABLED=y
|
||||
CONFIG_BT_NIMBLE_EXT_ADV=y
|
||||
@@ -1,13 +0,0 @@
|
||||
# Override some defaults so BT stack is enabled
|
||||
# in this example
|
||||
|
||||
#
|
||||
# BT config
|
||||
#
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
|
||||
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||
CONFIG_BT_BLUEDROID_ENABLED=n
|
||||
CONFIG_BT_NIMBLE_ENABLED=y
|
||||
CONFIG_BT_NIMBLE_EXT_ADV=y
|
||||
@@ -1,13 +0,0 @@
|
||||
# Override some defaults so BT stack is enabled
|
||||
# in this example
|
||||
|
||||
#
|
||||
# BT config
|
||||
#
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
|
||||
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||
CONFIG_BT_BLUEDROID_ENABLED=n
|
||||
CONFIG_BT_NIMBLE_ENABLED=y
|
||||
CONFIG_BT_NIMBLE_EXT_ADV=y
|
||||
@@ -1,12 +0,0 @@
|
||||
# Override some defaults so BT stack is enabled
|
||||
# in this example
|
||||
|
||||
#
|
||||
# BT config
|
||||
#
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
|
||||
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||
CONFIG_BT_BLUEDROID_ENABLED=n
|
||||
CONFIG_BT_NIMBLE_ENABLED=y
|
||||
@@ -1,12 +0,0 @@
|
||||
# Override some defaults so BT stack is enabled
|
||||
# in this example
|
||||
|
||||
#
|
||||
# BT config
|
||||
#
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
|
||||
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||
CONFIG_BT_BLUEDROID_ENABLED=n
|
||||
CONFIG_BT_NIMBLE_ENABLED=y
|
||||
@@ -1,12 +0,0 @@
|
||||
# Override some defaults so BT stack is enabled
|
||||
# in this example
|
||||
|
||||
#
|
||||
# BT config
|
||||
#
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
|
||||
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||
CONFIG_BT_BLUEDROID_ENABLED=n
|
||||
CONFIG_BT_NIMBLE_ENABLED=y
|
||||
@@ -1,12 +0,0 @@
|
||||
# Override some defaults so BT stack is enabled
|
||||
# in this example
|
||||
|
||||
#
|
||||
# BT config
|
||||
#
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
|
||||
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||
CONFIG_BT_BLUEDROID_ENABLED=n
|
||||
CONFIG_BT_NIMBLE_ENABLED=y
|
||||
@@ -1,12 +0,0 @@
|
||||
# Override some defaults so BT stack is enabled
|
||||
# in this example
|
||||
|
||||
#
|
||||
# BT config
|
||||
#
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
|
||||
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||
CONFIG_BT_BLUEDROID_ENABLED=n
|
||||
CONFIG_BT_NIMBLE_ENABLED=y
|
||||
7
examples/mesh/basic_on_off_level_server/CMakeLists.txt
Normal file
7
examples/mesh/basic_on_off_level_server/CMakeLists.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
set(SUPPORTED_TARGETS esp32)
|
||||
project(basic_on_off_level_server)
|
||||
3
examples/mesh/basic_on_off_level_server/Makefile
Normal file
3
examples/mesh/basic_on_off_level_server/Makefile
Normal file
@@ -0,0 +1,3 @@
|
||||
PROJECT_NAME := basic_on_off_level_server
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
@@ -0,0 +1,4 @@
|
||||
set(COMPONENT_SRCS "main.cpp")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||
|
||||
register_component()
|
||||
@@ -0,0 +1,4 @@
|
||||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
||||
64
examples/mesh/basic_on_off_level_server/main/main.cpp
Normal file
64
examples/mesh/basic_on_off_level_server/main/main.cpp
Normal file
@@ -0,0 +1,64 @@
|
||||
#include "NimBLEDevice.h"
|
||||
#include "driver/gpio.h"
|
||||
|
||||
extern "C" {void app_main(void);}
|
||||
|
||||
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
|
||||
|
||||
// LED pins
|
||||
#define LEDR GPIO_NUM_16
|
||||
#define LEDG GPIO_NUM_17
|
||||
#define LEDB GPIO_NUM_18
|
||||
#define OUTPUT_PIN (1ULL<<LEDG)
|
||||
|
||||
static uint8_t onOffVal = 0;
|
||||
static int16_t levelVal = 0;
|
||||
|
||||
class onOffSrvModelCallbacks : public NimBLEMeshModelCallbacks {
|
||||
void setOnOff(NimBLEMeshModel *pModel, uint8_t val) {
|
||||
printf("on/off set val %d, transition time: %dms\n", val, pModel->getTransTime());
|
||||
onOffVal = val;
|
||||
gpio_set_level(LEDG, !onOffVal);
|
||||
}
|
||||
|
||||
uint8_t getOnOff(NimBLEMeshModel *pModel) {
|
||||
printf("on/off get val %d\n", onOffVal);
|
||||
return onOffVal;
|
||||
}
|
||||
};
|
||||
|
||||
class levelSrvModelCallbacks : public NimBLEMeshModelCallbacks {
|
||||
void setLevel(NimBLEMeshModel *pModel, int16_t val) {
|
||||
printf("Level set val %d, transition time: %dms\n", val, pModel->getTransTime());
|
||||
levelVal = val;
|
||||
}
|
||||
|
||||
int16_t getLevel(NimBLEMeshModel *pModel) {
|
||||
printf("Level get val %d\n", levelVal);
|
||||
return levelVal;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void app_main(void) {
|
||||
gpio_config_t io_conf;
|
||||
io_conf.intr_type = (gpio_int_type_t)GPIO_PIN_INTR_DISABLE;
|
||||
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||
io_conf.pin_bit_mask = OUTPUT_PIN;
|
||||
io_conf.pull_down_en = (gpio_pulldown_t)0;
|
||||
io_conf.pull_up_en = (gpio_pullup_t)0;
|
||||
gpio_config(&io_conf);
|
||||
gpio_set_level(LEDG, 1);
|
||||
|
||||
NimBLEDevice::init("");
|
||||
NimBLEMeshNode *pMesh = NimBLEDevice::createMeshNode(NimBLEUUID(SERVICE_UUID),0);
|
||||
NimBLEMeshElement* pElem = pMesh->getElement();
|
||||
NimBLEMeshModel* pModel = pElem->createModel(BT_MESH_MODEL_ID_GEN_ONOFF_SRV, new onOffSrvModelCallbacks());
|
||||
pModel->setValue(onOffVal);
|
||||
|
||||
//pElem = pMesh->createElement();
|
||||
pModel = pElem->createModel(BT_MESH_MODEL_ID_GEN_LEVEL_SRV, new levelSrvModelCallbacks());
|
||||
pModel->setValue(levelVal);
|
||||
pMesh->start();
|
||||
printf("Mesh Started");
|
||||
}
|
||||
@@ -22,11 +22,11 @@
|
||||
#include "NimBLE2904.h"
|
||||
|
||||
|
||||
NimBLE2904::NimBLE2904(NimBLECharacteristic* pCharacteristic)
|
||||
NimBLE2904::NimBLE2904(NimBLECharacteristic* pCharacterisitic)
|
||||
: NimBLEDescriptor(NimBLEUUID((uint16_t) 0x2904),
|
||||
BLE_GATT_CHR_F_READ,
|
||||
sizeof(BLE2904_Data),
|
||||
pCharacteristic)
|
||||
pCharacterisitic)
|
||||
{
|
||||
m_data.m_format = 0;
|
||||
m_data.m_exponent = 0;
|
||||
|
||||
@@ -156,7 +156,7 @@ std::string NimBLEAddress::toString() const {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Convenience operator to check if this address is equal to another.
|
||||
* @brief Convienience operator to check if this address is equal to another.
|
||||
*/
|
||||
bool NimBLEAddress::operator ==(const NimBLEAddress & rhs) const {
|
||||
return memcmp(rhs.m_address, m_address, sizeof m_address) == 0;
|
||||
@@ -164,7 +164,7 @@ bool NimBLEAddress::operator ==(const NimBLEAddress & rhs) const {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Convenience operator to check if this address is not equal to another.
|
||||
* @brief Convienience operator to check if this address is not equal to another.
|
||||
*/
|
||||
bool NimBLEAddress::operator !=(const NimBLEAddress & rhs) const {
|
||||
return !this->operator==(rhs);
|
||||
@@ -186,7 +186,7 @@ NimBLEAddress::operator std::string() const {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Convenience operator to convert the native address representation to uint_64.
|
||||
* @brief Convienience operator to convert the native address representation to uint_64.
|
||||
*/
|
||||
NimBLEAddress::operator uint64_t() const {
|
||||
uint64_t address = 0;
|
||||
|
||||
@@ -52,9 +52,9 @@ NimBLEAddress NimBLEAdvertisedDevice::getAddress() {
|
||||
* @brief Get the advertisement type.
|
||||
* @return The advertising type the device is reporting:
|
||||
* * BLE_HCI_ADV_TYPE_ADV_IND (0) - indirect advertising
|
||||
* * BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD (1) - direct advertising - high duty cycle
|
||||
* * BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD (1) - direct advertisng - high duty cycle
|
||||
* * BLE_HCI_ADV_TYPE_ADV_SCAN_IND (2) - indirect scan response
|
||||
* * BLE_HCI_ADV_TYPE_ADV_NONCONN_IND (3) - indirect advertising - not connectable
|
||||
* * BLE_HCI_ADV_TYPE_ADV_NONCONN_IND (3) - indirect advertisng - not connectable
|
||||
* * BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_LD (4) - direct advertising - low duty cycle
|
||||
*/
|
||||
uint8_t NimBLEAdvertisedDevice::getAdvType() {
|
||||
@@ -66,7 +66,7 @@ uint8_t NimBLEAdvertisedDevice::getAdvType() {
|
||||
* @brief Get the appearance.
|
||||
*
|
||||
* A %BLE device can declare its own appearance. The appearance is how it would like to be shown to an end user
|
||||
* typically in the form of an icon.
|
||||
* typcially in the form of an icon.
|
||||
*
|
||||
* @return The appearance of the advertised device.
|
||||
*/
|
||||
@@ -308,7 +308,7 @@ std::string NimBLEAdvertisedDevice::getServiceData(const NimBLEUUID &uuid) {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the UUID of the service data at the index.
|
||||
* @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.
|
||||
*/
|
||||
@@ -448,7 +448,7 @@ uint8_t NimBLEAdvertisedDevice::getServiceUUIDCount() {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Check advertised services for existence of the required UUID
|
||||
* @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
|
||||
*/
|
||||
@@ -794,7 +794,7 @@ void NimBLEAdvertisedDevice::setPayload(const uint8_t *payload, uint8_t length,
|
||||
|
||||
/**
|
||||
* @brief Get the length of the advertisement data in the payload.
|
||||
* @return The number of bytes in the payload that is from the advertisement.
|
||||
* @return The number of bytes in the payload that is from the advertisment.
|
||||
*/
|
||||
uint8_t NimBLEAdvertisedDevice::getAdvLength() {
|
||||
return m_advLength;
|
||||
|
||||
@@ -434,16 +434,15 @@ bool NimBLEAdvertising::start(uint32_t duration, void (*advCompleteCB)(NimBLEAdv
|
||||
if(m_advParams.conn_mode == BLE_GAP_CONN_MODE_NON) {
|
||||
if(!m_scanResp) {
|
||||
m_advParams.disc_mode = BLE_GAP_DISC_MODE_NON;
|
||||
// non-connectable advertising does not require AD flags.
|
||||
m_advData.flags = 0;
|
||||
m_advData.flags = BLE_HS_ADV_F_BREDR_UNSUP;
|
||||
}
|
||||
}
|
||||
|
||||
int rc = 0;
|
||||
|
||||
if (!m_customAdvData && !m_advDataSet) {
|
||||
//start with 3 bytes for the flags data if required
|
||||
uint8_t payloadLen = (m_advData.flags > 0) ? (2 + 1) : 0;
|
||||
//start with 3 bytes for the flags data
|
||||
uint8_t payloadLen = (2 + 1);
|
||||
if(m_advData.mfg_data_len > 0)
|
||||
payloadLen += (2 + m_advData.mfg_data_len);
|
||||
|
||||
@@ -758,7 +757,7 @@ int NimBLEAdvertising::handleGapEvent(struct ble_gap_event *event, void *arg) {
|
||||
*/
|
||||
void NimBLEAdvertisementData::addData(const std::string &data) {
|
||||
if ((m_payload.length() + data.length()) > BLE_HS_ADV_MAX_SZ) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Advertisement data length exceeded");
|
||||
NIMBLE_LOGE(LOG_TAG, "Advertisement data length exceded");
|
||||
return;
|
||||
}
|
||||
m_payload.append(data);
|
||||
|
||||
@@ -54,7 +54,7 @@ struct Has_c_str_len<T, decltype(void(std::declval<T &>().c_str())),
|
||||
/**
|
||||
* @brief A specialized container class to hold BLE attribute values.
|
||||
* @details This class is designed to be more memory efficient than using\n
|
||||
* standard container types for value storage, while being convertible to\n
|
||||
* standard container types for value storage, while being convertable to\n
|
||||
* many different container classes.
|
||||
*/
|
||||
class NimBLEAttValue
|
||||
|
||||
@@ -130,7 +130,7 @@ void NimBLEBeacon::setManufacturerId(uint16_t manufacturerId) {
|
||||
*/
|
||||
void NimBLEBeacon::setMinor(uint16_t minor) {
|
||||
m_beaconData.minor = ENDIAN_CHANGE_U16(minor);
|
||||
} // setMinor
|
||||
} // setMinior
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -126,8 +126,8 @@ void NimBLECharacteristic::addDescriptor(NimBLEDescriptor *pDescriptor) {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Remove a descriptor from the characteristic.
|
||||
* @param[in] pDescriptor A pointer to the descriptor instance to remove from the characteristic.
|
||||
* @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) {
|
||||
@@ -273,13 +273,11 @@ int NimBLECharacteristic::handleGapEvent(uint16_t conn_handle, uint16_t attr_han
|
||||
if(ble_uuid_cmp(uuid, &pCharacteristic->getUUID().getNative()->u) == 0){
|
||||
switch(ctxt->op) {
|
||||
case BLE_GATT_ACCESS_OP_READ_CHR: {
|
||||
rc = ble_gap_conn_find(conn_handle, &desc);
|
||||
assert(rc == 0);
|
||||
|
||||
// If the packet header is only 8 bytes this is a follow up of a long read
|
||||
// so we don't want to call the onRead() callback again.
|
||||
if(ctxt->om->om_pkthdr_len > 8 ||
|
||||
pCharacteristic->m_value.size() <= (ble_att_mtu(desc.conn_handle) - 3)) {
|
||||
// If the packet header is only 8 bytes this is a follow up of a long read
|
||||
// so we don't want to call the onRead() callback again.
|
||||
if(ctxt->om->om_pkthdr_len > 8) {
|
||||
rc = ble_gap_conn_find(conn_handle, &desc);
|
||||
assert(rc == 0);
|
||||
pCharacteristic->m_pCallbacks->onRead(pCharacteristic);
|
||||
pCharacteristic->m_pCallbacks->onRead(pCharacteristic, &desc);
|
||||
}
|
||||
@@ -442,7 +440,7 @@ void NimBLECharacteristic::notify(const uint8_t* value, size_t length, bool is_n
|
||||
!(m_properties & NIMBLE_PROPERTY::INDICATE))
|
||||
{
|
||||
NIMBLE_LOGE(LOG_TAG,
|
||||
"<< notify-Error; Notify/indicate not enabled for characteristic: %s",
|
||||
"<< notify-Error; Notify/indicate not enabled for characterisitc: %s",
|
||||
std::string(getUUID()).c_str());
|
||||
}
|
||||
|
||||
|
||||
@@ -157,35 +157,35 @@ size_t NimBLEClient::deleteService(const NimBLEUUID &uuid) {
|
||||
|
||||
/**
|
||||
* @brief Connect to the BLE Server.
|
||||
* @param [in] deleteAttributes If true this will delete any attribute objects this client may already\n
|
||||
* @param [in] deleteAttibutes If true this will delete any attribute objects this client may already\n
|
||||
* have created and clears the vectors after successful connection.
|
||||
* @return True on success.
|
||||
*/
|
||||
bool NimBLEClient::connect(bool deleteAttributes) {
|
||||
return connect(m_peerAddress, deleteAttributes);
|
||||
bool NimBLEClient::connect(bool deleteAttibutes) {
|
||||
return connect(m_peerAddress, deleteAttibutes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Connect to an advertising device.
|
||||
* @param [in] device The device to connect to.
|
||||
* @param [in] deleteAttributes If true this will delete any attribute objects this client may already\n
|
||||
* @param [in] deleteAttibutes If true this will delete any attribute objects this client may already\n
|
||||
* have created and clears the vectors after successful connection.
|
||||
* @return True on success.
|
||||
*/
|
||||
bool NimBLEClient::connect(NimBLEAdvertisedDevice* device, bool deleteAttributes) {
|
||||
bool NimBLEClient::connect(NimBLEAdvertisedDevice* device, bool deleteAttibutes) {
|
||||
NimBLEAddress address(device->getAddress());
|
||||
return connect(address, deleteAttributes);
|
||||
return connect(address, deleteAttibutes);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Connect to the BLE Server.
|
||||
* @param [in] address The address of the server.
|
||||
* @param [in] deleteAttributes If true this will delete any attribute objects this client may already\n
|
||||
* @param [in] deleteAttibutes If true this will delete any attribute objects this client may already\n
|
||||
* have created and clears the vectors after successful connection.
|
||||
* @return True on success.
|
||||
*/
|
||||
bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttributes) {
|
||||
bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttibutes) {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> connect(%s)", address.toString().c_str());
|
||||
|
||||
if(!NimBLEDevice::m_synced) {
|
||||
@@ -259,7 +259,7 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttributes)
|
||||
break;
|
||||
|
||||
case BLE_HS_EALREADY:
|
||||
// Already attempting to connect to this device, cancel the previous
|
||||
// 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());
|
||||
@@ -317,7 +317,7 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttributes)
|
||||
NIMBLE_LOGI(LOG_TAG, "Connection established");
|
||||
}
|
||||
|
||||
if(deleteAttributes) {
|
||||
if(deleteAttibutes) {
|
||||
deleteServices();
|
||||
}
|
||||
|
||||
@@ -336,7 +336,6 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttributes)
|
||||
* @return True on success.
|
||||
*/
|
||||
bool NimBLEClient::secureConnection() {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> secureConnection()");
|
||||
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
|
||||
ble_task_data_t taskData = {this, cur_task, 0, nullptr};
|
||||
|
||||
@@ -346,7 +345,7 @@ bool NimBLEClient::secureConnection() {
|
||||
m_pTaskData = &taskData;
|
||||
|
||||
int rc = NimBLEDevice::startSecurity(m_conn_id);
|
||||
if(rc != 0 && rc != BLE_HS_EALREADY){
|
||||
if(rc != 0){
|
||||
m_lastErr = rc;
|
||||
m_pTaskData = nullptr;
|
||||
return false;
|
||||
@@ -361,11 +360,9 @@ bool NimBLEClient::secureConnection() {
|
||||
|
||||
if(taskData.rc != 0){
|
||||
m_lastErr = taskData.rc;
|
||||
NIMBLE_LOGE(LOG_TAG, "secureConnection: failed rc=%d", taskData.rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< secureConnection: success");
|
||||
return true;
|
||||
} // secureConnection
|
||||
|
||||
@@ -393,8 +390,8 @@ int NimBLEClient::disconnect(uint8_t reason) {
|
||||
// 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 supervision timeout time + 1 second.
|
||||
// In the case that the event happens shortly after the supervision timeout
|
||||
// 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);
|
||||
@@ -434,7 +431,7 @@ void NimBLEClient::setConnectPhy(uint8_t mask) {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the connection parameters to use when connecting to a server.
|
||||
* @brief Set the connection paramaters to use when connecting to a server.
|
||||
* @param [in] minInterval The minimum connection interval in 1.25ms units.
|
||||
* @param [in] maxInterval The maximum connection interval in 1.25ms units.
|
||||
* @param [in] latency The number of packets allowed to skip (extends max interval).
|
||||
@@ -706,29 +703,13 @@ std::vector<NimBLERemoteService*>* NimBLEClient::getServices(bool refresh) {
|
||||
|
||||
/**
|
||||
* @brief Retrieves the full database of attributes that the peripheral has available.
|
||||
* @return True if successful.
|
||||
*/
|
||||
bool NimBLEClient::discoverAttributes() {
|
||||
deleteServices();
|
||||
|
||||
if (!retrieveServices()){
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
for(auto svc: m_servicesVector) {
|
||||
if (!svc->retrieveCharacteristics()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for(auto chr: svc->m_characteristicVector) {
|
||||
if (!chr->retrieveDescriptors()) {
|
||||
return false;
|
||||
}
|
||||
void NimBLEClient::discoverAttributes() {
|
||||
for(auto svc: *getServices(true)) {
|
||||
for(auto chr: *svc->getCharacteristics(true)) {
|
||||
chr->getDescriptors(true);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
} // discoverAttributes
|
||||
|
||||
|
||||
|
||||
@@ -38,9 +38,9 @@ class NimBLEAdvertisedDevice;
|
||||
*/
|
||||
class NimBLEClient {
|
||||
public:
|
||||
bool connect(NimBLEAdvertisedDevice* device, bool deleteAttributes = true);
|
||||
bool connect(const NimBLEAddress &address, bool deleteAttributes = true);
|
||||
bool connect(bool deleteAttributes = true);
|
||||
bool connect(NimBLEAdvertisedDevice* device, bool deleteAttibutes = true);
|
||||
bool connect(const NimBLEAddress &address, bool deleteAttibutes = true);
|
||||
bool connect(bool deleteAttibutes = true);
|
||||
int disconnect(uint8_t reason = BLE_ERR_REM_USER_CONN_TERM);
|
||||
NimBLEAddress getPeerAddress();
|
||||
void setPeerAddress(const NimBLEAddress &address);
|
||||
@@ -70,7 +70,7 @@ public:
|
||||
void updateConnParams(uint16_t minInterval, uint16_t maxInterval,
|
||||
uint16_t latency, uint16_t timeout);
|
||||
void setDataLen(uint16_t tx_octets);
|
||||
bool discoverAttributes();
|
||||
void discoverAttributes();
|
||||
NimBLEConnInfo getConnInfo();
|
||||
int getLastError();
|
||||
#if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
@@ -137,7 +137,7 @@ public:
|
||||
* @brief Called when server requests to update the connection parameters.
|
||||
* @param [in] pClient A pointer to the calling client object.
|
||||
* @param [in] params A pointer to the struct containing the connection parameters requested.
|
||||
* @return True to accept the parameters.
|
||||
* @return True to accept the parmeters.
|
||||
*/
|
||||
virtual bool onConnParamsUpdateRequest(NimBLEClient* pClient, const ble_gap_upd_params* params);
|
||||
|
||||
@@ -152,7 +152,7 @@ public:
|
||||
|
||||
/**
|
||||
* @brief Called when the pairing procedure is complete.
|
||||
* @param [in] desc A reference to a NimBLEConnInfo instance containing the peer info.\n
|
||||
* @param [in] desc A pointer to the struct containing the connection information.\n
|
||||
* This can be used to check the status of the connection encryption/pairing.
|
||||
*/
|
||||
virtual void onAuthenticationComplete(ble_gap_conn_desc* desc);
|
||||
|
||||
@@ -155,7 +155,6 @@ int NimBLEDescriptor::handleGapEvent(uint16_t conn_handle, uint16_t attr_handle,
|
||||
|
||||
const ble_uuid_t *uuid;
|
||||
int rc;
|
||||
struct ble_gap_conn_desc desc;
|
||||
NimBLEDescriptor* pDescriptor = (NimBLEDescriptor*)arg;
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "Descriptor %s %s event", pDescriptor->getUUID().toString().c_str(),
|
||||
@@ -165,13 +164,9 @@ int NimBLEDescriptor::handleGapEvent(uint16_t conn_handle, uint16_t attr_handle,
|
||||
if(ble_uuid_cmp(uuid, &pDescriptor->getUUID().getNative()->u) == 0){
|
||||
switch(ctxt->op) {
|
||||
case BLE_GATT_ACCESS_OP_READ_DSC: {
|
||||
rc = ble_gap_conn_find(conn_handle, &desc);
|
||||
assert(rc == 0);
|
||||
|
||||
// If the packet header is only 8 bytes this is a follow up of a long read
|
||||
// so we don't want to call the onRead() callback again.
|
||||
if(ctxt->om->om_pkthdr_len > 8 ||
|
||||
pDescriptor->m_value.size() <= (ble_att_mtu(desc.conn_handle) - 3)) {
|
||||
// If the packet header is only 8 bytes this is a follow up of a long read
|
||||
// so we don't want to call the onRead() callback again.
|
||||
if(ctxt->om->om_pkthdr_len > 8) {
|
||||
pDescriptor->m_pCallbacks->onRead(pDescriptor);
|
||||
}
|
||||
|
||||
@@ -261,7 +256,7 @@ void NimBLEDescriptor::setValue(const std::vector<uint8_t>& vec) {
|
||||
|
||||
/**
|
||||
* @brief Set the characteristic this descriptor belongs to.
|
||||
* @param [in] pChar A pointer to 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;
|
||||
|
||||
@@ -76,6 +76,8 @@ NimBLEAdvertising* NimBLEDevice::m_bleAdvertising = nullptr;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
NimBLEMeshNode* NimBLEDevice::m_pMeshNode = nullptr;
|
||||
|
||||
gap_event_handler NimBLEDevice::m_customGapHandler = nullptr;
|
||||
ble_gap_event_listener NimBLEDevice::m_listener;
|
||||
#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
@@ -90,6 +92,30 @@ uint16_t NimBLEDevice::m_scanDuplicateSize = CONFIG_BTDM_SCAN
|
||||
uint8_t NimBLEDevice::m_scanFilterMode = CONFIG_BTDM_SCAN_DUPL_TYPE;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Create a new mesh node.
|
||||
* @param [in] uuid The uuid to advertise before being provisioned.
|
||||
* @param [in] type A bitmask of the node type to create.
|
||||
* @return A point to new instance of the mesh node.
|
||||
*/
|
||||
NimBLEMeshNode* NimBLEDevice::createMeshNode(NimBLEUUID uuid, uint8_t type) {
|
||||
if(m_pMeshNode == nullptr) {
|
||||
m_pMeshNode = new NimBLEMeshNode(uuid, type);
|
||||
}
|
||||
|
||||
return m_pMeshNode;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the mesh node instance.
|
||||
* @return a pointer to the mesh node instance or nullptr if no node exists.
|
||||
*/
|
||||
NimBLEMeshNode* NimBLEDevice::getMeshNode() {
|
||||
return m_pMeshNode;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a new instance of a server.
|
||||
* @return A new instance of the server.
|
||||
@@ -407,7 +433,7 @@ int NimBLEDevice::getPower(esp_ble_power_type_t powerType) {
|
||||
case ESP_PWR_LVL_N6:
|
||||
return -6;
|
||||
case ESP_PWR_LVL_N3:
|
||||
return -3;
|
||||
return -6;
|
||||
case ESP_PWR_LVL_N0:
|
||||
return 0;
|
||||
case ESP_PWR_LVL_P3:
|
||||
@@ -802,7 +828,7 @@ void NimBLEDevice::onSync(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
// Yield for housekeeping before returning to operations.
|
||||
// Yield for houskeeping before returning to operations.
|
||||
// Occasionally triggers exception without.
|
||||
taskYIELD();
|
||||
|
||||
@@ -851,7 +877,7 @@ void NimBLEDevice::init(const std::string &deviceName) {
|
||||
esp_err_t errRc = ESP_OK;
|
||||
|
||||
#ifdef CONFIG_ENABLE_ARDUINO_DEPENDS
|
||||
// make sure the linker includes esp32-hal-bt.c so Arduino init doesn't release BLE memory.
|
||||
// make sure the linker includes esp32-hal-bt.c so ardruino init doesn't release BLE memory.
|
||||
btStarted();
|
||||
#endif
|
||||
|
||||
@@ -971,15 +997,6 @@ void NimBLEDevice::deinit(bool clearAll) {
|
||||
}
|
||||
} // deinit
|
||||
|
||||
/**
|
||||
* @brief Set the BLEDevice's name
|
||||
* @param [in] deviceName The device name of the device.
|
||||
*/
|
||||
/* STATIC */
|
||||
void NimBLEDevice::setDeviceName(const std::string &deviceName) {
|
||||
ble_svc_gap_device_name_set(deviceName.c_str());
|
||||
} // setDeviceName
|
||||
|
||||
|
||||
/**
|
||||
* @brief Check if the initialization is complete.
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
#include "NimBLEServer.h"
|
||||
#endif
|
||||
|
||||
#include "NimBLEMeshNode.h"
|
||||
|
||||
#include "NimBLEUtils.h"
|
||||
#include "NimBLESecurity.h"
|
||||
#include "NimBLEAddress.h"
|
||||
@@ -97,7 +99,6 @@ class NimBLEDevice {
|
||||
public:
|
||||
static void init(const std::string &deviceName);
|
||||
static void deinit(bool clearAll = false);
|
||||
static void setDeviceName(const std::string &deviceName);
|
||||
static bool getInitialized();
|
||||
static NimBLEAddress getAddress();
|
||||
static std::string toString();
|
||||
@@ -116,6 +117,9 @@ public:
|
||||
static NimBLEServer* getServer();
|
||||
#endif
|
||||
|
||||
static NimBLEMeshNode* createMeshNode(NimBLEUUID uuid, uint8_t type);
|
||||
static NimBLEMeshNode* getMeshNode();
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
static void setPower(esp_power_level_t powerLevel, esp_ble_power_type_t powerType=ESP_BLE_PWR_TYPE_DEFAULT);
|
||||
static int getPower(esp_ble_power_type_t powerType=ESP_BLE_PWR_TYPE_DEFAULT);
|
||||
@@ -151,8 +155,7 @@ public:
|
||||
int max_events = 0);
|
||||
static bool stopAdvertising(uint8_t inst_id);
|
||||
static bool stopAdvertising();
|
||||
# endif
|
||||
# if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_)
|
||||
# else
|
||||
static NimBLEAdvertising* getAdvertising();
|
||||
static bool startAdvertising();
|
||||
static bool stopAdvertising();
|
||||
@@ -234,6 +237,7 @@ private:
|
||||
static uint8_t m_scanFilterMode;
|
||||
#endif
|
||||
static std::vector<NimBLEAddress> m_whiteList;
|
||||
static NimBLEMeshNode* m_pMeshNode;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -85,8 +85,8 @@ float NimBLEEddystoneTLM::getTemp() {
|
||||
} // getTemp
|
||||
|
||||
/**
|
||||
* @brief Get the count of advertisements sent.
|
||||
* @return The number of advertisements.
|
||||
* @brief Get the count of advertisments sent.
|
||||
* @return The number of advertisments.
|
||||
*/
|
||||
uint32_t NimBLEEddystoneTLM::getCount() {
|
||||
return ENDIAN_CHANGE_U32(m_eddystoneData.advCount);
|
||||
@@ -94,8 +94,8 @@ uint32_t NimBLEEddystoneTLM::getCount() {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the advertisement time.
|
||||
* @return The advertisement time.
|
||||
* @brief Get the advertisment time.
|
||||
* @return The advertisment time.
|
||||
*/
|
||||
uint32_t NimBLEEddystoneTLM::getTime() {
|
||||
return (ENDIAN_CHANGE_U32(m_eddystoneData.tmil)) / 10;
|
||||
@@ -158,7 +158,7 @@ std::string NimBLEEddystoneTLM::toString() {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the raw data for the beacon advertisement.
|
||||
* @brief Set the raw data for the beacon advertisment.
|
||||
* @param [in] data The raw data to advertise.
|
||||
*/
|
||||
void NimBLEEddystoneTLM::setData(const std::string &data) {
|
||||
@@ -208,8 +208,8 @@ void NimBLEEddystoneTLM::setTemp(float temp) {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the advertisement count.
|
||||
* @param [in] advCount The advertisement number.
|
||||
* @brief Set the advertisment count.
|
||||
* @param [in] advCount The advertisment number.
|
||||
*/
|
||||
void NimBLEEddystoneTLM::setCount(uint32_t advCount) {
|
||||
m_eddystoneData.advCount = advCount;
|
||||
@@ -217,8 +217,8 @@ void NimBLEEddystoneTLM::setCount(uint32_t advCount) {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the advertisement time.
|
||||
* @param [in] tmil The advertisement time in milliseconds.
|
||||
* @brief Set the advertisment time.
|
||||
* @param [in] tmil The advertisment time in milliseconds.
|
||||
*/
|
||||
void NimBLEEddystoneTLM::setTime(uint32_t tmil) {
|
||||
m_eddystoneData.tmil = tmil;
|
||||
|
||||
@@ -152,7 +152,7 @@ std::string NimBLEEddystoneURL::getDecodedURL() {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the raw data for the beacon advertisement.
|
||||
* @brief Set the raw data for the beacon advertisment.
|
||||
* @param [in] data The raw data to advertise.
|
||||
*/
|
||||
void NimBLEEddystoneURL::setData(const std::string &data) {
|
||||
|
||||
@@ -272,7 +272,7 @@ bool NimBLEExtAdvertising::stop() {
|
||||
|
||||
/**
|
||||
* @brief Set a callback to call when the advertisement stops.
|
||||
* @param [in] pCallbacks A pointer to a callback to be invoked when an advertisement stops.
|
||||
* @param [in] pCallbacks A pointer to a callback to be invoked when an advertisment stops.
|
||||
* @param [in] deleteCallbacks if true callback class will be deleted when advertising is destructed.
|
||||
*/
|
||||
void NimBLEExtAdvertising::setCallbacks(NimBLEExtAdvertisingCallbacks* pCallbacks,
|
||||
|
||||
@@ -99,7 +99,7 @@ void NimBLEHIDDevice::manufacturer(std::string name) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the Plug n Play characteristic value.
|
||||
* @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.
|
||||
@@ -203,12 +203,12 @@ void NimBLEHIDDevice::setBatteryLevel(uint8_t level) {
|
||||
/*
|
||||
* @brief Returns battery level characteristic
|
||||
* @ return battery level characteristic
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEHIDDevice::batteryLevel() {
|
||||
*//*
|
||||
BLECharacteristic* BLEHIDDevice::batteryLevel() {
|
||||
return m_batteryLevelCharacteristic;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
|
||||
BLECharacteristic* BLEHIDDevice::reportMap() {
|
||||
return m_reportMapCharacteristic;
|
||||
|
||||
@@ -55,7 +55,7 @@ public:
|
||||
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();
|
||||
//NimBLECharacteristic* batteryLevel();
|
||||
void setBatteryLevel(uint8_t level);
|
||||
|
||||
|
||||
|
||||
35
src/NimBLEMeshCreateModel.c
Normal file
35
src/NimBLEMeshCreateModel.c
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* NimBLEMeshCreateModel.cpp
|
||||
*
|
||||
* Created: on April 27 2022
|
||||
* Author H2zero
|
||||
*
|
||||
*/
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if CONFIG_BT_NIMBLE_MESH
|
||||
|
||||
#include "NimBLEMeshCreateModel.h"
|
||||
|
||||
static struct bt_mesh_model_cb mod_cb = {
|
||||
//.init = modelInitCallback
|
||||
};
|
||||
|
||||
struct bt_mesh_model createConfigSrvModel(struct bt_mesh_cfg_srv* cfg) {
|
||||
struct bt_mesh_model cmod = BT_MESH_MODEL_CFG_SRV(cfg);
|
||||
return cmod;
|
||||
}
|
||||
|
||||
struct bt_mesh_model createHealthModel(struct bt_mesh_health_srv* hsrv,
|
||||
struct bt_mesh_model_pub* hpub) {
|
||||
struct bt_mesh_model hmod = BT_MESH_MODEL_HEALTH_SRV(hsrv, hpub);
|
||||
return hmod;
|
||||
}
|
||||
|
||||
struct bt_mesh_model createGenModel(int16_t _id, struct bt_mesh_model_op* op,
|
||||
struct bt_mesh_model_pub* pub, void* udata) {
|
||||
struct bt_mesh_model mod = BT_MESH_MODEL_CB(_id, op, pub, udata, &mod_cb);
|
||||
return mod;
|
||||
}
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_MESH
|
||||
35
src/NimBLEMeshCreateModel.h
Normal file
35
src/NimBLEMeshCreateModel.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* NimBLEMeshCreateModel.h
|
||||
*
|
||||
* Created: on April 27 2022
|
||||
* Author H2zero
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __NIMBLE_MESH_CREATE_MODEL_H
|
||||
#define __NIMBLE_MESH_CREATE_MODEL_H
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
# include "mesh/mesh.h"
|
||||
# include "mesh/cfg_srv.h"
|
||||
#else
|
||||
# include "nimble/nimble/host/mesh/include/mesh/mesh.h"
|
||||
# include "nimble/nimble/host/mesh/include/mesh/cfg_srv.h"
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
//int modelInitCallback(struct bt_mesh_model *model);
|
||||
struct bt_mesh_model createConfigSrvModel(struct bt_mesh_cfg_srv* cfg);
|
||||
struct bt_mesh_model createHealthModel(struct bt_mesh_health_srv* hsrv,
|
||||
struct bt_mesh_model_pub* hpub);
|
||||
struct bt_mesh_model createGenModel(int16_t _id, struct bt_mesh_model_op* op,
|
||||
struct bt_mesh_model_pub* pub, void* udata);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
145
src/NimBLEMeshElement.cpp
Normal file
145
src/NimBLEMeshElement.cpp
Normal file
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* NimBLEMeshElement.cpp
|
||||
*
|
||||
* Created: on Aug 23 2020
|
||||
* Author H2zero
|
||||
*
|
||||
*/
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if CONFIG_BT_NIMBLE_MESH
|
||||
|
||||
#include "NimBLEMeshElement.h"
|
||||
#include "NimBLELog.h"
|
||||
#include "NimBLEMeshCreateModel.h"
|
||||
|
||||
static const char* LOG_TAG = "NimBLEMeshElement";
|
||||
|
||||
NimBLEMeshElement::NimBLEMeshElement() {
|
||||
m_pElem = nullptr;
|
||||
m_pHealthModel = nullptr;
|
||||
}
|
||||
|
||||
|
||||
NimBLEMeshElement::~NimBLEMeshElement() {
|
||||
if(m_pElem != nullptr) {
|
||||
delete m_pElem;
|
||||
}
|
||||
|
||||
if(m_pHealthModel != nullptr) {
|
||||
delete m_pHealthModel;
|
||||
}
|
||||
|
||||
for(auto &it : m_modelsVec) {
|
||||
if(it.id != BT_MESH_MODEL_ID_HEALTH_SRV) {
|
||||
delete (NimBLEMeshModel*)it.user_data;
|
||||
}
|
||||
}
|
||||
|
||||
m_modelsVec.clear();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Creates a model and adds it the the elements model vector.
|
||||
* @param [in] type The type of model to create.
|
||||
* @param [in] pCallbacks a pointer to a callback instance for this model.
|
||||
*/
|
||||
NimBLEMeshModel* NimBLEMeshElement::createModel(uint16_t type, NimBLEMeshModelCallbacks *pCallbacks) {
|
||||
if(getModel(type) != nullptr) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Error: element already has a type %04x model", type);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "Creating model type: %04x", type);
|
||||
|
||||
NimBLEMeshModel* pModel = nullptr;
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case BT_MESH_MODEL_ID_GEN_ONOFF_SRV:
|
||||
pModel = new NimBLEGenOnOffSrvModel(pCallbacks);
|
||||
break;
|
||||
|
||||
case BT_MESH_MODEL_ID_GEN_LEVEL_SRV:
|
||||
pModel = new NimBLEGenLevelSrvModel(pCallbacks);
|
||||
break;
|
||||
|
||||
case BT_MESH_MODEL_ID_HEALTH_SRV:
|
||||
m_pHealthModel = new NimBLEHealthSrvModel(pCallbacks);
|
||||
pModel = m_pHealthModel;
|
||||
m_modelsVec.push_back(createHealthModel(&m_pHealthModel->m_healthSrv, &pModel->m_opPub));
|
||||
return pModel;
|
||||
|
||||
default:
|
||||
NIMBLE_LOGE(LOG_TAG, "Error: model type %04x not supported", type);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
m_modelsVec.push_back(createGenModel(type, pModel->m_opList, &pModel->m_opPub, pModel));
|
||||
return pModel;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Adds a model created outside of element context to the elements model vector.
|
||||
* @param [in] model A pointer to the model instance to add.
|
||||
*/
|
||||
void NimBLEMeshElement::addModel(const bt_mesh_model & model) {
|
||||
m_modelsVec.push_back(model);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get a pointer to the model in the element with the type specified.
|
||||
* @param [in] The model type requested.
|
||||
* @returns A pointer to the model or nullptr if not found.
|
||||
*/
|
||||
NimBLEMeshModel* NimBLEMeshElement::getModel(uint16_t type) {
|
||||
if(type == BT_MESH_MODEL_ID_HEALTH_SRV) {
|
||||
return m_pHealthModel;
|
||||
}
|
||||
|
||||
for(auto &it : m_modelsVec) {
|
||||
if(it.id == type) {
|
||||
return (NimBLEMeshModel*)it.user_data;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get a pointer to a model with matching type and ID.
|
||||
* @param [in] eidx The element ID to compare.
|
||||
* @param [in] midx The model ID to compare.
|
||||
* @param [in] The model type requested.
|
||||
* @returns A pointer to the model or nullptr if not found.
|
||||
*/
|
||||
NimBLEMeshModel* NimBLEMeshElement::getModelByIdx(uint8_t eidx, uint8_t midx, uint16_t type) {
|
||||
for(auto &it : m_modelsVec) {
|
||||
if(it.elem_idx == eidx && it.mod_idx == midx) {
|
||||
if(type == BT_MESH_MODEL_ID_HEALTH_SRV) {
|
||||
return m_pHealthModel;
|
||||
} else {
|
||||
return (NimBLEMeshModel*)it.user_data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Creates a bt_mesh_elem for registering with the nimble stack.
|
||||
* @returns A pointer to the bt_mesh_elem created.
|
||||
* @details Must not be called until all models have been added.
|
||||
*/
|
||||
bt_mesh_elem* NimBLEMeshElement::start() {
|
||||
m_pElem = new bt_mesh_elem{0, 0, uint8_t(m_modelsVec.size()), 0, &m_modelsVec[0], NULL};
|
||||
return m_pElem;
|
||||
}
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_MESH
|
||||
46
src/NimBLEMeshElement.h
Normal file
46
src/NimBLEMeshElement.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* NimBLEMeshElement.h
|
||||
*
|
||||
* Created: on Aug 23 2020
|
||||
* Author H2zero
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MAIN_NIMBLE_MESH_ELEMENT_H_
|
||||
#define MAIN_NIMBLE_MESH_ELEMENT_H_
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
#include "nimconfig.h"
|
||||
|
||||
#include "NimBLEMeshNode.h"
|
||||
#include "NimBLEMeshModel.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
class NimBLEMeshModelCallbacks;
|
||||
class NimBLEMeshModel;
|
||||
class NimBLEHealthSrvModel;
|
||||
|
||||
class NimBLEMeshElement {
|
||||
public:
|
||||
NimBLEMeshModel* createModel(uint16_t type, NimBLEMeshModelCallbacks* pCallbacks=nullptr);
|
||||
NimBLEMeshModel* getModel(uint16_t type);
|
||||
NimBLEMeshModel* getModelByIdx(uint8_t eidx, uint8_t midx, uint16_t type);
|
||||
|
||||
private:
|
||||
friend class NimBLEMeshNode;
|
||||
|
||||
NimBLEMeshElement();
|
||||
~NimBLEMeshElement();
|
||||
void addModel(const bt_mesh_model & model);
|
||||
bt_mesh_elem* start();
|
||||
|
||||
bt_mesh_elem *m_pElem;
|
||||
NimBLEHealthSrvModel* m_pHealthModel;
|
||||
std::vector<bt_mesh_model> m_modelsVec;
|
||||
};
|
||||
|
||||
|
||||
#endif // CONFIG_BT_ENABLED
|
||||
#endif // MAIN_NIMBLE_MESH_ELEMENT_H_
|
||||
700
src/NimBLEMeshModel.cpp
Normal file
700
src/NimBLEMeshModel.cpp
Normal file
@@ -0,0 +1,700 @@
|
||||
/*
|
||||
* NimBLEMeshModel.cpp
|
||||
*
|
||||
* Created: on Aug 25 2020
|
||||
* Author H2zero
|
||||
*
|
||||
*/
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if CONFIG_BT_NIMBLE_MESH
|
||||
|
||||
#include "NimBLEMeshModel.h"
|
||||
#include "NimBLEUtils.h"
|
||||
#include "NimBLELog.h"
|
||||
|
||||
#if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
# include "nimble/nimble_port.h"
|
||||
#else
|
||||
# include "nimble/porting/nimble/include/nimble/nimble_port.h"
|
||||
#endif
|
||||
|
||||
#include "NimBLEDevice.h"
|
||||
|
||||
#define CID_VENDOR 0x05C3
|
||||
#define STANDARD_TEST_ID 0x00
|
||||
|
||||
static const char* LOG_TAG = "NimBLEMeshModel";
|
||||
|
||||
static NimBLEMeshModelCallbacks defaultCallbacks;
|
||||
|
||||
static const struct bt_mesh_health_srv_cb health_srv_cb = {
|
||||
NimBLEHealthSrvCallbacks::faultGetCurrent,
|
||||
NimBLEHealthSrvCallbacks::faultGetRegistered,
|
||||
NimBLEHealthSrvCallbacks::faultClear,
|
||||
NimBLEHealthSrvCallbacks::faultTest,
|
||||
NimBLEHealthSrvCallbacks::attentionOn,
|
||||
NimBLEHealthSrvCallbacks::attentionOff
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief base model constructor
|
||||
* @param [in] pCallbacks, a pointer to a callback instance for model operations
|
||||
*/
|
||||
NimBLEMeshModel::NimBLEMeshModel(NimBLEMeshModelCallbacks *pCallbacks,
|
||||
uint16_t initDataSize, uint16_t maxDataSize)
|
||||
: m_value(initDataSize, maxDataSize),
|
||||
m_targetValue(initDataSize, maxDataSize)
|
||||
{
|
||||
if(pCallbacks == nullptr) {
|
||||
m_callbacks = &defaultCallbacks;
|
||||
} else {
|
||||
m_callbacks = pCallbacks;
|
||||
}
|
||||
|
||||
m_opList = nullptr;
|
||||
m_lastTid = 0;
|
||||
m_lastSrcAddr = 0;
|
||||
m_lastDstAddr = 0;
|
||||
m_lastMsgTime = 0;
|
||||
m_transTime = 0;
|
||||
m_delayTime = 0;
|
||||
m_transStep = 0;
|
||||
|
||||
memset(&m_opPub, 0, sizeof(m_opPub));
|
||||
memset(&m_tdTimer, 0, sizeof(m_tdTimer));
|
||||
memset(&m_pubTimer, 0, sizeof(m_pubTimer));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief destructor
|
||||
*/
|
||||
NimBLEMeshModel::~NimBLEMeshModel() {
|
||||
if(m_opList != nullptr) {
|
||||
delete[] m_opList;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int NimBLEMeshModel::extractTransTimeDelay(os_mbuf *buf)
|
||||
{
|
||||
switch(buf->om_len) {
|
||||
case 0x00:
|
||||
m_transTime = 0;
|
||||
m_delayTime = 0;
|
||||
return 0;
|
||||
case 0x02:
|
||||
m_transTime = buf->om_data[0];
|
||||
if((m_transTime & 0x3F) == 0x3F) {
|
||||
// unknown transition time
|
||||
m_transTime = 0;
|
||||
m_delayTime = 0;
|
||||
return BLE_HS_EINVAL;
|
||||
}
|
||||
m_delayTime = buf->om_data[1];
|
||||
return 0;
|
||||
default:
|
||||
return BLE_HS_EMSGSIZE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool NimBLEMeshModel::checkRetransmit(uint8_t tid, bt_mesh_msg_ctx *ctx) {
|
||||
time_t now = time(nullptr);
|
||||
|
||||
if(m_lastTid == tid &&
|
||||
m_lastSrcAddr == ctx->addr &&
|
||||
m_lastDstAddr == ctx->recv_dst &&
|
||||
(now - m_lastMsgTime <= 6)) {
|
||||
NIMBLE_LOGD(LOG_TAG, "Ignoring retransmit");
|
||||
return true;
|
||||
}
|
||||
|
||||
m_lastTid = tid;
|
||||
m_lastSrcAddr = ctx->addr;
|
||||
m_lastDstAddr = ctx->recv_dst;
|
||||
m_lastMsgTime = now;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void NimBLEMeshModel::sendMessage(bt_mesh_model *model, bt_mesh_msg_ctx *ctx, os_mbuf *msg) {
|
||||
if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Send status failed");
|
||||
}
|
||||
|
||||
os_mbuf_free_chain(msg);
|
||||
}
|
||||
|
||||
|
||||
void NimBLEMeshModel::startTdTimer(ble_npl_time_t timerMs) {
|
||||
ble_npl_time_t ticks;
|
||||
ble_npl_time_ms_to_ticks(timerMs, &ticks);
|
||||
ble_npl_callout_reset(&m_tdTimer, ticks);
|
||||
}
|
||||
|
||||
|
||||
void NimBLEMeshModel::publish() {
|
||||
ble_npl_callout_reset(&m_pubTimer, 1);
|
||||
}
|
||||
|
||||
|
||||
uint32_t NimBLEMeshModel::getTransTime() {
|
||||
return (m_transTime & 0x3F) * NimBLEUtils::meshTransTimeMs(m_transTime);
|
||||
}
|
||||
|
||||
|
||||
uint16_t NimBLEMeshModel::getDelayTime() {
|
||||
return m_delayTime * 5;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Generic on/off server model constructor
|
||||
* @param [in] pCallbacks, a pointer to a callback instance for model operations
|
||||
*/
|
||||
NimBLEGenOnOffSrvModel::NimBLEGenOnOffSrvModel(NimBLEMeshModelCallbacks *pCallbacks)
|
||||
:NimBLEMeshModel(pCallbacks, 1, 1)
|
||||
{
|
||||
// Register the opcodes for this model with the required callbacks
|
||||
m_opList = new bt_mesh_model_op[4]{
|
||||
{ BT_MESH_MODEL_OP_2(0x82, 0x01), 0, NimBLEGenOnOffSrvModel::getOnOff },
|
||||
{ BT_MESH_MODEL_OP_2(0x82, 0x02), 2, NimBLEGenOnOffSrvModel::setOnOff },
|
||||
{ BT_MESH_MODEL_OP_2(0x82, 0x03), 2, NimBLEGenOnOffSrvModel::setOnOffUnack },
|
||||
BT_MESH_MODEL_OP_END};
|
||||
|
||||
ble_npl_callout_init(&m_tdTimer, nimble_port_get_dflt_eventq(),
|
||||
NimBLEGenOnOffSrvModel::tdTimerCb, this);
|
||||
ble_npl_callout_init(&m_pubTimer, nimble_port_get_dflt_eventq(),
|
||||
NimBLEGenOnOffSrvModel::pubTimerCb, this);
|
||||
|
||||
m_opPub.msg = NET_BUF_SIMPLE(2 + 3);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Called by the NimBLE stack to get the on/off status of the model
|
||||
*/
|
||||
void NimBLEGenOnOffSrvModel::getOnOff(bt_mesh_model *model,
|
||||
bt_mesh_msg_ctx *ctx,
|
||||
os_mbuf *buf)
|
||||
{
|
||||
NimBLEMeshModel *pModel = (NimBLEMeshModel*)model->user_data;
|
||||
if(pModel->m_callbacks != &defaultCallbacks) {
|
||||
pModel->setValue(pModel->m_callbacks->getOnOff(pModel));
|
||||
}
|
||||
pModel->setPubMsg();
|
||||
|
||||
if (bt_mesh_model_send(model, ctx, pModel->m_opPub.msg, NULL, NULL)) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Send status failed");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Called by the NimBLE stack to set the status of the model with acknowledgement.
|
||||
*/
|
||||
void NimBLEGenOnOffSrvModel::setOnOff(bt_mesh_model *model,
|
||||
bt_mesh_msg_ctx *ctx,
|
||||
os_mbuf *buf)
|
||||
{
|
||||
// Rather than duplicate code just call the unack function then send the status
|
||||
NimBLEGenOnOffSrvModel::setOnOffUnack(model,ctx,buf);
|
||||
NimBLEGenOnOffSrvModel::getOnOff(model,ctx,buf);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Called by the NimBLE stack to set the status of the model without acknowledgement.
|
||||
*/
|
||||
void NimBLEGenOnOffSrvModel::setOnOffUnack(bt_mesh_model *model,
|
||||
bt_mesh_msg_ctx *ctx,
|
||||
os_mbuf *buf)
|
||||
{
|
||||
NimBLEMeshModel *pModel = (NimBLEMeshModel*)model->user_data;
|
||||
uint8_t newval = net_buf_simple_pull_u8(buf);
|
||||
uint8_t tid = net_buf_simple_pull_u8(buf);
|
||||
|
||||
if(pModel->checkRetransmit(tid, ctx)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(pModel->extractTransTimeDelay(buf) != 0) {
|
||||
NIMBLE_LOGI(LOG_TAG, "Transition time / delay data error");
|
||||
return;
|
||||
}
|
||||
|
||||
// stop the transition timer to handle the new input
|
||||
ble_npl_callout_stop(&pModel->m_tdTimer);
|
||||
|
||||
// Mesh spec says transition to "ON state" happens immediately
|
||||
// after delay, so ignore the transition time.
|
||||
if(newval == 1) {
|
||||
pModel->m_transTime = 0;
|
||||
}
|
||||
|
||||
ble_npl_time_t timerMs = 0;
|
||||
|
||||
if(newval != pModel->m_value[0]) {
|
||||
pModel->m_targetValue.setValue(&newval, sizeof(newval));
|
||||
|
||||
if(pModel->m_delayTime > 0) {
|
||||
timerMs = 5 * pModel->m_delayTime;
|
||||
} else if(pModel->m_transTime & 0x3F) {
|
||||
timerMs = NimBLEUtils::meshTransTimeMs(pModel->m_transTime);
|
||||
pModel->m_transTime -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(timerMs > 0) {
|
||||
pModel->startTdTimer(timerMs);
|
||||
} else {
|
||||
pModel->m_value = pModel->m_targetValue;
|
||||
pModel->m_callbacks->setOnOff(pModel, pModel->m_value[0]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void NimBLEGenOnOffSrvModel::tdTimerCb(ble_npl_event *event) {
|
||||
NimBLEMeshModel *pModel = (NimBLEMeshModel*)event->arg;
|
||||
if(pModel->m_delayTime > 0) {
|
||||
pModel->m_delayTime = 0;
|
||||
}
|
||||
|
||||
if((pModel->m_transTime & 0x3F) && pModel->m_targetValue[0] == 0) {
|
||||
pModel->startTdTimer(NimBLEUtils::meshTransTimeMs(pModel->m_transTime));
|
||||
pModel->m_transTime -= 1;
|
||||
pModel->publish();
|
||||
return;
|
||||
}
|
||||
|
||||
pModel->m_transTime = 0;
|
||||
pModel->m_value = pModel->m_targetValue;
|
||||
pModel->m_callbacks->setOnOff(pModel, pModel->m_value[0]);
|
||||
}
|
||||
|
||||
|
||||
void NimBLEGenOnOffSrvModel::pubTimerCb(ble_npl_event *event) {
|
||||
NimBLEMeshModel *pModel = (NimBLEMeshModel*)event->arg;
|
||||
pModel->setPubMsg();
|
||||
|
||||
int err = bt_mesh_model_publish(pModel->m_opPub.mod);
|
||||
if(err != 0) {
|
||||
NIMBLE_LOGD(LOG_TAG, "Publish rc: %d",err);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void NimBLEGenOnOffSrvModel::setPubMsg() {
|
||||
bt_mesh_model_msg_init(m_opPub.msg, BT_MESH_MODEL_OP_2(0x82, 0x04));
|
||||
net_buf_simple_add_u8(m_opPub.msg, m_value[0]);
|
||||
if(m_transTime > 0) {
|
||||
net_buf_simple_add_u8(m_opPub.msg, m_targetValue[0]);
|
||||
// If we started the transition timer in setOnOff we need to correct the reported remaining time.
|
||||
net_buf_simple_add_u8(m_opPub.msg, (m_delayTime > 0) ?
|
||||
m_transTime : m_transTime + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void NimBLEGenOnOffSrvModel::setValue(uint8_t *val, size_t len) {
|
||||
if(len != sizeof(uint8_t)) {
|
||||
NIMBLE_LOGE(LOG_TAG, "NimBLEGenOnOffSrvModel: Incorrect value length");
|
||||
return;
|
||||
}
|
||||
m_value.setValue(val, len);
|
||||
}
|
||||
|
||||
|
||||
void NimBLEGenOnOffSrvModel::setTargetValue(uint8_t *val, size_t len) {
|
||||
if(len != sizeof(uint8_t)) {
|
||||
NIMBLE_LOGE(LOG_TAG, "NimBLEGenOnOffSrvModel: Incorrect target value length");
|
||||
return;
|
||||
}
|
||||
m_targetValue.setValue(val, len);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Generic level server model constructor
|
||||
* @param [in] pCallbacks, a pointer to a callback instance for model operations
|
||||
*/
|
||||
NimBLEGenLevelSrvModel::NimBLEGenLevelSrvModel(NimBLEMeshModelCallbacks *pCallbacks)
|
||||
:NimBLEMeshModel(pCallbacks, 2, 2)
|
||||
{
|
||||
// Register the opcodes for this model with the required callbacks
|
||||
m_opList = new bt_mesh_model_op[8]{
|
||||
{ BT_MESH_MODEL_OP_2(0x82, 0x05), 0, NimBLEGenLevelSrvModel::getLevel },
|
||||
{ BT_MESH_MODEL_OP_2(0x82, 0x06), 3, NimBLEGenLevelSrvModel::setLevel },
|
||||
{ BT_MESH_MODEL_OP_2(0x82, 0x07), 3, NimBLEGenLevelSrvModel::setLevelUnack },
|
||||
{ BT_MESH_MODEL_OP_2(0x82, 0x09), 5, NimBLEGenLevelSrvModel::setDelta },
|
||||
{ BT_MESH_MODEL_OP_2(0x82, 0x0a), 5, NimBLEGenLevelSrvModel::setDeltaUnack },
|
||||
{ BT_MESH_MODEL_OP_2(0x82, 0x0b), 3, NimBLEGenLevelSrvModel::setMove },
|
||||
{ BT_MESH_MODEL_OP_2(0x82, 0x0c), 3, NimBLEGenLevelSrvModel::setMoveUnack },
|
||||
BT_MESH_MODEL_OP_END};
|
||||
|
||||
ble_npl_callout_init(&m_tdTimer, nimble_port_get_dflt_eventq(),
|
||||
NimBLEGenLevelSrvModel::tdTimerCb, this);
|
||||
ble_npl_callout_init(&m_pubTimer, nimble_port_get_dflt_eventq(),
|
||||
NimBLEGenLevelSrvModel::pubTimerCb, this);
|
||||
m_opPub.msg = NET_BUF_SIMPLE(2 + 5);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Called by the NimBLE stack to get the level value of the model.
|
||||
*/
|
||||
void NimBLEGenLevelSrvModel::getLevel(bt_mesh_model *model,
|
||||
bt_mesh_msg_ctx *ctx,
|
||||
os_mbuf *buf)
|
||||
{
|
||||
NimBLEMeshModel *pModel = (NimBLEMeshModel*)model->user_data;
|
||||
if(pModel->m_callbacks != &defaultCallbacks) {
|
||||
pModel->setValue(pModel->m_callbacks->getLevel(pModel));
|
||||
}
|
||||
pModel->setPubMsg();
|
||||
|
||||
if (bt_mesh_model_send(model, ctx, pModel->m_opPub.msg, NULL, NULL)) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Send status failed");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Called by the NimBLE stack to set the level value of the model.
|
||||
*/
|
||||
void NimBLEGenLevelSrvModel::setLevel(bt_mesh_model *model,
|
||||
bt_mesh_msg_ctx *ctx,
|
||||
os_mbuf *buf)
|
||||
{
|
||||
NimBLEGenLevelSrvModel::setLevelUnack(model, ctx, buf);
|
||||
NimBLEGenLevelSrvModel::getLevel(model, ctx, buf);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Called by the NimBLE stack to set the level value of the model without acknowledgement.
|
||||
*/
|
||||
void NimBLEGenLevelSrvModel::setLevelUnack(bt_mesh_model *model,
|
||||
bt_mesh_msg_ctx *ctx,
|
||||
os_mbuf *buf)
|
||||
{
|
||||
NimBLEMeshModel *pModel = (NimBLEMeshModel*)model->user_data;
|
||||
int16_t newval = (int16_t) net_buf_simple_pull_le16(buf);
|
||||
uint8_t tid = net_buf_simple_pull_u8(buf);
|
||||
|
||||
if(pModel->checkRetransmit(tid, ctx)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(pModel->extractTransTimeDelay(buf) != 0) {
|
||||
NIMBLE_LOGI(LOG_TAG, "Transition time / delay data error");
|
||||
return;
|
||||
}
|
||||
|
||||
// stop the transition timer to handle the new input
|
||||
ble_npl_callout_stop(&pModel->m_tdTimer);
|
||||
|
||||
ble_npl_time_t timerMs = 0;
|
||||
|
||||
int16_t curval = pModel->m_value.getValue<int16_t>(nullptr, true);
|
||||
|
||||
if(newval != curval) {
|
||||
pModel->m_targetValue.setValue(newval);
|
||||
|
||||
if(pModel->m_delayTime > 0) {
|
||||
timerMs = 5 * pModel->m_delayTime;
|
||||
}
|
||||
|
||||
if(pModel->m_transTime & 0x3F) {
|
||||
pModel->m_transStep = -1 * ((curval - newval) / (pModel->m_transTime & 0x3F));
|
||||
if(timerMs == 0) {
|
||||
timerMs = NimBLEUtils::meshTransTimeMs(pModel->m_transTime);
|
||||
pModel->m_transTime -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(timerMs > 0) {
|
||||
pModel->startTdTimer(timerMs);
|
||||
} else {
|
||||
pModel->m_value = pModel->m_targetValue;
|
||||
pModel->m_callbacks->setLevel(pModel, newval);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Called by the NimBLE stack to set the level value by delta of the model.
|
||||
*/
|
||||
void NimBLEGenLevelSrvModel::setDelta(bt_mesh_model *model,
|
||||
bt_mesh_msg_ctx *ctx,
|
||||
os_mbuf *buf)
|
||||
{
|
||||
NimBLEGenLevelSrvModel::setDeltaUnack(model, ctx, buf);
|
||||
NimBLEGenLevelSrvModel::getLevel(model, ctx, buf);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Called by the NimBLE stack to set the level value by delta without acknowledgement.
|
||||
*/
|
||||
void NimBLEGenLevelSrvModel::setDeltaUnack(bt_mesh_model *model,
|
||||
bt_mesh_msg_ctx *ctx,
|
||||
os_mbuf *buf)
|
||||
{
|
||||
NimBLEMeshModel *pModel = (NimBLEMeshModel*)model->user_data;
|
||||
int32_t delta = (int32_t) net_buf_simple_pull_le32(buf);
|
||||
|
||||
int32_t temp32 = pModel->m_value.getValue<int16_t>(nullptr, true) + delta;
|
||||
if (temp32 < INT16_MIN) {
|
||||
temp32 = INT16_MIN;
|
||||
} else if (temp32 > INT16_MAX) {
|
||||
temp32 = INT16_MAX;
|
||||
}
|
||||
|
||||
net_buf_simple_push_le16(buf, (uint16_t)temp32);
|
||||
NimBLEGenLevelSrvModel::setLevelUnack(model, ctx, buf);
|
||||
}
|
||||
|
||||
|
||||
void NimBLEGenLevelSrvModel::setMove(bt_mesh_model *model,
|
||||
bt_mesh_msg_ctx *ctx,
|
||||
os_mbuf *buf)
|
||||
{
|
||||
NimBLEGenLevelSrvModel::setMoveUnack(model, ctx, buf);
|
||||
NimBLEGenLevelSrvModel::getLevel(model, ctx, buf);
|
||||
}
|
||||
|
||||
|
||||
void NimBLEGenLevelSrvModel::setMoveUnack(bt_mesh_model *model,
|
||||
bt_mesh_msg_ctx *ctx,
|
||||
os_mbuf *buf)
|
||||
{
|
||||
int16_t delta = (int16_t) net_buf_simple_pull_le16(buf);
|
||||
// Check if a transition time is present, if not then ignore this message.
|
||||
// See: bluetooth mesh specifcation
|
||||
if(buf->om_len < 3) {
|
||||
return;
|
||||
}
|
||||
put_le32(net_buf_simple_push(buf, 4), (int32_t)delta);
|
||||
NimBLEGenLevelSrvModel::setDeltaUnack(model, ctx, buf);
|
||||
}
|
||||
|
||||
|
||||
void NimBLEGenLevelSrvModel::tdTimerCb(ble_npl_event *event) {
|
||||
NimBLEMeshModel *pModel = (NimBLEMeshModel*)event->arg;
|
||||
if(pModel->m_delayTime > 0) {
|
||||
pModel->m_delayTime = 0;
|
||||
}
|
||||
|
||||
if(pModel->m_transTime & 0x3F) {
|
||||
int16_t newval = pModel->m_value.getValue<int16_t>(nullptr, true) + pModel->m_transStep;
|
||||
pModel->m_value.setValue(newval);
|
||||
pModel->m_callbacks->setLevel(pModel, newval);
|
||||
pModel->startTdTimer(NimBLEUtils::meshTransTimeMs(pModel->m_transTime));
|
||||
pModel->m_transTime -= 1;
|
||||
return;
|
||||
}
|
||||
|
||||
pModel->m_transTime = 0;
|
||||
pModel->m_value = pModel->m_targetValue;
|
||||
pModel->m_callbacks->setLevel(pModel, pModel->m_value.getValue<int16_t>(nullptr, true));
|
||||
}
|
||||
|
||||
|
||||
void NimBLEGenLevelSrvModel::pubTimerCb(ble_npl_event *event) {
|
||||
NimBLEMeshModel *pModel = (NimBLEMeshModel*)event->arg;
|
||||
pModel->setPubMsg();
|
||||
|
||||
int err = bt_mesh_model_publish(pModel->m_opPub.mod);
|
||||
if(err != 0) {
|
||||
NIMBLE_LOGD(LOG_TAG, "Publish rc: %d",err);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void NimBLEGenLevelSrvModel::setPubMsg() {
|
||||
bt_mesh_model_msg_init(m_opPub.msg, BT_MESH_MODEL_OP_2(0x82, 0x08));
|
||||
net_buf_simple_add_le16(m_opPub.msg, m_value.getValue<int16_t>(nullptr, true));
|
||||
if(m_transTime > 0) {
|
||||
net_buf_simple_add_le16(m_opPub.msg, m_targetValue.getValue<int16_t>(nullptr, true));
|
||||
// If we started the transition timer in setOnOff we need to correct the reported remaining time.
|
||||
net_buf_simple_add_u8(m_opPub.msg, (m_delayTime > 0) ?
|
||||
m_transTime : m_transTime + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void NimBLEGenLevelSrvModel::setValue(uint8_t *val, size_t len) {
|
||||
if(len != sizeof(int16_t)) {
|
||||
NIMBLE_LOGE(LOG_TAG, "NimBLEGenLevelSrvModel: Incorrect value length");
|
||||
return;
|
||||
}
|
||||
m_value.setValue(val, len);
|
||||
}
|
||||
|
||||
|
||||
void NimBLEGenLevelSrvModel::setTargetValue(uint8_t *val, size_t len) {
|
||||
if(len != sizeof(int16_t)) {
|
||||
NIMBLE_LOGE(LOG_TAG, "NimBLEGenLevelSrvModel: Incorrect target value length");
|
||||
return;
|
||||
}
|
||||
m_targetValue.setValue(val, len);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Health server model constructor
|
||||
* @param [in] pCallbacks, a pointer to a callback instance for model operations
|
||||
*/
|
||||
NimBLEHealthSrvModel::NimBLEHealthSrvModel(NimBLEMeshModelCallbacks *pCallbacks)
|
||||
:NimBLEMeshModel(pCallbacks, 1, 1)
|
||||
{
|
||||
memset(&m_healthSrv, 0, sizeof(m_healthSrv));
|
||||
m_healthSrv.cb = &health_srv_cb;
|
||||
m_opPub.msg = NET_BUF_SIMPLE(1 + 3);
|
||||
m_hasFault = false;
|
||||
m_testId = 0;
|
||||
}
|
||||
|
||||
|
||||
void NimBLEHealthSrvModel::setFault(uint8_t fault) {
|
||||
m_faults.push_back(fault);
|
||||
m_hasFault = true;
|
||||
}
|
||||
|
||||
|
||||
void NimBLEHealthSrvModel::clearFaults() {
|
||||
m_faults.clear();
|
||||
m_hasFault = false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Default model callbacks
|
||||
*/
|
||||
NimBLEMeshModelCallbacks::~NimBLEMeshModelCallbacks() {}
|
||||
|
||||
void NimBLEMeshModelCallbacks::setOnOff(NimBLEMeshModel *pModel, uint8_t val) {
|
||||
NIMBLE_LOGD(LOG_TAG, "Gen On/Off set val: %d", val);
|
||||
}
|
||||
|
||||
uint8_t NimBLEMeshModelCallbacks::getOnOff(NimBLEMeshModel *pModel) {
|
||||
NIMBLE_LOGD(LOG_TAG, "Gen On/Off get");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void NimBLEMeshModelCallbacks::setLevel(NimBLEMeshModel *pModel, int16_t val) {
|
||||
NIMBLE_LOGD(LOG_TAG, "Gen Level set val: %d", val);
|
||||
}
|
||||
|
||||
int16_t NimBLEMeshModelCallbacks::getLevel(NimBLEMeshModel *pModel) {
|
||||
NIMBLE_LOGD(LOG_TAG, "Gen Level get");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void NimBLEMeshModelCallbacks::attentionOn(NimBLEMeshModel *pModel) {
|
||||
NIMBLE_LOGD(LOG_TAG, "Attention On Default");
|
||||
}
|
||||
|
||||
void NimBLEMeshModelCallbacks::attentionOff(NimBLEMeshModel *pModel) {
|
||||
NIMBLE_LOGD(LOG_TAG, "Attention Off Default");
|
||||
}
|
||||
|
||||
void NimBLEMeshModelCallbacks::faultTest(NimBLEMeshModel *pModel) {
|
||||
NIMBLE_LOGD(LOG_TAG, "Fault Test");
|
||||
}
|
||||
|
||||
void NimBLEMeshModelCallbacks::faultClear(NimBLEMeshModel *pModel) {
|
||||
NIMBLE_LOGD(LOG_TAG, "Fault Clear");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Health server callbacks
|
||||
*/
|
||||
int NimBLEHealthSrvCallbacks::faultGetCurrent(bt_mesh_model *model, uint8_t *test_id,
|
||||
uint16_t *company_id, uint8_t *faults,
|
||||
uint8_t *fault_count)
|
||||
{
|
||||
NIMBLE_LOGD(LOG_TAG, "faultGetCurrent");
|
||||
|
||||
NimBLEHealthSrvModel* pModel = (NimBLEHealthSrvModel*)NimBLEDevice::getMeshNode()->getHealthModel(model);
|
||||
*test_id = pModel->m_testId;
|
||||
*company_id = CID_VENDOR;
|
||||
*fault_count = std::min(*(size_t*)fault_count, pModel->m_faults.size());
|
||||
memcpy(faults, &pModel->m_faults[0], *fault_count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int NimBLEHealthSrvCallbacks::faultGetRegistered(bt_mesh_model *model, uint16_t company_id,
|
||||
uint8_t *test_id, uint8_t *faults,
|
||||
uint8_t *fault_count)
|
||||
{
|
||||
NIMBLE_LOGD(LOG_TAG, "faultGetRegistered");
|
||||
|
||||
if (company_id != CID_VENDOR) {
|
||||
return -BLE_HS_EINVAL;
|
||||
}
|
||||
|
||||
NimBLEHealthSrvModel* pModel = (NimBLEHealthSrvModel*)NimBLEDevice::getMeshNode()->getHealthModel(model);
|
||||
*test_id = pModel->m_testId;
|
||||
*fault_count = std::min(*(size_t*)fault_count, pModel->m_faults.size());
|
||||
memcpy(faults, &pModel->m_faults[0], *fault_count);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int NimBLEHealthSrvCallbacks::faultClear(bt_mesh_model *model, uint16_t company_id)
|
||||
{
|
||||
NIMBLE_LOGD(LOG_TAG, "faultClear - default");
|
||||
|
||||
if (company_id != CID_VENDOR) {
|
||||
return -BLE_HS_EINVAL;
|
||||
}
|
||||
|
||||
NimBLEHealthSrvModel* pModel = (NimBLEHealthSrvModel*)NimBLEDevice::getMeshNode()->getHealthModel(model);
|
||||
pModel->m_callbacks->faultClear(pModel);
|
||||
pModel->clearFaults();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int NimBLEHealthSrvCallbacks::faultTest(bt_mesh_model *model, uint8_t test_id, uint16_t company_id)
|
||||
{
|
||||
NIMBLE_LOGD(LOG_TAG, "faultTest - default");
|
||||
|
||||
if (company_id != CID_VENDOR) {
|
||||
return -BLE_HS_EINVAL;
|
||||
}
|
||||
|
||||
if (test_id != STANDARD_TEST_ID) {
|
||||
return -BLE_HS_EINVAL;
|
||||
}
|
||||
|
||||
NimBLEHealthSrvModel* pModel = (NimBLEHealthSrvModel*)NimBLEDevice::getMeshNode()->getHealthModel(model);
|
||||
pModel->setFault(0);
|
||||
pModel->m_testId = test_id;
|
||||
pModel->m_callbacks->faultTest(pModel);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void NimBLEHealthSrvCallbacks::attentionOn(bt_mesh_model *model)
|
||||
{
|
||||
NIMBLE_LOGD(LOG_TAG, "attentionOn - default");
|
||||
NimBLEMeshModel* pModel = NimBLEDevice::getMeshNode()->getHealthModel(model);
|
||||
pModel->m_callbacks->attentionOn(pModel);
|
||||
}
|
||||
|
||||
void NimBLEHealthSrvCallbacks::attentionOff(bt_mesh_model *model)
|
||||
{
|
||||
NIMBLE_LOGD(LOG_TAG, "attentionOff - default");
|
||||
NimBLEMeshModel* pModel = NimBLEDevice::getMeshNode()->getHealthModel(model);
|
||||
pModel->m_callbacks->attentionOff(pModel);
|
||||
}
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_MESH
|
||||
197
src/NimBLEMeshModel.h
Normal file
197
src/NimBLEMeshModel.h
Normal file
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
* NimBLEMeshModel.h
|
||||
*
|
||||
* Created: on Aug 25 2020
|
||||
* Author H2zero
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MAIN_NIMBLE_MESH_MODEL_H_
|
||||
#define MAIN_NIMBLE_MESH_MODEL_H_
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
#include "nimconfig.h"
|
||||
|
||||
#include "NimBLEMeshElement.h"
|
||||
#include "NimBLEAttValue.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
class NimBLEMeshModelCallbacks;
|
||||
|
||||
class NimBLEMeshModel {
|
||||
public:
|
||||
NimBLEMeshModel(NimBLEMeshModelCallbacks* pCallbacks,
|
||||
uint16_t initDataSize = CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH,
|
||||
uint16_t maxDataSize = BLE_ATT_ATTR_MAX_LEN);
|
||||
virtual ~NimBLEMeshModel();
|
||||
int extractTransTimeDelay(os_mbuf *buf);
|
||||
bool checkRetransmit(uint8_t tid, bt_mesh_msg_ctx *ctx);
|
||||
void sendMessage(bt_mesh_model *model, bt_mesh_msg_ctx *ctx, os_mbuf *msg);
|
||||
void startTdTimer(ble_npl_time_t timerMs);
|
||||
void publish();
|
||||
uint32_t getTransTime();
|
||||
uint16_t getDelayTime();
|
||||
virtual void setPubMsg(){};
|
||||
virtual void setValue(uint8_t *val, size_t len){};
|
||||
virtual void setTargetValue(uint8_t *val, size_t len){};
|
||||
virtual void setFault(uint8_t){};
|
||||
virtual void clearFaults(){};
|
||||
|
||||
template<typename T>
|
||||
void setValue(const T &s) {
|
||||
setValue((uint8_t*)&s, sizeof(T));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void setTargetValue(const T &s) {
|
||||
setTargetValue((uint8_t*)&s, sizeof(T));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void getValue(T &s) {
|
||||
s = (T)m_value[0];
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void getTargetValue(T &s) {
|
||||
s = (T)m_targetValue[0];
|
||||
}
|
||||
|
||||
bt_mesh_model_op* m_opList;
|
||||
bt_mesh_model_pub m_opPub;
|
||||
NimBLEMeshModelCallbacks* m_callbacks;
|
||||
uint8_t m_lastTid;
|
||||
uint16_t m_lastSrcAddr;
|
||||
uint16_t m_lastDstAddr;
|
||||
time_t m_lastMsgTime;
|
||||
uint8_t m_transTime;
|
||||
uint8_t m_delayTime;
|
||||
NimBLEAttValue m_value;
|
||||
NimBLEAttValue m_targetValue;
|
||||
int16_t m_transStep;
|
||||
|
||||
ble_npl_callout m_tdTimer;
|
||||
ble_npl_callout m_pubTimer;
|
||||
};
|
||||
|
||||
|
||||
class NimBLEGenOnOffSrvModel : NimBLEMeshModel {
|
||||
friend class NimBLEMeshElement;
|
||||
friend class NimBLEMeshNode;
|
||||
|
||||
NimBLEGenOnOffSrvModel(NimBLEMeshModelCallbacks *pCallbacks);
|
||||
~NimBLEGenOnOffSrvModel(){};
|
||||
|
||||
static void getOnOff(bt_mesh_model *model,
|
||||
bt_mesh_msg_ctx *ctx,
|
||||
os_mbuf *buf);
|
||||
static void setOnOff(bt_mesh_model *model,
|
||||
bt_mesh_msg_ctx *ctx,
|
||||
os_mbuf *buf);
|
||||
static void setOnOffUnack(bt_mesh_model *model,
|
||||
bt_mesh_msg_ctx *ctx,
|
||||
os_mbuf *buf);
|
||||
static void tdTimerCb(ble_npl_event *event);
|
||||
static void pubTimerCb(ble_npl_event *event);
|
||||
|
||||
void setPubMsg() override;
|
||||
void setValue(uint8_t *val, size_t len) override;
|
||||
void setTargetValue(uint8_t *val, size_t len) override;
|
||||
};
|
||||
|
||||
|
||||
class NimBLEGenLevelSrvModel : NimBLEMeshModel {
|
||||
friend class NimBLEMeshElement;
|
||||
friend class NimBLEMeshNode;
|
||||
|
||||
NimBLEGenLevelSrvModel(NimBLEMeshModelCallbacks *pCallbacks);
|
||||
~NimBLEGenLevelSrvModel(){};
|
||||
|
||||
static void getLevel(bt_mesh_model *model,
|
||||
bt_mesh_msg_ctx *ctx,
|
||||
os_mbuf *buf);
|
||||
static void setLevel(bt_mesh_model *model,
|
||||
bt_mesh_msg_ctx *ctx,
|
||||
os_mbuf *buf);
|
||||
static void setLevelUnack(bt_mesh_model *model,
|
||||
bt_mesh_msg_ctx *ctx,
|
||||
os_mbuf *buf);
|
||||
static void setDelta(bt_mesh_model *model,
|
||||
bt_mesh_msg_ctx *ctx,
|
||||
os_mbuf *buf);
|
||||
static void setDeltaUnack(bt_mesh_model *model,
|
||||
bt_mesh_msg_ctx *ctx,
|
||||
os_mbuf *buf);
|
||||
static void setMove(bt_mesh_model *model,
|
||||
bt_mesh_msg_ctx *ctx,
|
||||
os_mbuf *buf);
|
||||
static void setMoveUnack(bt_mesh_model *model,
|
||||
bt_mesh_msg_ctx *ctx,
|
||||
os_mbuf *buf);
|
||||
static void tdTimerCb(ble_npl_event *event);
|
||||
static void pubTimerCb(ble_npl_event *event);
|
||||
|
||||
void setPubMsg() override;
|
||||
void setValue(uint8_t *val, size_t len) override;
|
||||
void setTargetValue(uint8_t *val, size_t len) override;
|
||||
};
|
||||
|
||||
|
||||
class NimBLEHealthSrvModel : NimBLEMeshModel {
|
||||
friend class NimBLEMeshElement;
|
||||
friend class NimBLEMeshNode;
|
||||
friend class NimBLEHealthSrvCallbacks;
|
||||
|
||||
NimBLEHealthSrvModel(NimBLEMeshModelCallbacks *pCallbacks);
|
||||
~NimBLEHealthSrvModel(){};
|
||||
|
||||
public:
|
||||
void setFault(uint8_t) override;
|
||||
void clearFaults() override;
|
||||
|
||||
private:
|
||||
bt_mesh_health_srv m_healthSrv;
|
||||
bool m_hasFault;
|
||||
uint8_t m_testId;
|
||||
std::vector<uint8_t> m_faults;
|
||||
};
|
||||
|
||||
|
||||
class NimBLEMeshModelCallbacks {
|
||||
public:
|
||||
virtual ~NimBLEMeshModelCallbacks();
|
||||
virtual void setOnOff(NimBLEMeshModel *pModel, uint8_t val);
|
||||
virtual uint8_t getOnOff(NimBLEMeshModel *pModel);
|
||||
virtual void setLevel(NimBLEMeshModel *pModel, int16_t val);
|
||||
virtual int16_t getLevel(NimBLEMeshModel *pModel);
|
||||
virtual void attentionOn(NimBLEMeshModel *pModel);
|
||||
virtual void attentionOff(NimBLEMeshModel *pModel);
|
||||
virtual void faultTest(NimBLEMeshModel *pModel);
|
||||
virtual void faultClear(NimBLEMeshModel *pModel);
|
||||
|
||||
};
|
||||
|
||||
|
||||
class NimBLEHealthSrvCallbacks {
|
||||
public:
|
||||
static int faultGetCurrent(bt_mesh_model *model, uint8_t *test_id,
|
||||
uint16_t *company_id, uint8_t *faults,
|
||||
uint8_t *fault_count);
|
||||
|
||||
static int faultGetRegistered(bt_mesh_model *model, uint16_t company_id,
|
||||
uint8_t *test_id, uint8_t *faults,
|
||||
uint8_t *fault_count);
|
||||
|
||||
static int faultClear(bt_mesh_model *model, uint16_t company_id);
|
||||
|
||||
static int faultTest(bt_mesh_model *model, uint8_t test_id, uint16_t company_id);
|
||||
|
||||
static void attentionOn(bt_mesh_model *model);
|
||||
|
||||
static void attentionOff(bt_mesh_model *model);
|
||||
};
|
||||
|
||||
#endif // CONFIG_BT_ENABLED
|
||||
#endif // MAIN_NIMBLE_MESH_MODEL_H_
|
||||
209
src/NimBLEMeshNode.cpp
Normal file
209
src/NimBLEMeshNode.cpp
Normal file
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* NimBLEMeshNode.cpp
|
||||
*
|
||||
* Created: on July 22 2020
|
||||
* Author H2zero
|
||||
*
|
||||
*/
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if CONFIG_BT_NIMBLE_MESH
|
||||
|
||||
#include "NimBLEMeshNode.h"
|
||||
#include "NimBLELog.h"
|
||||
#include "NimBLEDevice.h"
|
||||
#include "NimBLEMeshCreateModel.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
|
||||
|
||||
|
||||
|
||||
#define CID_VENDOR 0x05C3
|
||||
|
||||
static const char* LOG_TAG = "NimBLEMeshNode";
|
||||
|
||||
|
||||
/**
|
||||
* @brief Construct a mesh node.
|
||||
* @param [in] uuid The uuid used to advertise for provisioning.
|
||||
* @param [in] type Bitmask of the node features supported.
|
||||
*/
|
||||
NimBLEMeshNode::NimBLEMeshNode(const NimBLEUUID &uuid, uint8_t type) {
|
||||
assert(uuid.bitSize() == 128);
|
||||
|
||||
memset(&m_serverConfig, 0, sizeof(m_serverConfig));
|
||||
memset(&m_prov, 0, sizeof(m_prov));
|
||||
memset(&m_comp, 0, sizeof(m_comp));
|
||||
|
||||
// Default server config
|
||||
m_serverConfig.relay = BT_MESH_RELAY_DISABLED;/*(type & NIMBLE_MESH::RELAY) ?
|
||||
BT_MESH_RELAY_ENABLED :
|
||||
BT_MESH_RELAY_DISABLED;*/
|
||||
|
||||
m_serverConfig.beacon = BT_MESH_BEACON_ENABLED;
|
||||
m_serverConfig.frnd = BT_MESH_FRIEND_DISABLED;/*(type & NIMBLE_MESH::FRIEND) ?
|
||||
BT_MESH_FRIEND_ENABLED :
|
||||
BT_MESH_FRIEND_DISABLED;*/
|
||||
|
||||
m_serverConfig.gatt_proxy = BT_MESH_GATT_PROXY_ENABLED; /*(type & NIMBLE_MESH::RELAY) ?
|
||||
BT_MESH_GATT_PROXY_ENABLED :
|
||||
BT_MESH_GATT_PROXY_DISABLED;*/
|
||||
|
||||
m_serverConfig.default_ttl = 7;
|
||||
|
||||
// 3 transmissions with 20ms interval
|
||||
m_serverConfig.net_transmit = BT_MESH_TRANSMIT(2, 20);
|
||||
m_serverConfig.relay_retransmit = BT_MESH_TRANSMIT(2, 20);
|
||||
|
||||
// Provisioning config
|
||||
m_uuid = uuid;
|
||||
m_prov.uuid = m_uuid.getNative()->u128.value;
|
||||
m_prov.complete = NimBLEMeshNode::provComplete;
|
||||
m_prov.reset = NimBLEMeshNode::provReset;
|
||||
|
||||
// Create the primary element
|
||||
m_elemVec.push_back(new NimBLEMeshElement());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Destructor, cleanup any resources created.
|
||||
*/
|
||||
NimBLEMeshNode::~NimBLEMeshNode() {
|
||||
if(m_comp.elem != nullptr) {
|
||||
free (m_comp.elem);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Called from the callbacks when provisioning changes.
|
||||
*/
|
||||
void NimBLEMeshNode::setProvData(uint16_t netIdx, uint16_t addr) {
|
||||
m_primAddr = addr;
|
||||
m_primNetIdx = netIdx;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief callback, Called by NimBLE stack when provisioning is complete.
|
||||
*/
|
||||
void NimBLEMeshNode::provComplete(uint16_t netIdx, uint16_t addr) {
|
||||
NIMBLE_LOGI(LOG_TAG,
|
||||
"provisioning complete for netIdx 0x%04x addr 0x%04x",
|
||||
netIdx, addr);
|
||||
NimBLEDevice::getMeshNode()->setProvData(netIdx, addr);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief callback, Called by NimBLE stack when provisioning is reset.
|
||||
*/
|
||||
void NimBLEMeshNode::provReset() {
|
||||
NIMBLE_LOGI(LOG_TAG, "provisioning reset");
|
||||
NimBLEDevice::getMeshNode()->setProvData(0, 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief get a pointer an element.
|
||||
* @param [in] index The element vector index of the element.
|
||||
* @returns a pointer to the element requested.
|
||||
*/
|
||||
NimBLEMeshElement* NimBLEMeshNode::getElement(uint8_t index) {
|
||||
return m_elemVec[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a new mesh element.
|
||||
* @returns a pointer to the newly created element.
|
||||
*/
|
||||
NimBLEMeshElement* NimBLEMeshNode::createElement() {
|
||||
m_elemVec.push_back(new NimBLEMeshElement());
|
||||
return m_elemVec.back();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get a pointer to the health model instance that matches the ID's of the input model.
|
||||
* @param [in] model A pointer to the NimBLE internal model instance.
|
||||
* @returns A pointer to the model.
|
||||
*/
|
||||
NimBLEMeshModel* NimBLEMeshNode::getHealthModel(bt_mesh_model *model) {
|
||||
NimBLEMeshModel* pModel;
|
||||
|
||||
for(auto &it : m_elemVec) {
|
||||
pModel = it->getModelByIdx(model->elem_idx, model->mod_idx, BT_MESH_MODEL_ID_HEALTH_SRV);
|
||||
if(pModel != nullptr) {
|
||||
return pModel;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Start the Mesh mode.
|
||||
* @returns true on success.
|
||||
*/
|
||||
bool NimBLEMeshNode::start() {
|
||||
// Reset and restart gatts so we can register mesh gatt
|
||||
ble_gatts_reset();
|
||||
ble_svc_gap_init();
|
||||
ble_svc_gatt_init();
|
||||
bt_mesh_register_gatt();
|
||||
ble_gatts_start();
|
||||
|
||||
// Config server and primary health models are required in the primary element
|
||||
// create them here and add them as the first models.
|
||||
m_elemVec[0]->addModel(createConfigSrvModel(&m_serverConfig));
|
||||
|
||||
if(m_elemVec[0]->getModel(BT_MESH_MODEL_ID_HEALTH_SRV) == nullptr) {
|
||||
m_elemVec[0]->createModel(BT_MESH_MODEL_ID_HEALTH_SRV);
|
||||
}
|
||||
|
||||
// setup node composition
|
||||
m_comp.cid = CID_VENDOR;
|
||||
m_comp.elem = (bt_mesh_elem*)calloc(m_elemVec.size(), sizeof(bt_mesh_elem));
|
||||
|
||||
if(m_comp.elem == nullptr) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Error: No Mem");
|
||||
return false;
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < m_elemVec.size(); i++) {
|
||||
memcpy((void*)&m_comp.elem[i], (void*)m_elemVec[i]->start(), sizeof(bt_mesh_elem));
|
||||
}
|
||||
m_comp.elem_count = (uint8_t)m_elemVec.size();
|
||||
|
||||
// Use random address
|
||||
ble_addr_t addr;
|
||||
int err = ble_hs_id_gen_rnd(1, &addr);
|
||||
assert(err == 0);
|
||||
err = ble_hs_id_set_rnd(addr.val);
|
||||
assert(err == 0);
|
||||
|
||||
err = bt_mesh_init(addr.type, &m_prov, &m_comp);
|
||||
if (err) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Initializing mesh failed (err %d)", err);
|
||||
return false;
|
||||
}
|
||||
if (IS_ENABLED(CONFIG_SETTINGS)) {
|
||||
settings_load();
|
||||
}
|
||||
|
||||
if (bt_mesh_is_provisioned()) {
|
||||
NIMBLE_LOGI(LOG_TAG, "Mesh network restored from flash");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_MESH
|
||||
76
src/NimBLEMeshNode.h
Normal file
76
src/NimBLEMeshNode.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* NimBLEMeshNode.h
|
||||
*
|
||||
* Created: on July 22 2020
|
||||
* Author H2zero
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MAIN_NIMBLE_MESH_NODE_H_
|
||||
#define MAIN_NIMBLE_MESH_NODE_H_
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wpointer-arith"
|
||||
#if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
# include "mesh/glue.h"
|
||||
# include "mesh/mesh.h"
|
||||
#else
|
||||
# include "nimble/nimble/host/mesh/include/mesh/glue.h"
|
||||
# include "nimble/nimble/host/mesh/include/mesh/mesh.h"
|
||||
#endif
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
/**** FIX COMPILATION ****/
|
||||
#undef min
|
||||
#undef max
|
||||
/**************************/
|
||||
|
||||
#include "NimBLEUUID.h"
|
||||
#include "NimBLEMeshElement.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
class NimBLEMeshModel;
|
||||
|
||||
typedef enum {
|
||||
RELAY = 0x01 << 0,
|
||||
BEACON = 0x01 << 1,
|
||||
FRIEND = 0x01 << 2,
|
||||
PROXY = 0x01 << 3,
|
||||
} NIMBLE_MESH;
|
||||
|
||||
class NimBLEMeshElement;
|
||||
|
||||
class NimBLEMeshNode {
|
||||
public:
|
||||
bool start();
|
||||
NimBLEMeshElement* createElement();
|
||||
NimBLEMeshElement* getElement(uint8_t index = 0);
|
||||
NimBLEMeshModel* getHealthModel(bt_mesh_model *model);
|
||||
|
||||
private:
|
||||
friend class NimBLEDevice;
|
||||
friend class NimBLEMeshElement;
|
||||
|
||||
NimBLEMeshNode(const NimBLEUUID &uuid, uint8_t type);
|
||||
~NimBLEMeshNode();
|
||||
static void provComplete(uint16_t netIdx, uint16_t addr);
|
||||
static void provReset();
|
||||
void setProvData(uint16_t netIdx, uint16_t addr);
|
||||
|
||||
bt_mesh_cfg_srv m_serverConfig;
|
||||
bt_mesh_prov m_prov;
|
||||
bt_mesh_comp m_comp;
|
||||
uint16_t m_primAddr;
|
||||
uint16_t m_primNetIdx;
|
||||
NimBLEUUID m_uuid;
|
||||
|
||||
std::vector<NimBLEMeshElement*> m_elemVec;
|
||||
};
|
||||
|
||||
|
||||
#endif // CONFIG_BT_ENABLED
|
||||
#endif // MAIN_NIMBLE_MESH_NODE_H_
|
||||
@@ -165,7 +165,7 @@ std::vector<NimBLERemoteCharacteristic*>* NimBLERemoteService::getCharacteristic
|
||||
|
||||
|
||||
/**
|
||||
* @brief Callback for Characteristic discovery.
|
||||
* @brief Callback for Characterisic discovery.
|
||||
* @return success == 0 or error code.
|
||||
*/
|
||||
int NimBLERemoteService::characteristicDiscCB(uint16_t conn_handle,
|
||||
|
||||
@@ -34,7 +34,7 @@ NimBLEScan::NimBLEScan() {
|
||||
m_scan_params.itvl = 0; // This is defined as the time interval from when the Controller started its last LE scan until it begins the subsequent LE scan. (units=0.625 msec)
|
||||
m_scan_params.window = 0; // The duration of the LE scan. LE_Scan_Window shall be less than or equal to LE_Scan_Interval (units=0.625 msec)
|
||||
m_scan_params.limited = 0; // If set, only discover devices in limited discoverable mode.
|
||||
m_scan_params.filter_duplicates = 1; // If set, the controller ignores all but the first advertisement from each device.
|
||||
m_scan_params.filter_duplicates = 0; // If set, the controller ignores all but the first advertisement from each device.
|
||||
m_pAdvertisedDeviceCallbacks = nullptr;
|
||||
m_ignoreResults = false;
|
||||
m_pTaskData = nullptr;
|
||||
@@ -134,10 +134,6 @@ NimBLEScan::~NimBLEScan() {
|
||||
event_type == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP));
|
||||
|
||||
if (pScan->m_pAdvertisedDeviceCallbacks) {
|
||||
if (pScan->m_scan_params.filter_duplicates && advertisedDevice->m_callbackSent) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If not active scanning or scan response is not available
|
||||
// or extended advertisement scanning, report the result to the callback now.
|
||||
if(pScan->m_scan_params.passive || !isLegacyAdv ||
|
||||
@@ -164,7 +160,7 @@ NimBLEScan::~NimBLEScan() {
|
||||
NIMBLE_LOGD(LOG_TAG, "discovery complete; reason=%d",
|
||||
event->disc_complete.reason);
|
||||
|
||||
// If a device advertised with scan response available and it was not received
|
||||
// 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) {
|
||||
@@ -211,7 +207,7 @@ void NimBLEScan::setActiveScan(bool active) {
|
||||
* from devices it has not already seen.
|
||||
* @param [in] enabled If true, scanned devices will only be reported once.
|
||||
* @details The controller has a limited buffer and will start reporting
|
||||
* duplicate devices once the limit is reached.
|
||||
* dupicate devices once the limit is reached.
|
||||
*/
|
||||
void NimBLEScan::setDuplicateFilter(bool enabled) {
|
||||
m_scan_params.filter_duplicates = enabled;
|
||||
@@ -236,7 +232,7 @@ void NimBLEScan::setLimitedOnly(bool enabled) {
|
||||
* directed, connectable advertising packets not sent to the scanner.
|
||||
* * BLE_HCI_SCAN_FILT_USE_WL (1)
|
||||
* Scanner processes advertisements from white list only. A connectable,\n
|
||||
* directed advertisement is ignored unless it contains scanners address.
|
||||
* directed advertisment is ignored unless it contains scanners address.
|
||||
* * BLE_HCI_SCAN_FILT_NO_WL_INITA (2)
|
||||
* Scanner process all advertising packets (white list not used). A\n
|
||||
* connectable, directed advertisement shall not be ignored if the InitA
|
||||
|
||||
@@ -61,8 +61,8 @@ void NimBLESecurity::setCapability(esp_ble_io_cap_t iocap) {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Sets the keys we will distribute during encryption.
|
||||
* @param [in] init_key A bitmask of the keys we will distribute.\n
|
||||
* @brief Sets the keys we will distibute during encryption.
|
||||
* @param [in] init_key A bitmask of the keys we will distibute.\n
|
||||
* Can be one or more of:
|
||||
* * ESP_BLE_ENC_KEY_MASK (1 << 0)
|
||||
* * ESP_BLE_ID_KEY_MASK (1 << 1)
|
||||
|
||||
@@ -373,7 +373,7 @@ int NimBLEServer::handleGapEvent(struct ble_gap_event *event, void *arg) {
|
||||
|
||||
case BLE_GAP_EVENT_DISCONNECT: {
|
||||
// If Host reset tell the device now before returning to prevent
|
||||
// any errors caused by calling host functions before resync.
|
||||
// any errors caused by calling host functions before resyncing.
|
||||
switch(event->disconnect.reason) {
|
||||
case BLE_HS_ETIMEOUT_HCI:
|
||||
case BLE_HS_EOS:
|
||||
@@ -636,7 +636,7 @@ void NimBLEServer::setCallbacks(NimBLEServerCallbacks* pCallbacks, bool deleteCa
|
||||
* @brief Remove a service from the server.
|
||||
*
|
||||
* @details Immediately removes access to the service by clients, sends a service changed indication,
|
||||
* and removes the service (if applicable) from the advertisements.
|
||||
* and removes the service (if applicable) from the advertisments.
|
||||
* The service is not deleted unless the deleteSvc parameter is true, otherwise the service remains
|
||||
* available and can be re-added in the future. If desired a removed but not deleted service can
|
||||
* be deleted later by calling this method with deleteSvc set to true.
|
||||
|
||||
@@ -58,8 +58,7 @@ public:
|
||||
int duration = 0,
|
||||
int max_events = 0);
|
||||
bool stopAdvertising(uint8_t inst_id);
|
||||
#endif
|
||||
# if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_)
|
||||
#else
|
||||
NimBLEAdvertising* getAdvertising();
|
||||
bool startAdvertising();
|
||||
#endif
|
||||
@@ -152,7 +151,7 @@ public:
|
||||
* @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 containing information
|
||||
* @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);
|
||||
@@ -160,7 +159,7 @@ public:
|
||||
/**
|
||||
* @brief Called when the connection MTU changes.
|
||||
* @param [in] MTU The new MTU value.
|
||||
* @param [in] desc A pointer to the connection description structure containing information
|
||||
* @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);
|
||||
|
||||
@@ -297,7 +297,7 @@ std::string NimBLEUUID::toString() const {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Convenience operator to check if this UUID is equal to another.
|
||||
* @brief Convienience operator to check if this UUID is equal to another.
|
||||
*/
|
||||
bool NimBLEUUID::operator ==(const NimBLEUUID & rhs) const {
|
||||
if(m_valueSet && rhs.m_valueSet) {
|
||||
@@ -336,7 +336,7 @@ bool NimBLEUUID::operator ==(const NimBLEUUID & rhs) const {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Convenience operator to check if this UUID is not equal to another.
|
||||
* @brief Convienience operator to check if this UUID is not equal to another.
|
||||
*/
|
||||
bool NimBLEUUID::operator !=(const NimBLEUUID & rhs) const {
|
||||
return !this->operator==(rhs);
|
||||
@@ -344,7 +344,7 @@ bool NimBLEUUID::operator !=(const NimBLEUUID & rhs) const {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Convenience operator to convert this UUID to string representation.
|
||||
* @brief Convienience operator to convert this UUID to string representation.
|
||||
* @details This allows passing NimBLEUUID to functions
|
||||
* that accept std::string and/or or it's methods as a parameter.
|
||||
*/
|
||||
|
||||
@@ -54,6 +54,22 @@ int NimBLEUtils::checkConnParams(ble_gap_conn_params* params) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ble_npl_time_t NimBLEUtils::meshTransTimeMs(uint8_t tt) {
|
||||
switch(tt >> 6) {
|
||||
case 0:
|
||||
return 100;
|
||||
case 1:
|
||||
return 1000;
|
||||
case 2:
|
||||
return 10000;
|
||||
case 3:
|
||||
return 600000;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Converts a return code from the NimBLE stack to a text string.
|
||||
@@ -355,7 +371,7 @@ const char* NimBLEUtils::returnCodeToString(int rc) {
|
||||
* @return A string representation of the advertising flags.
|
||||
*/
|
||||
const char* NimBLEUtils::advTypeToString(uint8_t advType) {
|
||||
#if defined(CONFIG_NIMBLE_CPP_ENABLE_ADVERTISEMENT_TYPE_TEXT)
|
||||
#if defined(CONFIG_NIMBLE_CPP_ENABLE_ADVERTISMENT_TYPE_TEXT)
|
||||
switch(advType) {
|
||||
case BLE_HCI_ADV_TYPE_ADV_IND : //0
|
||||
return "Undirected - Connectable / Scannable";
|
||||
@@ -370,10 +386,10 @@ const char* NimBLEUtils::advTypeToString(uint8_t advType) {
|
||||
default:
|
||||
return "Unknown flag";
|
||||
}
|
||||
#else // #if defined(CONFIG_NIMBLE_CPP_ENABLE_ADVERTISEMENT_TYPE_TEXT)
|
||||
#else // #if defined(CONFIG_NIMBLE_CPP_ENABLE_ADVERTISMENT_TYPE_TEXT)
|
||||
(void)advType;
|
||||
return "";
|
||||
#endif // #if defined(CONFIG_NIMBLE_CPP_ENABLE_ADVERTISEMENT_TYPE_TEXT)
|
||||
#endif // #if defined(CONFIG_NIMBLE_CPP_ENABLE_ADVERTISMENT_TYPE_TEXT)
|
||||
} // adFlagsToString
|
||||
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@ public:
|
||||
static const char* advTypeToString(uint8_t advType);
|
||||
static const char* returnCodeToString(int rc);
|
||||
static int checkConnParams(ble_gap_conn_params* params);
|
||||
static ble_npl_time_t meshTransTimeMs(uint8_t tt);
|
||||
};
|
||||
|
||||
|
||||
|
||||
295
src/mesh_config_store/base64/base64.h
Normal file
295
src/mesh_config_store/base64/base64.h
Normal file
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
#ifndef __UTIL_BASE64_H
|
||||
#define __UTIL_BASE64_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct base64_decoder {
|
||||
/*** public */
|
||||
const char *src;
|
||||
void *dst;
|
||||
int src_len; /* <=0 if src ends with '\0' */
|
||||
int dst_len; /* <=0 if dst unbounded */
|
||||
|
||||
/*** private */
|
||||
char buf[4];
|
||||
int buf_len;
|
||||
};
|
||||
|
||||
static const char base64_chars[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
static int
|
||||
pos(char c)
|
||||
{
|
||||
const char *p;
|
||||
for (p = base64_chars; *p; p++)
|
||||
if (*p == c)
|
||||
return p - base64_chars;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
base64_encode(const void *data, int size, char *s, uint8_t should_pad)
|
||||
{
|
||||
char *p;
|
||||
int i;
|
||||
int c;
|
||||
const unsigned char *q;
|
||||
char *last;
|
||||
int diff;
|
||||
|
||||
p = s;
|
||||
|
||||
q = (const unsigned char *) data;
|
||||
last = NULL;
|
||||
i = 0;
|
||||
while (i < size) {
|
||||
c = q[i++];
|
||||
c *= 256;
|
||||
if (i < size)
|
||||
c += q[i];
|
||||
i++;
|
||||
c *= 256;
|
||||
if (i < size)
|
||||
c += q[i];
|
||||
i++;
|
||||
p[0] = base64_chars[(c & 0x00fc0000) >> 18];
|
||||
p[1] = base64_chars[(c & 0x0003f000) >> 12];
|
||||
p[2] = base64_chars[(c & 0x00000fc0) >> 6];
|
||||
p[3] = base64_chars[(c & 0x0000003f) >> 0];
|
||||
last = p;
|
||||
p += 4;
|
||||
}
|
||||
|
||||
if (last) {
|
||||
diff = i - size;
|
||||
if (diff > 0) {
|
||||
if (should_pad) {
|
||||
memset(last + (4 - diff), '=', diff);
|
||||
} else {
|
||||
p = last + (4 - diff);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*p = 0;
|
||||
|
||||
return (p - s);
|
||||
}
|
||||
|
||||
int
|
||||
base64_pad(char *buf, int len)
|
||||
{
|
||||
int remainder;
|
||||
|
||||
remainder = len % 4;
|
||||
if (remainder == 0) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
memset(buf, '=', 4 - remainder);
|
||||
|
||||
return (4 - remainder);
|
||||
}
|
||||
|
||||
#define DECODE_ERROR -1
|
||||
|
||||
static unsigned int
|
||||
token_decode(const char *token, int len)
|
||||
{
|
||||
int i;
|
||||
unsigned int val = 0;
|
||||
int marker = 0;
|
||||
|
||||
if (len < 4) {
|
||||
return DECODE_ERROR;
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
val *= 64;
|
||||
if (token[i] == '=') {
|
||||
marker++;
|
||||
} else if (marker > 0) {
|
||||
return DECODE_ERROR;
|
||||
} else {
|
||||
val += pos(token[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (marker > 2) {
|
||||
return DECODE_ERROR;
|
||||
}
|
||||
|
||||
return (marker << 24) | val;
|
||||
}
|
||||
|
||||
int
|
||||
base64_decoder_go(struct base64_decoder *dec)
|
||||
{
|
||||
unsigned int marker;
|
||||
unsigned int val;
|
||||
uint8_t *dst;
|
||||
char sval;
|
||||
int read_len;
|
||||
int src_len;
|
||||
int src_rem;
|
||||
int src_off;
|
||||
int dst_len;
|
||||
int dst_off;
|
||||
int i;
|
||||
|
||||
dst = dec->dst;
|
||||
dst_off = 0;
|
||||
src_off = 0;
|
||||
|
||||
/* A length <= 0 means "unbounded". */
|
||||
if (dec->src_len <= 0) {
|
||||
src_len = INT_MAX;
|
||||
} else {
|
||||
src_len = dec->src_len;
|
||||
}
|
||||
if (dec->dst_len <= 0) {
|
||||
dst_len = INT_MAX;
|
||||
} else {
|
||||
dst_len = dec->dst_len;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
src_rem = src_len - src_off;
|
||||
if (src_rem == 0) {
|
||||
/* End of source input. */
|
||||
break;
|
||||
}
|
||||
|
||||
if (dec->src[src_off] == '\0') {
|
||||
/* End of source string. */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Account for possibility of partial token from previous call. */
|
||||
read_len = 4 - dec->buf_len;
|
||||
|
||||
/* Detect invalid input. */
|
||||
for (i = 0; i < read_len; i++) {
|
||||
sval = dec->src[src_off + i];
|
||||
if (sval == '\0') {
|
||||
/* Incomplete input. */
|
||||
return -1;
|
||||
}
|
||||
if (sval != '=' && strchr(base64_chars, sval) == NULL) {
|
||||
/* Invalid base64 character. */
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (src_rem < read_len) {
|
||||
/* Input contains a partial token. Stash it for use during the
|
||||
* next call.
|
||||
*/
|
||||
memcpy(&dec->buf[dec->buf_len], &dec->src[src_off], src_rem);
|
||||
dec->buf_len += src_rem;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Copy full token into buf and decode it. */
|
||||
memcpy(&dec->buf[dec->buf_len], &dec->src[src_off], read_len);
|
||||
val = token_decode(dec->buf, read_len);
|
||||
if (val == DECODE_ERROR) {
|
||||
return -1;
|
||||
}
|
||||
src_off += read_len;
|
||||
dec->buf_len = 0;
|
||||
|
||||
marker = (val >> 24) & 0xff;
|
||||
|
||||
if (dst_off >= dst_len) {
|
||||
break;
|
||||
}
|
||||
dst[dst_off] = (val >> 16) & 0xff;
|
||||
dst_off++;
|
||||
|
||||
if (marker < 2) {
|
||||
if (dst_off >= dst_len) {
|
||||
break;
|
||||
}
|
||||
dst[dst_off] = (val >> 8) & 0xff;
|
||||
dst_off++;
|
||||
}
|
||||
|
||||
if (marker < 1) {
|
||||
if (dst_off >= dst_len) {
|
||||
break;
|
||||
}
|
||||
dst[dst_off] = val & 0xff;
|
||||
dst_off++;
|
||||
}
|
||||
}
|
||||
|
||||
return dst_off;
|
||||
}
|
||||
|
||||
int
|
||||
base64_decode(const char *str, void *data)
|
||||
{
|
||||
struct base64_decoder dec = {
|
||||
.src = str,
|
||||
.dst = data,
|
||||
};
|
||||
|
||||
return base64_decoder_go(&dec);
|
||||
}
|
||||
|
||||
int
|
||||
base64_decode_maxlen(const char *str, void *data, int len)
|
||||
{
|
||||
struct base64_decoder dec = {
|
||||
.src = str,
|
||||
.dst = data,
|
||||
.dst_len = len,
|
||||
};
|
||||
|
||||
return base64_decoder_go(&dec);
|
||||
}
|
||||
|
||||
int
|
||||
base64_decode_len(const char *str)
|
||||
{
|
||||
int len;
|
||||
|
||||
len = strlen(str);
|
||||
while (len && str[len - 1] == '=') {
|
||||
len--;
|
||||
}
|
||||
return len * 3 / 4;
|
||||
}
|
||||
|
||||
#define BASE64_ENCODE_SIZE(__size) (((((__size) - 1) / 3) * 4) + 4)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __UTIL_BASE64_H__ */
|
||||
238
src/mesh_config_store/config/config.h
Normal file
238
src/mesh_config_store/config/config.h
Normal file
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
#ifndef __SYS_CONFIG_H_
|
||||
#define __SYS_CONFIG_H_
|
||||
|
||||
#include "../../nimconfig.h"
|
||||
#if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
# include <os/queue.h>
|
||||
#else
|
||||
# include "nimble/porting/nimble/include/os/queue.h"
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define CONF_MAX_DIR_DEPTH 8 /* max depth of config tree */
|
||||
#define CONF_MAX_NAME_LEN (8 * CONF_MAX_DIR_DEPTH)
|
||||
|
||||
/**
|
||||
* Type of configuration value.
|
||||
*/
|
||||
typedef enum conf_type {
|
||||
CONF_NONE = 0,
|
||||
CONF_DIR,
|
||||
/** 8-bit signed integer */
|
||||
CONF_INT8,
|
||||
/** 16-bit signed integer */
|
||||
CONF_INT16,
|
||||
/** 32-bit signed integer */
|
||||
CONF_INT32,
|
||||
/** 64-bit signed integer */
|
||||
CONF_INT64,
|
||||
/** String */
|
||||
CONF_STRING,
|
||||
/** Bytes */
|
||||
CONF_BYTES,
|
||||
/** Floating point */
|
||||
CONF_FLOAT,
|
||||
/** Double precision */
|
||||
CONF_DOUBLE,
|
||||
/** Boolean */
|
||||
CONF_BOOL,
|
||||
/** 8-bit unsigned integer */
|
||||
CONF_UINT8,
|
||||
/** 16-bit unsigned integer */
|
||||
CONF_UINT16,
|
||||
/** 32-bit unsigned integer */
|
||||
CONF_UINT32,
|
||||
/** 64-bit unsigned integer */
|
||||
CONF_UINT64,
|
||||
} __attribute__((__packed__)) conf_type_t;
|
||||
|
||||
/**
|
||||
* Parameter to commit handler describing where data is going to.
|
||||
*/
|
||||
enum conf_export_tgt {
|
||||
/** Value is to be persisted */
|
||||
CONF_EXPORT_PERSIST,
|
||||
/** Value is to be display */
|
||||
CONF_EXPORT_SHOW
|
||||
};
|
||||
|
||||
typedef enum conf_export_tgt conf_export_tgt_t;
|
||||
|
||||
/**
|
||||
* Handler for getting configuration items, this handler is called
|
||||
* per-configuration section. Configuration sections are delimited
|
||||
* by '/', for example:
|
||||
*
|
||||
* - section/name/value
|
||||
*
|
||||
* Would be passed as:
|
||||
*
|
||||
* - argc = 3
|
||||
* - argv[0] = section
|
||||
* - argv[1] = name
|
||||
* - argv[2] = value
|
||||
*
|
||||
* The handler returns the value into val, null terminated, up to
|
||||
* val_len_max.
|
||||
*
|
||||
* @param argc The number of sections in the configuration variable
|
||||
* @param argv The array of configuration sections
|
||||
* @param val A pointer to the buffer to return the configuration
|
||||
* value into.
|
||||
* @param val_len_max The maximum length of the val buffer to copy into.
|
||||
*
|
||||
* @return A pointer to val or NULL if error.
|
||||
*/
|
||||
typedef char *(*conf_get_handler_t)(int argc, char **argv, char *val, int val_len_max);
|
||||
typedef char *(*conf_get_handler_ext_t)(int argc, char **argv, char *val, int val_len_max, void *arg);
|
||||
|
||||
/**
|
||||
* Set the configuration variable pointed to by argc and argv. See
|
||||
* description of ch_get_handler_t for format of these variables. This sets the
|
||||
* configuration variable to the shadow value, but does not apply the configuration
|
||||
* change. In order to apply the change, call the ch_commit() handler.
|
||||
*
|
||||
* @param argc The number of sections in the configuration variable.
|
||||
* @param argv The array of configuration sections
|
||||
* @param val The value to configure that variable to
|
||||
*
|
||||
* @return 0 on success, non-zero error code on failure.
|
||||
*/
|
||||
typedef int (*conf_set_handler_t)(int argc, char **argv, char *val);
|
||||
typedef int (*conf_set_handler_ext_t)(int argc, char **argv, char *val, void *arg);
|
||||
|
||||
/**
|
||||
* Commit shadow configuration state to the active configuration.
|
||||
*
|
||||
* @return 0 on success, non-zero error code on failure.
|
||||
*/
|
||||
typedef int (*conf_commit_handler_t)(void);
|
||||
typedef int (*conf_commit_handler_ext_t)(void *arg);
|
||||
|
||||
/**
|
||||
* Called per-configuration variable being exported.
|
||||
*
|
||||
* @param name The name of the variable to export
|
||||
* @param val The value of the variable to export
|
||||
*/
|
||||
typedef void (*conf_export_func_t)(char *name, char *val);
|
||||
|
||||
/**
|
||||
* Export all of the configuration variables, calling the export_func
|
||||
* per variable being exported.
|
||||
*
|
||||
* @param export_func The export function to call.
|
||||
* @param tgt The target of the export, either for persistence or display.
|
||||
*
|
||||
* @return 0 on success, non-zero error code on failure.
|
||||
*/
|
||||
typedef int (*conf_export_handler_t)(conf_export_func_t export_func,
|
||||
conf_export_tgt_t tgt);
|
||||
typedef int (*conf_export_handler_ext_t)(conf_export_func_t export_func,
|
||||
conf_export_tgt_t tgt, void *arg);
|
||||
|
||||
/**
|
||||
* Configuration handler, used to register a config item/subtree.
|
||||
*/
|
||||
struct conf_handler {
|
||||
SLIST_ENTRY(conf_handler) ch_list;
|
||||
/**
|
||||
* The name of the conifguration item/subtree
|
||||
*/
|
||||
char *ch_name;
|
||||
|
||||
/**
|
||||
* Whether to use the extended callbacks.
|
||||
* false: standard
|
||||
* true: extended
|
||||
*/
|
||||
bool ch_ext;
|
||||
|
||||
/** Get configuration value */
|
||||
union {
|
||||
conf_get_handler_t ch_get;
|
||||
conf_get_handler_ext_t ch_get_ext;
|
||||
};
|
||||
|
||||
/** Set configuration value */
|
||||
union {
|
||||
conf_set_handler_t ch_set;
|
||||
conf_set_handler_ext_t ch_set_ext;
|
||||
};
|
||||
|
||||
/** Commit configuration value */
|
||||
union {
|
||||
conf_commit_handler_t ch_commit;
|
||||
conf_commit_handler_ext_t ch_commit_ext;
|
||||
};
|
||||
|
||||
/** Export configuration value */
|
||||
union {
|
||||
conf_export_handler_t ch_export;
|
||||
conf_export_handler_ext_t ch_export_ext;
|
||||
};
|
||||
|
||||
/** Custom argument that gets passed to the extended callbacks */
|
||||
void *ch_arg;
|
||||
};
|
||||
|
||||
/**
|
||||
* Register a handler for configurations items.
|
||||
*
|
||||
* @param cf Structure containing registration info.
|
||||
*
|
||||
* @return 0 on success, non-zero on failure.
|
||||
*/
|
||||
int conf_register(struct conf_handler *cf);
|
||||
|
||||
/**
|
||||
* Load configuration from registered persistence sources. Handlers for
|
||||
* configuration subtrees registered earlier will be called for encountered
|
||||
* values.
|
||||
*
|
||||
* @return 0 on success, non-zero on failure.
|
||||
*/
|
||||
int conf_load(void);
|
||||
|
||||
/**
|
||||
* Write a single configuration value to persisted storage (if it has
|
||||
* changed value).
|
||||
*
|
||||
* @param name Name/key of the configuration item.
|
||||
* @param var Value of the configuration item.
|
||||
*
|
||||
* @return 0 on success, non-zero on failure.
|
||||
*/
|
||||
int conf_save_one(const char *name, char *var);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#define SYSINIT_PANIC_ASSERT_MSG(rc, msg) assert(rc)
|
||||
|
||||
#endif /* __SYS_CONFIG_H_ */
|
||||
136
src/mesh_config_store/config/config_store.c
Normal file
136
src/mesh_config_store/config/config_store.c
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "nimconfig.h"
|
||||
#ifdef ESP_PLATFORM
|
||||
#if CONFIG_BT_NIMBLE_MESH && CONFIG_NIMBLE_CPP_PERSIST_MESH_SETTINGS
|
||||
|
||||
#include "config.h"
|
||||
#include "nvs.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
static struct conf_handler* config_handler;
|
||||
|
||||
int conf_parse_name(char *name, int *name_argc, char *name_argv[])
|
||||
{
|
||||
char *tok;
|
||||
char *tok_ptr;
|
||||
const char *sep = "/";
|
||||
int i;
|
||||
|
||||
tok = strtok_r(name, sep, &tok_ptr);
|
||||
|
||||
i = 0;
|
||||
while (tok) {
|
||||
name_argv[i++] = tok;
|
||||
tok = strtok_r(NULL, sep, &tok_ptr);
|
||||
}
|
||||
*name_argc = i;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int conf_load(void)
|
||||
{
|
||||
esp_err_t err;
|
||||
nvs_handle handle;
|
||||
|
||||
err = nvs_open(config_handler->ch_name, NVS_READONLY, &handle);
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
nvs_iterator_t it = nvs_entry_find("nvs", config_handler->ch_name, NVS_TYPE_ANY);
|
||||
|
||||
while (it != NULL) {
|
||||
nvs_entry_info_t info;
|
||||
nvs_entry_info(it, &info);
|
||||
it = nvs_entry_next(it);
|
||||
|
||||
size_t required_size = 0;
|
||||
err = nvs_get_str(handle, info.key, NULL, &required_size);
|
||||
if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) return err;
|
||||
|
||||
char* val = malloc(required_size);
|
||||
if (required_size > 0) {
|
||||
err = nvs_get_str(handle, info.key, val, &required_size);
|
||||
if (err != ESP_OK) {
|
||||
free(val);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
int name_argc;
|
||||
char *name_argv[8];
|
||||
conf_parse_name(info.key, &name_argc, name_argv);
|
||||
|
||||
config_handler->ch_set(name_argc, &name_argv[0], val);
|
||||
free(val);
|
||||
}
|
||||
|
||||
nvs_close(handle);
|
||||
config_handler->ch_commit();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
int conf_save_one(const char *name, char *var)
|
||||
{
|
||||
esp_err_t err;
|
||||
nvs_handle_t handle;
|
||||
int name_argc;
|
||||
char *name_argv[CONF_MAX_DIR_DEPTH];
|
||||
char n[CONF_MAX_NAME_LEN];
|
||||
|
||||
strcpy(n, name);
|
||||
conf_parse_name(n, &name_argc, name_argv);
|
||||
|
||||
err = nvs_open(name_argv[0], NVS_READWRITE, &handle);
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
const char* key = name_argv[1];
|
||||
if (name_argc > 2) {
|
||||
key = name;
|
||||
while (*key != '/') {
|
||||
key++;
|
||||
}
|
||||
key++;
|
||||
}
|
||||
|
||||
if (var) {
|
||||
err = nvs_set_str(handle, key, var);
|
||||
if (err != ESP_OK) return err;
|
||||
} else {
|
||||
err = nvs_erase_key(handle, key);
|
||||
if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) return err;
|
||||
}
|
||||
|
||||
err = nvs_commit(handle);
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
nvs_close(handle);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
int conf_register(struct conf_handler *cf)
|
||||
{
|
||||
config_handler = cf;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_MESH && MYNEWT_VAL_BLE_MESH_SETTINGS
|
||||
#endif // ESP_PLATFORM
|
||||
@@ -131,6 +131,7 @@
|
||||
/** @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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user