forked from h2zero/esp-nimble-cpp
Compare commits
6 Commits
2.0.1
...
remove-ard
Author | SHA1 | Date | |
---|---|---|---|
c218a27dd8 | |||
8883f44d9f | |||
9c7b690771 | |||
641f297120 | |||
7f853fa04b | |||
df4eb9f7d8 |
@ -1,42 +0,0 @@
|
||||
BasedOnStyle: Google
|
||||
Language: Cpp
|
||||
ColumnLimit: 120
|
||||
IndentWidth: 4
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
SortIncludes: Never
|
||||
PPIndentWidth : 1
|
||||
IndentPPDirectives: AfterHash
|
||||
ReflowComments: true
|
||||
SpacesBeforeTrailingComments: 1
|
||||
AlignTrailingComments: true
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveMacros:
|
||||
Enabled: true
|
||||
AcrossEmptyLines: true
|
||||
AcrossComments: true
|
||||
AlignConsecutiveAssignments:
|
||||
Enabled: true
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: true
|
||||
AlignCompound: true
|
||||
PadOperators: true
|
||||
AlignConsecutiveDeclarations:
|
||||
Enabled: true
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: true
|
||||
AlignEscapedNewlines: Left
|
||||
AccessModifierOffset: -2
|
||||
AlignArrayOfStructures: Right
|
||||
AlignOperands: Align
|
||||
AllowAllArgumentsOnNextLine: false
|
||||
AllowShortFunctionsOnASingleLine: Inline
|
||||
AllowShortBlocksOnASingleLine: Empty
|
||||
BreakBeforeBinaryOperators: None
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
DerivePointerAlignment: false
|
||||
PenaltyBreakAssignment: 4
|
||||
PenaltyExcessCharacter: 4
|
||||
PenaltyBreakBeforeFirstCallParameter: 1
|
||||
PointerAlignment: Left
|
65
.github/workflows/build.yml
vendored
65
.github/workflows/build.yml
vendored
@ -1,65 +0,0 @@
|
||||
name: Build
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
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", "release-v5.1", "v5.3.2"]
|
||||
idf_target: ["esp32", "esp32s3", "esp32c2", "esp32c3", "esp32c6", "esp32h2", "esp32p4"]
|
||||
example:
|
||||
- NimBLE_Client
|
||||
- NimBLE_Server
|
||||
- Bluetooth_5/NimBLE_extended_client
|
||||
- Bluetooth_5/NimBLE_extended_server
|
||||
exclude:
|
||||
- idf_target: "esp32"
|
||||
example: Bluetooth_5/NimBLE_extended_client
|
||||
- idf_target: "esp32"
|
||||
example: Bluetooth_5/NimBLE_extended_server
|
||||
- idf_ver: release-v4.4
|
||||
idf_target: "esp32c2"
|
||||
- idf_ver: release-v4.4
|
||||
idf_target: "esp32c6"
|
||||
- idf_ver: release-v4.4
|
||||
idf_target: "esp32h2"
|
||||
- idf_ver: release-v4.4
|
||||
idf_target: "esp32p4"
|
||||
- idf_ver: release-v5.1
|
||||
idf_target: "esp32p4"
|
||||
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
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@v4
|
||||
- name: Doxygen Action
|
||||
uses: mattnotmitt/doxygen-action@v1.9.8
|
||||
with:
|
||||
working-directory: 'docs/'
|
20
.github/workflows/release.yml
vendored
20
.github/workflows/release.yml
vendored
@ -1,20 +0,0 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
build_docs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Doxygen Action
|
||||
uses: mattnotmitt/doxygen-action@v1.9.8
|
||||
with:
|
||||
working-directory: 'docs/'
|
||||
- name: Deploy
|
||||
uses: peaceiris/actions-gh-pages@v4
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
publish_dir: ./docs/doxydocs/html
|
17
.github/workflows/sponsors.yml
vendored
17
.github/workflows/sponsors.yml
vendored
@ -1,17 +0,0 @@
|
||||
name: Generate Sponsors README
|
||||
on:
|
||||
workflow_dispatch:
|
||||
permissions:
|
||||
contents: write
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout 🛎️
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Generate Sponsors 💖
|
||||
uses: JamesIves/github-sponsors-readme-action@v1.5.4
|
||||
with:
|
||||
token: ${{ secrets.PAT }}
|
||||
file: 'README.md'
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +0,0 @@
|
||||
docs/doxydocs
|
27
.travis.yml
Normal file
27
.travis.yml
Normal file
@ -0,0 +1,27 @@
|
||||
sudo: false
|
||||
|
||||
before_install:
|
||||
- cd ${TMPDIR-/tmp}
|
||||
- wget -q http://doxygen.nl/files/doxygen-1.9.0.src.tar.gz
|
||||
- tar -xzvf doxygen-1.9.0.src.tar.gz
|
||||
- mkdir doxygen_build
|
||||
- cd doxygen_build
|
||||
- cmake ../doxygen-1.9.0/
|
||||
- make
|
||||
- export PATH="${TMPDIR-/tmp}/doxygen_build/bin:$PATH"
|
||||
- cd ${TRAVIS_BUILD_DIR}
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
||||
script:
|
||||
- doxygen ./docs/Doxyfile
|
||||
|
||||
deploy:
|
||||
provider: pages
|
||||
skip_cleanup: true
|
||||
local_dir: docs/html
|
||||
github_token: $GH_REPO_TOKEN
|
||||
on:
|
||||
branch: master
|
354
CHANGELOG.md
354
CHANGELOG.md
@ -1,349 +1,7 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [2.0.1] 2024-12-16
|
||||
|
||||
## Fixed
|
||||
- `NimBLEHIDDevice::getOutputReport` will now return the correct characteristic.
|
||||
- Compile error when central is disabled, class `NimBLEServer` has no member named `m_pClient`.
|
||||
|
||||
## Changed
|
||||
- Added missing includes for `NimBLEConnInfo` and `NimBLEUtils` to `NimBLEDevice.h`.
|
||||
|
||||
## [2.0.0] 2024-12-14
|
||||
|
||||
## **Breaking changes**
|
||||
- All connection oriented callbacks now receive a reference to `NimBLEConnInfo`, the `ble_gap_conn_desc` has also been replace with `NimBLEConnInfo` in the functions that received it.
|
||||
- All functions that take a time input parameter now expect the value to be in milliseconds instead of seconds.
|
||||
- Removed Eddystone URL as it has been shutdown by google since 2021.
|
||||
- NimBLESecurity class removed.
|
||||
- `NimBLEDevice` Ignore list functions removed.
|
||||
- `NimBLEDevice::startSecurity` now returns a `bool`, true on success, instead of an int to be consistent with the rest of the library.
|
||||
- `NimBLEDevice::getInitialized` renamed to `NimBLEDevice::isInitialized`.
|
||||
- `NimBLEDevice::setPower` no longer takes the `esp_power_level_t` and `esp_ble_power_type_t`, instead only an integer value in dbm units is accepted.
|
||||
- `NimBLEDevice::setOwnAddrType` no longer takes a `bool nrpa` parameter.
|
||||
- `NimBLEDevice::getClientListSize` replaced with `NimBLEDevice::getCreatedClientCount`.
|
||||
- `NimBLEDevice::getClientList` was removed.
|
||||
- `NimBLEServer::disconnect` now returns `bool`, true = success, instead of `int` to be consistent with the rest of the library.
|
||||
- `NimBLEServerCallbacks::onMTUChanged` renamed to `NimBLEServerCallbacks::onMTUChange` to be consistent with the client callback.
|
||||
- `NimBLEServer::getPeerIDInfo` renamed to `NimBLEServer::getPeerInfoByHandle` to better describe it's use.
|
||||
- `NimBLEServerCallbacks::onPassKeyRequest` has been replaced with `NimBLEServer::onPassKeyDisplay` which should display the pairing pin that the client is expected to send.
|
||||
- `NimBLEServerCallbacks::onAuthenticationComplete` now takes a `NimBLEConnInfo&` parameter.
|
||||
- `NimBLEClient::getServices` now returns a const reference to std::vector<NimBLERemoteService*> instead of a pointer to the internal vector.
|
||||
- `NimBLEClient::getConnId` has been renamed to `getConnHandle` to be consistent with bluetooth terminology.
|
||||
- `NimBLEClient::disconnect` now returns a `bool`, true on success, instead of an int to be consistent with the rest of the library.
|
||||
- `NimBLEClientCallbacks::onDisconnect` now takes an additional `int reason` parameter to let the application know why the disconnect occurred.
|
||||
- `NimBLEClientCallbacks::onPassKeyRequest` has been changed to `NimBLEClientCallbacks::onPassKeyEntry` which takes a `NimBLEConnInfo&` parameter and does not return a value. Instead or returning a value this callback should prompt a user to enter a pin number which is sent later via `NimBLEDevice::injectPassKey`.
|
||||
- `NimBLEClientCallbacks::onConfirmPIN` renamed to `NimBLEClientCallbacks::onConfirmPasskey` and no longer returns a value and now takes a `NimBLEConnInfo&` parameter. This should be used to prompt a user to confirm the pin on the display (YES/NO) after which the response should be sent with `NimBLEDevice::injectConfirmPasskey`.
|
||||
- `NimBLEAdvertising::setMinPreferred` and `NimBLEAdvertising::setMaxPreferred` have been removed, use `NimBLEAdvertising::setPreferredParams` instead.
|
||||
- Advertising the name and TX power of the device will no longer happen by default and should be set manually by the application.
|
||||
- `NimBLEAdvertising::setAdvertisementType` has been renamed to `NimBLEAdvertising::setConnectableMode` to better reflect it's function.
|
||||
- `NimBLEAdvertising::setScanResponse` has been renamed to `NimBLEAdvertising::enableScanResponse` to better reflect it's function.
|
||||
- `NimBLEAdvertising`; Scan response is no longer enabled by default.
|
||||
- `NimBLEAdvertising::start` No longer takes a callback pointer parameter, instead the new method `NimBLEAdvertising::setAdvertisingCompleteCallback` should be used.
|
||||
- `NimBLEAdvertisementData::addData` now takes either a `std::vector<uint8_t>` or `uint8_t* + length` instead of `std::string` or `char + length`.
|
||||
- `NimBLEAdvertisementData::getPayload` now returns `std::vector<uint8_t>` instead of `std::string`.
|
||||
- The callback parameter for `NimBLEScan::start` has been removed and the blocking overload of `NimBLEScan::start` has been replaced by an overload of `NimBLEScan::getResults` with the same parameters.
|
||||
- `NimBLEAdvertisedDeviceCallbacks` Has been replaced by `NimBLEScanCallbacks` which contains the following methods: `onResult`, `onScanEnd`, and `onDiscovered
|
||||
- - `NimBLEScanCallbacks::onResult`, functions the same as the old `NimBLEAdvertisedDeviceCallbacks::onResult` but now takes aa `const NimBLEAdvertisedDevice*` instead of non-const.
|
||||
- - `NimBLEScanCallbacks::onScanEnd`, replaces the scanEnded callback passed to `NimBLEScan::start` and now takes a `const NimBLEScanResults&` and `int reason` parameter.
|
||||
- - `NimBLEScanCallbacks::onDiscovered`, This is called immediately when a device is first scanned, before any scan response data is available and takes a `const NimBLEAdvertisedDevice*` parameter.
|
||||
- `NimBLEScan::stop` will no longer call the `onScanEnd` callback as the caller should know its been stopped when this is called.
|
||||
- `NimBLEScan::clearDuplicateCache` has been removed as it was problematic and only for the esp32. Stop and start the scanner for the same effect.
|
||||
- `NimBLEScanResults::getDevice` methods now return `const NimBLEAdvertisedDevice*`.
|
||||
- `NimBLEScanResults` iterators are now `const_iterator`.
|
||||
- `NimBLEAdvertisedDevice::hasRSSI` removed as redundant, RSSI is always available.
|
||||
- `NimBLEAdvertisedDevice::getPayload` now returns `const std::vector<uint8_t>` instead of a pointer to internal memory.
|
||||
- `NimBLEAdvertisedDevice` Timestamp removed, if needed then the app should track the time from the callback.
|
||||
- `NimBLECharacteristic::notify` no longer takes a `bool is_notification` parameter, instead `indicate()` should be called to send indications.
|
||||
- `NimBLECharacteristicCallbacks::onNotify` removed as unnecessary, the library does not call notify without app input.
|
||||
- `NimBLECharacteristicCallbacks::onStatus` No longer takes a `status` parameter, refer to the return code for success/failure.
|
||||
- `NimBLERemoteCharacteristic::getRemoteService` now returns a `const NimBLERemoteService*` instead of non-const.
|
||||
- `NimBLERemoteCharacteristic::readUInt32` Has been removed.
|
||||
- `NimBLERemoteCharacteristic::readUInt16` Has been removed.
|
||||
- `NimBLERemoteCharacteristic::readUInt8` Has been removed.
|
||||
- `NimBLERemoteCharacteristic::readFloat` Has been removed.
|
||||
- `NimBLERemoteCharacteristic::registerForNotify` Has been removed.
|
||||
- `NimBLERemoteService::getCharacteristics` now returns a `const std::vector<NimBLERemoteCharacteristic*>&` instead of non-const `std::vector<NimBLERemoteCharacteristic*>*`.
|
||||
- `NimBLERemoteService::getValue` now returns `NimBLEAttValue` instead of `std::string`.
|
||||
- `NimBLEService::getCharacteristics` now returns a `const std::vector<NimBLECharacteristic*>&` instead of std::vector<NimBLECharacteristic *>.
|
||||
- `NimBLEUUID::getNative` method replaced with `NimBLEUUID::getBase` which returns a read-only pointer to the underlying `ble_uuid_t` struct.
|
||||
- `NimBLEUUID`; `msbFirst` parameter has been removed from constructor, caller should reverse the data first or call the new `reverseByteOrder` method after.
|
||||
- `NimBLEAddress` constructor; default value for the `type` parameter removed, caller should know the address type and specify it.
|
||||
- `NimBLEAddress::getNative` replaced with `NimBLEAddress::getBase` and now returns a pointer to `const ble_addr_t` instead of a pointer to the address value.
|
||||
- `NimBLEAddress::equals` method and `NimBLEAddress::== operator` will now also test if the address types are the same.
|
||||
- `NimBLEUtils::dumpGapEvent` function removed.
|
||||
- `NimBLEUtils::buildHexData` replaced with `NimBLEUtils::dataToHexString`, which returns a `std::string` containing the hex string.
|
||||
- `NimBLEEddystoneTLM::setTemp` now takes an `int16_t` parameter instead of float to be friendly to devices without floating point support.
|
||||
- `NimBLEEddystoneTLM::getTemp` now returns `int16_t` to work with devices that don't have floating point support.
|
||||
- `NimBLEEddystoneTLM::setData` now takes a reference to * `NimBLEEddystoneTLM::BeaconData` instead of `std::string`.
|
||||
- `NimBLEEddystoneTLM::getData` now returns a reference to * `NimBLEEddystoneTLM::BeaconData` instead of `std::string`.
|
||||
- `NimBLEBeacon::setData` now takes `const NimBLEBeacon::BeaconData&` instead of `std::string`.
|
||||
- `NimBLEBeacon::getData` now returns `const NimBLEBeacon::BeaconData&` instead of `std::string`.
|
||||
- `NimBLEHIDDevice::reportMap` renamed to `NimBLEHIDDevice::getReportMap`.
|
||||
- `NimBLEHIDDevice::hidControl` renamed to `NimBLEHIDDevice::getHidControl`.
|
||||
- `NimBLEHIDDevice::inputReport`renamed to `NimBLEHIDDevice::getInputReport`.
|
||||
- `NimBLEHIDDevice::outputReport`renamed to `NimBLEHIDDevice::getOutputReport`.
|
||||
- `NimBLEHIDDevice::featureReport`renamed to `NimBLEHIDDevice::getFeatureReport`.
|
||||
- `NimBLEHIDDevice::protocolMode`renamed to `NimBLEHIDDevice::getProtocolMode`.
|
||||
- `NimBLEHIDDevice::bootOutput`renamed to `NimBLEHIDDevice::getBootOutput`.
|
||||
- `NimBLEHIDDevice::pnp`renamed to `NimBLEHIDDevice::setPnp`.
|
||||
- `NimBLEHIDDevice::hidInfo`renamed to `NimBLEHIDDevice::setHidInfo`.
|
||||
- `NimBLEHIDDevice::deviceInfo`renamed to `NimBLEHIDDevice::getDeviceInfoService`.
|
||||
- `NimBLEHIDDevice::hidService`renamed to `NimBLEHIDDevice::getHidService`.
|
||||
- `NimBLEHIDDevice::batteryService`renamed to `NimBLEHIDDevice::getBatteryService`.
|
||||
|
||||
## Fixed
|
||||
- `NimBLEDevice::getPower` and `NimBLEDevice::getPowerLevel` bug worked around for the esp32s3 and esp32c3.
|
||||
- `NimBLEDevice::setPower` and `NimBLEDevice::getPower` now support the full power range for all esp devices.
|
||||
- `NimBLEDevice::setOwnAddrType` will now correctly apply the provided address type for all devices.
|
||||
- `NimBLEDevice::getPower` (esp32) return value is now calculated to support devices with different min/max ranges.
|
||||
- Crash if `NimBLEDevice::deinit` is called when the stack has not been initialized.
|
||||
- `NimBLEServer` service changed notifications will now wait until the changes have taken effect and the server re-started before indicating the change to peers, reducing difficultly for some clients to update their data.
|
||||
- `NimBLEService::getHandle` will now fetch the handle from the stack if not valid to avoid returning an invalid value.
|
||||
- `std::vector` input to set/write values template.
|
||||
- `NimBLEHIDDevice::pnp` will now set the data correctly.
|
||||
- Check for Arduino component
|
||||
- Fixed building with esp-idf version 5.x.
|
||||
- Fixed pairing failing when the process was started by the peer first.
|
||||
- Fixed building with esp-idf and Arduino component.
|
||||
- Workaround for esp32s3 and esp32c3 not returning the correct txPower with some IDF versions.
|
||||
|
||||
### Changed
|
||||
- `NimBLEClient::secureConnection` now takes an additional parameter `bool async`, if true, will send the secure command and return immediately with a true value for successfully sending the command, else false. This allows for asynchronously securing a connection.
|
||||
- Deleting the client instance from the `onDisconnect` callback is now supported.
|
||||
- `NimBLEClient::connect` will no longer cancel already in progress connections.
|
||||
- `NimBLEClient::setDataLen` now returns bool, true if successful.
|
||||
- `NimBLEClient::updateConnParams` now returns bool, true if successful.
|
||||
- `NimBLEClient::setPeerAddress` now returns a bool, true on success.
|
||||
- `NimBLEDevice::startSecurity` now takes and additional parameter `int* rcPtr` which will provide the return code from the stack if provided.
|
||||
- `NimBLEDevice::deleteClient` no longer blocks tasks.
|
||||
- `NimBLEDevice::getAddress` will now return the address currently in use.
|
||||
- `NimBLEDevice::init` now returns a bool with `true` indicating success.
|
||||
- `NimBLEDevice::deinit` now returns a bool with `true` indicating success.
|
||||
- `NimBLEDevice::setDeviceName` now returns a bool with `true` indicating success.
|
||||
- `NimBLEDevice::setCustomGapHandler` now returns a bool with `true` indicating success.
|
||||
- `NimBLEDevice::setOwnAddrType` now returns a bool with `true` indicating success and works with non-esp32 devices.
|
||||
- `NimBLEDevice::setPower` now returns a bool value, true = success.
|
||||
- `NimBLEDevice::setMTU` now returns a bool value, true = success.
|
||||
- `NimBLEDevice::deleteAllBonds` now returns true on success, otherwise false.
|
||||
- `NimBLEEddystoneTLM` internal data struct type `BeaconData` is now public and usable by the application.
|
||||
- `NimBLEBeacon` internal data struct type `BeaconData` is now public and can be used by the application.
|
||||
- Removed tracking of client characteristic subscription status from `NimBLEServer` and `NimBLECharacteristic` and instead uses
|
||||
the functions and tracking in the host stack.
|
||||
- `NimBLECharacteristic::indicate` now takes the same parameters as `notify`.
|
||||
- `NimBLECharacteristic::notify` and `NimBLECharacteristic::indicate` now return a `bool`, true = success.
|
||||
- Added optional `connHandle` parameter to `NimBLECharacteristic::notify` to allow for sending notifications to specific clients.
|
||||
- `NimBLEServer` Now uses a std::array to store client connection handles instead of std::vector to reduce memory allocation.
|
||||
- `NimBLEExtAdvertisement` : All functions that set data now return `bool`, true = success.
|
||||
- `NimBLEAdvertising` Advertising data is now stored in instances of `NimBLEAdvertisingData` and old vectors removed.
|
||||
- `NimBLEAdvertising::setAdvertisementData` and `NimBLEAdvertising::setScanResponseData` now return `bool`, true = success.
|
||||
- Added optional `NimBLEAddress` parameter to `NimBLEAdvertising::start` to allow for directed advertising to a peer.
|
||||
- All `NimBLEAdvertising` functions that change data values now return `bool`, true = success.
|
||||
- All `NimBLEAdvertisementData` functions that change data values now return `bool`, true = success.
|
||||
- `NimBLEAdvertising` advertising complete callback is now defined as std::function to allow for using std::bind for callback functions.
|
||||
- `NimBLEAdvertisementData::setName` now takes an optional `bool` parameter to indicate if the name is complete or incomplete, default = complete.
|
||||
- `NimBLEAdvertisementData` moved to it's own .h and .cpp files.
|
||||
- `NimBLEScan::start` takes a new `bool restart` parameter, default `true`, that will restart an already in progress scan and clear the duplicate filter so all devices will be discovered again.
|
||||
- Scan response data that is received without advertisement first will now create the device and send a callback.
|
||||
- `NimBLEScan::start` will no longer clear cache or results if scanning is already in progress.
|
||||
- `NimBLEScan::start` will now allow the start command to be sent with updated parameters if already scanning.
|
||||
- `NimBLEScan::clearResults` will now reset the vector capacity to 0.
|
||||
- Host reset will now no longer restart scanning and instead will call `NimBLEScanCallbacks::onScanEnd`.
|
||||
- Added optional `index` parameter to `NimBLEAdvertisedDevice::getPayloadByType`
|
||||
- `NimBLEAdvertisedDevice::getManufacturerData` now takes an optional index parameter for use in the case of multiple manufacturer data fields.
|
||||
- `NimBLEUtils`: Add missing GAP event strings.
|
||||
- `NimBLEUtils`: Add missing return code strings.
|
||||
- `NimBLEUtils`: Event/error code strings optimized.
|
||||
- `NimBLEAttValue` cleanup and optimization.
|
||||
- cleaned up code, removed assert/abort calls, replaced with a configurable option to enable debug asserts.
|
||||
|
||||
### Added
|
||||
- (esp32 specific) `NimBLEDevice::setPowerLevel` and `NimBLEDevice::getPowerLevel` which take and return the related `esp_power_level* ` types.
|
||||
- `NimBLEDevice::setDefaultPhy` which will set the default preferred PHY for all connections.
|
||||
- `NimBLEDevice::getConnectedClients`, which returns a vector of pointers to the currently connected client instances.
|
||||
- `NimBLEDevice::setOwnAddr` function added, which takes a `uint8_t*` or `NimBLEAddress&` and will set the mac address of the device, returns `bool` true= success.
|
||||
- `NimBLEDevice::injectPassKey` Used to send the pairing passkey instead of a return value from the client callback.
|
||||
- `NimBLEDevice::injectConfirmPasskey` Used to send the numeric comparison pairing passkey confirmation instead of a return value from the client callback.
|
||||
- `NimBLEDevice::setDeviceName` to change the device name after initialization.
|
||||
- `NimBLECharacteristic::create2904` which will specifically create a Characteristic Presentation Format (0x2904) descriptor.
|
||||
- `NimBLEAdvertising::refreshAdvertisingData` refreshes the advertisement data while still actively advertising.
|
||||
- `NimBLEClient::updatePhy` to request a PHY change with a peer.
|
||||
- `NimBLEClient::getPhy` to read the current connection PHY setting.
|
||||
- `Config` struct to `NimBLEClient` to efficiently set single bit config settings.
|
||||
- `NimBLEClient::setSelfDelete` that takes the bool parameters `deleteOnDisconnect` and `deleteOnConnectFail`, which will configure the client to delete itself when disconnected or the connection attempt fails.
|
||||
- `NimBLEClient::setConfig` and `NimBLEClient::getConfig` which takes or returns a `NimBLEClient::Config` object respectively.
|
||||
- `NimBLEClient::cancelConnect()` to cancel an in-progress connection, returns `bool`, true = success.
|
||||
- Non-blocking `NimBLEClient::connect` option added via 2 new `bool` parameters added to the function:
|
||||
- * `asyncConnect`; if true, will send the connect command and return immediately.
|
||||
- * `exchangeMTU`; if true will send the exchange MTU command upon connection.
|
||||
- `NimBLEClientCallbacks::onConnectFail` callback that is called when the connection attempt fail while connecting asynchronously.
|
||||
- `NimBLEClientCallbacks::onMTUChange` callback which will be called when the MTU exchange completes and takes a `NimBLEClient*` and `uint16_t MTU` parameter.
|
||||
- `NimBLEClientCallbacks::onPhyUpdate` and -`NimBLEServerCallbacks::onPhyUpdate` Which are called when the PHY update is complete.
|
||||
- Extended scan example.
|
||||
- `NimBLEServer::updatePhy` to request a PHY change with a peer.
|
||||
- `NimBLEServer::getPhy` to read the PHY of a peer connection.
|
||||
- `NimBLEServer::getClient` which will create a client instance from the provided peer connHandle or connInfo to facilitate reading/write from the connected client.
|
||||
- `NimBLEServerCallbacks::onConnParamsUpdate` callback.
|
||||
- `NimBLEScan::erase` overload that takes a `const NimBLEAdvertisedDevice*` parameter.
|
||||
- `NimBLEScan::setScanPhy` to enable/disable the PHY's to scan on (extended advertising only).
|
||||
- `NimBLEScan::setScanPeriod` which will allow for setting a scan restart timer in the controller (extended advertising only).
|
||||
- `NimBLEAdvertisedDevice::isScannable()` that returns true if the device is scannable.
|
||||
- `NimBLEAdvertisedDevice::begin` and `NimBLEAdvertisedDevice::end` read-only iterators for convenience and use in range loops.
|
||||
- `NimBLEAdvertisedDevice::getAdvFlags` returns the advertisement flags of the advertiser.
|
||||
- `NimBLEAdvertisedDevice::getPayloadByType` Generic use function that returns the data from the advertisement with the specified type.
|
||||
- `NimBLEAdvertisedDevice::haveType` Generic use function that returns true if the advertisement data contains a field with the specified type.
|
||||
- Support for esp32c6, esp32c2, esp32h2, and esp32p4.
|
||||
- `NimBLEExtAdvertisement::removeData`, which will remove the data of the specified type from the advertisement.
|
||||
- `NimBLEExtAdvertisement::addServiceUUID`, which will append to the service uuids advertised.
|
||||
- `NimBLEExtAdvertisement::removeServiceUUID`, which will remove the service from the uuids advertised.
|
||||
- `NimBLEExtAdvertisement::removeServices`, which will remove all service uuids advertised.
|
||||
- New overloads for `NimBLEExtAdvertisement::setServiceData` with the parameters `const NimBLEUUID& uuid, const uint8_t* data, size_t length` and `const NimBLEUUID& uuid, const std::vector<uint8_t>& data`.
|
||||
- `NimBLEExtAdvertisement::getDataLocation`, which returns the location in the advertisement data of the type requested in parameter `uint8_t type`.
|
||||
- `NimBLEExtAdvertisement::toString` which returns a hex string representation of the advertisement data.
|
||||
- `NimBLEAdvertising::getAdvertisementData`, which returns a reference to the currently set advertisement data.
|
||||
- `NimBLEAdvertising::getScanData`, which returns a reference to the currently set scan response data.
|
||||
- New overloads for `NimBLEAdvertising::removeServiceUUID` and `NimBLEAdvertisementData::removeServiceUUID` to accept a `const char*`
|
||||
- `NimBLEAdvertising::clearData`, which will clear the advertisement and scan response data.
|
||||
- `NimBLEAdvertising::setManufacturerData` Overload that takes a `const uint8_t*` and , size_t` parameter.
|
||||
- `NimBLEAdvertising::setServiceData` Overload that takes `const NimBLEUUID& uuid`, ` const uint8_t* data`, ` size_t length` as parameters.
|
||||
- `NimBLEAdvertising::setServiceData` Overload that takes `const NimBLEUUID& uuid`, `const std::vector<uint8_t>&` as parameters.
|
||||
- `NimBLEAdvertising::setDiscoverableMode` to allow applications to control the discoverability of the advertiser.
|
||||
- `NimBLEAdvertising::setAdvertisingCompleteCallback` sets the callback to call when advertising ends.
|
||||
- `NimBLEAdvertising::setPreferredParams` that takes the min and max preferred connection parameters as an alternative for `setMinPreferred` and `setMaxPreferred`.
|
||||
- `NimBLEAdvertising::setAdvertisingInterval` Sets the advertisement interval for min and max to the same value instead of calling `setMinInterval` and `setMaxInterval` separately if there is not value difference.
|
||||
- `NimBLEAdvertisementData::removeData`, which takes a parameter `uint8_t type`, the data type to remove.
|
||||
- `NimBLEAdvertisementData::toString`, which will print the data in hex.
|
||||
- `NimBLEUtils::taskWait` which causes the calling task to wait for an event.
|
||||
- `NimBLEUtils::taskRelease` releases the task from and event.
|
||||
- `NimBLEUtils::generateAddr` function added with will generate a random address and takes a `bool` parameter, true = create non-resolvable private address, otherwise a random static address is created, returns `NimBLEAddress`.
|
||||
- `NimBLEUUID::getValue` which returns a read-only `uint8_t` pointer to the UUID value.
|
||||
- `NimBLEUUID::reverseByteOrder`, this will reverse the bytes of the UUID, which can be useful for advertising/logging.
|
||||
- `NimBLEUUID` constructor overload that takes a reference to `ble_uuid_any_t`.
|
||||
- `NimBLEAddress::isNrpa` method to test if an address is random non-resolvable.
|
||||
- `NimBLEAddress::isStatic` method to test if an address is random static.
|
||||
- `NimBLEAddress::isPublic` method to test if an address is a public address.
|
||||
- `NimBLEAddress::isNull` methods to test if an address is NULL.
|
||||
- `NimBLEAddress::getValue` method which returns a read-only pointer to the address value.
|
||||
- `NimBLEAddress::reverseByteOrder` method which will reverse the byte order of the address value.
|
||||
- `NimBLEHIDDevice::batteryLevel` returns the HID device battery level characteristic.
|
||||
- `NimBLEBeacon::setData` overload that takes `uint8_t* data` and `uint8_t length`.
|
||||
- `NimBLEHIDDevice::getPnp` function added to access the pnp characteristic.
|
||||
- `NimBLEHIDDevice::getHidInfo` function added to access the hid info characteristic.
|
||||
|
||||
## [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
|
||||
- If attribute retrieval fails with a "not found" try again with the 16 bit version if a 128 bit base uuid is used.
|
||||
|
||||
### Fixed
|
||||
- Memory leak when deleting client instance.
|
||||
- IDf version check for data length extension.
|
||||
- Memory leak when server services changed.
|
||||
- Compiler warnings for non-esp32 devices.
|
||||
|
||||
## [1.3.2] - 2022-01-15
|
||||
|
||||
### Fixed
|
||||
- Initialize advertising complete callback in NimBLEAdvertising constructor.
|
||||
- Clear client disconnect timer in constructor before initializing.
|
||||
- Fix missing data when reading large values.
|
||||
- Fix missing data in notifications when using a large MTU size and more than 270 bytes of data are sent.
|
||||
- Workaround fix added for cases when the task notification value is not cleared, causing various functions that should block not to block.
|
||||
|
||||
### Added
|
||||
- `NimBLEClient::getLastError` : Gets the error code of the last function call that produces a return code from the stack.
|
||||
- `NimBLECharacteristic::notify` : Overload method to send notifications/indications with custom values.
|
||||
- Added conditional checks for ESP32 specific functions/values to support use of the library on non-esp32 devices.
|
||||
- Added an alias to use the callback name from the original library `onMtuChanged`.
|
||||
- `NimBLEClient::setDataLen` and `NimBLEServer::setDataLen`: Data length extension support (IDF version >= 4.3.2 only)
|
||||
- Config option to set logging level for esp-nimble-cpp
|
||||
|
||||
### Changed
|
||||
- Critical section calls now use the NimBLE API instead of FreeRTOS directly. This removes the need for a `portMUX_TYPE` variable in the class definitions.
|
||||
- Removed unnecessary variables in `NimBLEService` and changed the constructor no no longer accept `numHandles` and `inst_id` parameters.
|
||||
|
||||
## [1.3.1] - 2021-08-04
|
||||
|
||||
### Fixed
|
||||
- Corrected a compiler/linker error when an application or a library uses bluetooth classic due to the redefinition of `btInUse`.
|
||||
|
||||
## [1.3.0] - 2021-08-02
|
||||
|
||||
### Added
|
||||
- `NimBLECharacteristic::removeDescriptor`: Dynamically remove a descriptor from a characteristic. Takes effect after all connections are closed and sends a service changed indication.
|
||||
- `NimBLEService::removeCharacteristic`: Dynamically remove a characteristic from a service. Takes effect after all connections are closed and sends a service changed indication
|
||||
- `NimBLEServerCallbacks::onMTUChange`: This is callback is called when the MTU is updated after connection with a client.
|
||||
- ESP32C3 support
|
||||
|
||||
- Whitelist API:
|
||||
- `NimBLEDevice::whiteListAdd`: Add a device to the whitelist.
|
||||
- `NimBLEDevice::whiteListRemove`: Remove a device from the whitelist.
|
||||
- `NimBLEDevice::onWhiteList`: Check if the device is on the whitelist.
|
||||
- `NimBLEDevice::getWhiteListCount`: Gets the size of the whitelist
|
||||
- `NimBLEDevice::getWhiteListAddress`: Get the address of a device on the whitelist by index value.
|
||||
|
||||
- Bond management API:
|
||||
- `NimBLEDevice::getNumBonds`: Gets the number of bonds stored.
|
||||
- `NimBLEDevice::isBonded`: Checks if the device is bonded.
|
||||
- `NimBLEDevice::deleteAllBonds`: Deletes all bonds.
|
||||
- `NimBLEDevice::getBondedAddress`: Gets the address of a bonded device by the index value.
|
||||
|
||||
- `NimBLECharacteristic::getCallbacks` to retrieve the current callback handler.
|
||||
- Connection Information class: `NimBLEConnInfo`.
|
||||
- `NimBLEScan::clearDuplicateCache`: This can be used to reset the cache of advertised devices so they will be immediately discovered again.
|
||||
|
||||
### Changed
|
||||
- FreeRTOS files have been removed as they are not used by the library.
|
||||
- Services, characteristics and descriptors can now be created statically and added after.
|
||||
- Excess logging and some asserts removed.
|
||||
- Use ESP_LOGx macros to enable using local log level filtering.
|
||||
|
||||
### Fixed
|
||||
- `NimBLECharacteristicCallbacks::onSubscribe` Is now called after the connection is added to the vector.
|
||||
- Corrected bonding failure when reinitializing the BLE stack.
|
||||
- Writing to a characteristic with a std::string value now correctly writes values with null characters.
|
||||
- Retrieving remote descriptors now uses the characteristic end handle correctly.
|
||||
- Missing data in long writes to remote descriptors.
|
||||
- Hanging on task notification when sending an indication from the characteristic callback.
|
||||
- BLE controller memory could be released when using Arduino as a component.
|
||||
- Compile errors with NimBLE release 1.3.0.
|
||||
|
||||
## [1.2.0] - 2021-02-08
|
||||
|
||||
### Added
|
||||
@ -397,7 +55,7 @@ Overloads to get a vector containing pointers to all the characteristics in a se
|
||||
|
||||
- `NimBLEAdvertising` Transmission power is no longer advertised by default and can be added to the advertisement by calling `NimBLEAdvertising::addTxPower`
|
||||
|
||||
- `NimBLEAdvertising` Custom scan response data can now be used without custom advertisement.
|
||||
- `NimBLEAdvertising` Custom scan response data can now be used without custom advertisment.
|
||||
|
||||
- `NimBLEScan` Now uses the controller duplicate filter.
|
||||
|
||||
@ -439,7 +97,7 @@ to obtain information about the disconnected client.
|
||||
- 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 existence 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.
|
||||
|
||||
@ -450,7 +108,7 @@ this allows the starting of a new scan from the callback function.
|
||||
- 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 characteristic the end handle of the service was used as a proxy for the characteristic end
|
||||
- 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
|
||||
@ -467,7 +125,7 @@ and would be unable to reconnect. A timer has been added to reset the host/contr
|
||||
- 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 Arduino core and IDF v3.3.
|
||||
- `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.
|
||||
|
||||
@ -483,7 +141,7 @@ advertised them as 16/32bit but resolved them to 128bits. Both are now checked.
|
||||
### Changed
|
||||
|
||||
- `NimBLEAdvertising::start` Now takes 2 optional parameters, the first is the duration to advertise for (in seconds), the second is a
|
||||
callback that is invoked when advertising ends and takes a pointer to a `NimBLEAdvertising` object (similar to the `NimBLEScan::start` API).
|
||||
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.
|
||||
|
@ -2,64 +2,51 @@
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
if(__COMPONENT_TARGETS MATCHES "___idf_esp-nimble-component")
|
||||
idf_build_get_property(__hack_component_targets __COMPONENT_TARGETS)
|
||||
|
||||
if("esp-nimble-component" IN_LIST BUILD_COMPONENTS OR "__esp-nimble-component" IN_LIST __hack_component_targets)
|
||||
list(APPEND ESP_NIMBLE_PRIV_REQUIRES
|
||||
esp-nimble-component
|
||||
)
|
||||
elseif(__COMPONENT_TARGETS MATCHES "__idf_nimble")
|
||||
elseif("nimble" IN_LIST BUILD_COMPONENTS OR "__nimble" IN_LIST __hack_component_targets)
|
||||
list(APPEND ESP_NIMBLE_PRIV_REQUIRES
|
||||
nimble
|
||||
)
|
||||
endif()
|
||||
|
||||
# Arduino install using IDF component manager
|
||||
if(__COMPONENT_TARGETS MATCHES "___idf_espressif__arduino-esp32")
|
||||
list(APPEND ESP_NIMBLE_PRIV_REQUIRES
|
||||
arduino-esp32
|
||||
)
|
||||
# Manual installation of Arduino framework
|
||||
elseif(__COMPONENT_TARGETS MATCHES "__idf_arduino")
|
||||
list(APPEND ESP_NIMBLE_PRIV_REQUIRES
|
||||
arduino
|
||||
)
|
||||
# PlatformIO
|
||||
elseif(__COMPONENT_TARGETS MATCHES "___idf_framework-arduinoespressif32")
|
||||
list(APPEND ESP_NIMBLE_PRIV_REQUIRES
|
||||
framework-arduinoespressif32
|
||||
)
|
||||
endif()
|
||||
# Dont use arduino bullshit
|
||||
#if("arduino" IN_LIST BUILD_COMPONENTS OR __hack_component_targets MATCHES "__idf_arduino")
|
||||
# list(APPEND ESP_NIMBLE_PRIV_REQUIRES
|
||||
# arduino
|
||||
# )
|
||||
#endif()
|
||||
|
||||
idf_component_register(
|
||||
REQUIRED_IDF_TARGETS
|
||||
"esp32"
|
||||
"esp32s3"
|
||||
"esp32c2"
|
||||
"esp32c3"
|
||||
"esp32c6"
|
||||
"esp32h2"
|
||||
"esp32p4"
|
||||
INCLUDE_DIRS
|
||||
"src"
|
||||
SRCS
|
||||
"src/FreeRTOS.cpp"
|
||||
"src/NimBLE2904.cpp"
|
||||
"src/NimBLEAddress.cpp"
|
||||
"src/NimBLEAdvertisedDevice.cpp"
|
||||
"src/NimBLEAdvertisementData.cpp"
|
||||
"src/NimBLEAdvertising.cpp"
|
||||
"src/NimBLEAttValue.cpp"
|
||||
"src/NimBLEBeacon.cpp"
|
||||
"src/NimBLECharacteristic.cpp"
|
||||
"src/NimBLEClient.cpp"
|
||||
"src/NimBLEDescriptor.cpp"
|
||||
"src/NimBLEDevice.cpp"
|
||||
"src/NimBLEEddystoneTLM.cpp"
|
||||
"src/NimBLEExtAdvertising.cpp"
|
||||
"src/NimBLEEddystoneURL.cpp"
|
||||
"src/NimBLEHIDDevice.cpp"
|
||||
"src/NimBLERemoteCharacteristic.cpp"
|
||||
"src/NimBLERemoteDescriptor.cpp"
|
||||
"src/NimBLERemoteService.cpp"
|
||||
"src/NimBLERemoteValueAttribute.cpp"
|
||||
"src/NimBLEScan.cpp"
|
||||
"src/NimBLESecurity.cpp"
|
||||
"src/NimBLEServer.cpp"
|
||||
"src/NimBLEService.cpp"
|
||||
"src/NimBLEUtils.cpp"
|
||||
@ -67,8 +54,12 @@ idf_component_register(
|
||||
REQUIRES
|
||||
bt
|
||||
nvs_flash
|
||||
driver
|
||||
esp_ringbuf
|
||||
PRIV_REQUIRES
|
||||
${ESP_NIMBLE_PRIV_REQUIRES}
|
||||
)
|
||||
|
||||
target_compile_options(${COMPONENT_TARGET}
|
||||
PUBLIC
|
||||
-DDONT_USE_ARDUINO_BULLSHIT
|
||||
)
|
||||
|
57
CMakeLists.txt_idf3
Normal file
57
CMakeLists.txt_idf3
Normal file
@ -0,0 +1,57 @@
|
||||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
set(SUPPORTED_TARGETS esp32)
|
||||
|
||||
set(COMPONENT_SRCS
|
||||
"src/FreeRTOS.cpp"
|
||||
"src/NimBLE2904.cpp"
|
||||
"src/NimBLEAddress.cpp"
|
||||
"src/NimBLEAdvertisedDevice.cpp"
|
||||
"src/NimBLEAdvertising.cpp"
|
||||
"src/NimBLEBeacon.cpp"
|
||||
"src/NimBLECharacteristic.cpp"
|
||||
"src/NimBLEClient.cpp"
|
||||
"src/NimBLEDescriptor.cpp"
|
||||
"src/NimBLEDevice.cpp"
|
||||
"src/NimBLEEddystoneTLM.cpp"
|
||||
"src/NimBLEEddystoneURL.cpp"
|
||||
"src/NimBLEHIDDevice.cpp"
|
||||
"src/NimBLERemoteCharacteristic.cpp"
|
||||
"src/NimBLERemoteDescriptor.cpp"
|
||||
"src/NimBLERemoteService.cpp"
|
||||
"src/NimBLEScan.cpp"
|
||||
"src/NimBLESecurity.cpp"
|
||||
"src/NimBLEServer.cpp"
|
||||
"src/NimBLEService.cpp"
|
||||
"src/NimBLEUtils.cpp"
|
||||
"src/NimBLEUUID.cpp"
|
||||
)
|
||||
|
||||
set(COMPONENT_ADD_INCLUDEDIRS
|
||||
src
|
||||
)
|
||||
|
||||
set(COMPONENT_PRIV_REQUIRES
|
||||
nvs_flash
|
||||
bt
|
||||
)
|
||||
|
||||
if(COMPONENTS MATCHES "esp-nimble-component")
|
||||
list(APPEND COMPONENT_PRIV_REQUIRES
|
||||
esp-nimble-component
|
||||
)
|
||||
elseif(COMPONENTS MATCHES "nimble")
|
||||
list(APPEND COMPONENT_PRIV_REQUIRES
|
||||
nimble
|
||||
)
|
||||
endif()
|
||||
|
||||
if(COMPONENTS MATCHES "arduino")
|
||||
list(APPEND COMPONENT_PRIV_REQUIRES
|
||||
arduino
|
||||
)
|
||||
endif()
|
||||
|
||||
register_component()
|
108
Kconfig
108
Kconfig
@ -1,31 +1,5 @@
|
||||
menu "ESP-NimBLE-CPP configuration"
|
||||
|
||||
choice NIMBLE_CPP_LOG_LEVEL
|
||||
prompt "NimBLE CPP log verbosity"
|
||||
default NIMBLE_CPP_LOG_LEVEL_NONE
|
||||
help
|
||||
Select NimBLE CPP log verbosity level.
|
||||
|
||||
config NIMBLE_CPP_LOG_LEVEL_NONE
|
||||
bool "No logs"
|
||||
config NIMBLE_CPP_LOG_LEVEL_ERROR
|
||||
bool "Error logs"
|
||||
config NIMBLE_CPP_LOG_LEVEL_WARNING
|
||||
bool "Warning logs"
|
||||
config NIMBLE_CPP_LOG_LEVEL_INFO
|
||||
bool "Info logs"
|
||||
config NIMBLE_CPP_LOG_LEVEL_DEBUG
|
||||
bool "Debug logs"
|
||||
endchoice #NIMBLE_CPP_LOG_LEVEL
|
||||
|
||||
config NIMBLE_CPP_LOG_LEVEL
|
||||
int
|
||||
default 0 if NIMBLE_CPP_LOG_LEVEL_NONE
|
||||
default 1 if NIMBLE_CPP_LOG_LEVEL_ERROR
|
||||
default 2 if NIMBLE_CPP_LOG_LEVEL_WARNING
|
||||
default 3 if NIMBLE_CPP_LOG_LEVEL_INFO
|
||||
default 4 if NIMBLE_CPP_LOG_LEVEL_DEBUG
|
||||
|
||||
config NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT
|
||||
bool "Show NimBLE return codes as text in debug log."
|
||||
default "n"
|
||||
@ -42,7 +16,7 @@ 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
|
||||
@ -50,84 +24,4 @@ config NIMBLE_CPP_ENABLE_ADVERTISEMENT_TYPE_TEXT
|
||||
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
|
||||
bool "Enable timestamps to be stored with attribute values."
|
||||
default "n"
|
||||
help
|
||||
Enabling this option will store the timestamp when an attribute value is updated.
|
||||
This allows for checking the last update time using getTimeStamp()
|
||||
or getValue(time_t*). If disabled, the timestamp returned from these functions will be 0.
|
||||
Disabling timestamps will reduce the memory used for each value.
|
||||
|
||||
config NIMBLE_CPP_ATT_VALUE_INIT_LENGTH
|
||||
int "Initial attribute value size (bytes) for empty values."
|
||||
range 1 512
|
||||
default 20
|
||||
help
|
||||
Sets the default allocation size (bytes) for each attribute if not specified
|
||||
when the constructor is called. This is also the size used when a remote
|
||||
characteristic or descriptor is constructed before a value is read/notifed.
|
||||
Increasing this will reduce reallocations but increase memory footprint.
|
||||
|
||||
config NIMBLE_CPP_DEBUG_ASSERT_ENABLED
|
||||
bool "Enable debug asserts."
|
||||
default "n"
|
||||
help
|
||||
Enabling this option will add debug asserts to the NimBLE CPP library.
|
||||
This will use approximately 1kB of flash memory.
|
||||
|
||||
config NIMBLE_CPP_FREERTOS_TASK_BLOCK_BIT
|
||||
int "FreeRTOS task block bit"
|
||||
default 31
|
||||
help
|
||||
Configure the bit to set in the task notification value when a task is blocked waiting for an event.
|
||||
This should be set to a bit that is not used by other notifications in the system.
|
||||
|
||||
#
|
||||
# BT config
|
||||
#
|
||||
config BT_ENABLED
|
||||
bool "Bluetooth"
|
||||
default "y"
|
||||
help
|
||||
Select this option to enable Bluetooth and show the submenu with Bluetooth configuration choices.
|
||||
|
||||
|
||||
config BT_NIMBLE_ENABLED
|
||||
bool "NimBLE - BLE only"
|
||||
default "y"
|
||||
help
|
||||
This option is recommended for BLE only usecases to save on memory
|
||||
|
||||
if IDF_TARGET_ESP32P4
|
||||
|
||||
config BT_NIMBLE_TRANSPORT_UART
|
||||
bool "Enable Uart Transport"
|
||||
default "n"
|
||||
|
||||
#
|
||||
# Enable ESP Hosted BT
|
||||
# Used as VHCI transport between BT Host and Controller
|
||||
#
|
||||
config ESP_ENABLE_BT
|
||||
bool "Enable Hosted Bluetooth support"
|
||||
default "y"
|
||||
help
|
||||
Enable Bluetooth Support via Hosted
|
||||
|
||||
choice ESP_WIFI_REMOTE_LIBRARY
|
||||
prompt "Choose WiFi-remote implementation"
|
||||
default ESP_WIFI_REMOTE_LIBRARY_HOSTED
|
||||
help
|
||||
Select type of WiFi Remote implementation
|
||||
|
||||
ESP-HOSTED is the default and most versatile option.
|
||||
It's also possible to use EPPP, which uses PPPoS link between micros and NAPT, so it's slower
|
||||
and less universal.
|
||||
|
||||
config ESP_WIFI_REMOTE_LIBRARY_HOSTED
|
||||
bool "ESP-HOSTED"
|
||||
endchoice
|
||||
endif
|
||||
|
||||
endmenu
|
||||
|
4
LICENSE
4
LICENSE
@ -186,7 +186,7 @@
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
Copyright {2020} {Ryan Powell}
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@ -199,3 +199,5 @@
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
This product partly derives from esp32-snippets; Copyright 2017 Neil Kolban.
|
10
NOTICE
10
NOTICE
@ -1,10 +0,0 @@
|
||||
esp-nimble-cpp
|
||||
NimBLE-Arduino
|
||||
Copyright 2020-2024 Ryan Powell <ryan@nable-embedded.io> and
|
||||
esp-nimble-cpp, NimBLE-Arduino contributors.
|
||||
|
||||
The Initial Developer of some parts of this library, which are copied from,
|
||||
derived from, or inspired by is, esp32-snippets, Copyright 2017 Neil Kolban.
|
||||
|
||||
If this library is used for commercial purposes, it is requested that the user consider
|
||||
making a donation and/or sponsoring this project to support it's ongoing development.
|
37
README.md
37
README.md
@ -1,20 +1,19 @@
|
||||
[
|
||||
[Latest release 
|
||||
](https://github.com/h2zero/esp-nimble-cpp/releases/latest/)
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Version 2 is now released!
|
||||
> Check out the [1.x to 2.x Migration Guide](docs/1.x_to2.x_migration_guide.md) and [Release Notes](https://github.com/h2zero/esp-nimble-cpp/releases/latest/)
|
||||
Need help? Have questions or suggestions? Join the [](https://gitter.im/NimBLE-Arduino/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||
<br/>
|
||||
|
||||
# esp-nimble-cpp
|
||||
|
||||
NimBLE CPP library for use with ESP32 that attempts to maintain compatibility with the [nkolban cpp_utils BLE API](https://github.com/nkolban/esp32-snippets/tree/master/cpp_utils).
|
||||
NimBLE CPP library for use with ESP32 that attempts to maintain compatibility with the [nkolban cpp_uitls BLE API](https://github.com/nkolban/esp32-snippets/tree/master/cpp_utils).
|
||||
|
||||
**An Arduino version of this library, including NimBLE, can be [found here.](https://github.com/h2zero/NimBLE-Arduino)**
|
||||
|
||||
This library **significantly** reduces resource usage and improves performance for ESP32 BLE applications as compared
|
||||
with the bluedroid based library. The goal is to maintain, as much as reasonable, compatibility with the original
|
||||
library but using the NimBLE stack. In addition, this library will be more actively developed and maintained
|
||||
to provide improved capabilities and stability over the original.
|
||||
library but refactored to use the NimBLE stack. In addition, this library will be more actively developed and maintained
|
||||
to provide improved capabilites and stability over the original.
|
||||
|
||||
**Testing shows a nearly 50% reduction in flash use and approx. 100kB less ram consumed vs the original!**
|
||||
*Your results may vary*
|
||||
@ -36,6 +35,16 @@ Configure settings in `NimBLE Options`.
|
||||
Call `NimBLEDevice::init("");` in `app_main`.
|
||||
<br/>
|
||||
|
||||
### ESP-IDF v3.2 & v3.3
|
||||
The NimBLE component does not come with these versions of IDF (now included in 3.3.2 and above).
|
||||
A backport that works in these versions has been created and is [available here](https://github.com/h2zero/esp-nimble-component).
|
||||
Download or clone that repo into your project/components folder and run menuconfig.
|
||||
Configure settings in `main menu -> NimBLE Options`.
|
||||
|
||||
`#include "NimBLEDevice.h"` in main.cpp.
|
||||
Call `NimBLEDevice::init("");` in `app_main`.
|
||||
<br/>
|
||||
|
||||
# Using
|
||||
This library is intended to be compatible with the original ESP32 BLE functions and types with minor changes.
|
||||
|
||||
@ -53,17 +62,15 @@ When using this library along with Arduino and compiling with *CMake* you must a
|
||||
in your project/CMakeLists.txt after the line `include($ENV{IDF_PATH}/tools/cmake/project.cmake)` to prevent Arduino from releasing BLE memory.
|
||||
<br>
|
||||
|
||||
# Sponsors
|
||||
Thank you to all the sponsors who support this project!
|
||||
|
||||
<!-- sponsors --><!-- sponsors -->
|
||||
|
||||
If you use this library for a commercial product please consider [sponsoring the development](https://github.com/sponsors/h2zero) to ensure the continued updates and maintenance.
|
||||
<br/>
|
||||
|
||||
# Acknowledgments
|
||||
* [nkolban](https://github.com/nkolban) and [chegewara](https://github.com/chegewara) for the [original esp32 BLE library](https://github.com/nkolban/esp32-snippets/tree/master/cpp_utils) this project was derived from.
|
||||
* [beegee-tokyo](https://github.com/beegee-tokyo) for contributing your time to test/debug and contributing the beacon examples.
|
||||
* [Jeroen88](https://github.com/Jeroen88) for the amazing help debugging and improving the client code.
|
||||
<br/>
|
||||
|
||||
# Todo
|
||||
- Improve host reset handler
|
||||
- Implement random address handling
|
||||
- Implement bond management
|
||||
- Add Bluetooth Mesh
|
||||
<br/>
|
||||
|
2
component.mk
Normal file
2
component.mk
Normal file
@ -0,0 +1,2 @@
|
||||
COMPONENT_ADD_INCLUDEDIRS := src
|
||||
COMPONENT_SRCDIRS := src
|
@ -1,165 +0,0 @@
|
||||
# Migrating from 1.x to 2.x
|
||||
|
||||
Nearly all of the codebase has been updated and changed under the surface, which has greatly reduced the resource use of the library and improved it's performance. To be able to support these changes it required various API changes and additions.
|
||||
|
||||
This guide will help you migrate your application code to use the new API.
|
||||
|
||||
The changes listed here are only the required changes that must be made, and a short overview of options for migrating existing applications.
|
||||
|
||||
* [General changes](#general-changes)
|
||||
* [BLE Device](#ble-device)
|
||||
* [BLE Addresses](#ble-addresses)
|
||||
* [BLE UUID's](#ble-uuids)
|
||||
* [Server](#server)
|
||||
* [Services](#services)
|
||||
* [Characteristics](#characteristics)
|
||||
* [Characteristic Callbacks](#characteristic-callbacks)
|
||||
* [Security](#server)
|
||||
* [Client](#client)
|
||||
* [Client Callbacks](#client-callbacks)
|
||||
* [Remote Services](#remote-services)
|
||||
* [Remote characteristics](#remote-characteristics)
|
||||
* [Scanning](#scan)
|
||||
* [Advertise device](#advertised-device)
|
||||
* [Advertising](#advertising)
|
||||
* [Beacons](#beacons)
|
||||
* [Utilities](#utilities)
|
||||
<br/>
|
||||
|
||||
## General changes
|
||||
- All functions that take a time parameter now require the time in milliseconds instead of seconds, i.e. `NimBLEScan::start(10000); // 10 seconds`
|
||||
- `NimBLESecurity` class has been removed it's functionality has been merged into the `NimBLEServer` and `NimBLEClient` classes.
|
||||
- All connection oriented callbacks now receive a reference to `NimBLEConnInfo` and the `ble_gap_conn_desc` parameter has been replaced with `NimBLEConnInfo` in the functions that received it.
|
||||
For instance `onAuthenticationComplete(ble_gap_conn_desc* desc)` signature is now `onAuthenticationComplete(NimBLEConnInfo& connInfo)` and
|
||||
`NimBLEServerCallbacks::onConnect(NimBLEServer* pServer)` signature is now `NimBLEServerCallbacks::onConnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo)`.
|
||||
<br/>
|
||||
|
||||
## BLE Device
|
||||
- Ignore list functions and vector have been removed, the application should implement this if desired. It was no longer used by the library.
|
||||
- `NimBLEDevice::startSecurity` now returns a `bool`, true on success, instead of an int to be consistent with the rest of the library.
|
||||
- `NimBLEDevice::getInitialized` renamed to `NimBLEDevice::isInitialized`.
|
||||
- `NimBLEDevice::setPower` no longer takes the `esp_power_level_t` and `esp_ble_power_type_t`, instead only an integer value in dbm units is accepted, so instead of `ESP_PWR_LVL_P9` an `int8_t` value of `9` would be used for the same result.
|
||||
- `NimBLEDevice::setOwnAddrType` no longer takes a `bool nrpa` parameter, the random address type will be determined by the bits the in the address instead.
|
||||
Note: If setting a custom address, it should be set with `NimBLEDevice::setOwnAddr` first before calling `NimBLEDevice::setOwnAddrType`.
|
||||
- `NimBLEDevice::getClientListSize` replaced with `NimBLEDevice::getCreatedClientCount`.
|
||||
- `NimBLEDevice::getClientList` was removed and `NimBLEDevice::getConnectedClients` can be used instead which returns a `std::vector` of pointers to the connected client instances. This was done because internally the clients are managed in a `std::array` which replaced the 'std::list`.
|
||||
<br/>
|
||||
|
||||
## BLE Addresses
|
||||
NimBLEAddress comparisons have changed to now consider the address type. If 2 address values are the same but the type is different then they are no longer considered equal. This is a correction to the 1.x version which did not consider the type, whereas the BLE specification states:
|
||||
> Whenever two device addresses are compared, the comparison shall include the device address type (i.e. if the two addresses have different types, they are different even if the two 48-bit addresses are the same).
|
||||
|
||||
This means that if in your application you create a NimBLEAddress instance and are comparing a scan result or some other address created by the library and you did not define the address type then the comparison may fail.
|
||||
The default address type is public `0`, whereas many devices use a random `1` address type.
|
||||
If you experience this issue please create your address instances with the address type specified, i.e. `NimBLEAddress address("11:22:33:44:55:66", TYPE_HERE)`
|
||||
|
||||
`NimBLEAddress::getNative` has been removed and replaced with `NimBLEAddress::getBase`.
|
||||
This returns a pointer to `const ble_addr_t` instead of a pointer to the address value that `getNative` did. The value can be accessed through this struct via `ble_addr_t.value` and type is in `ble_addr_t.type`.
|
||||
<br/>
|
||||
|
||||
## BLE UUID's
|
||||
- `NimBLEUUID::getNative` method replaced with `NimBLEUUID::getBase` which returns a read-only pointer to the underlying `ble_uuid_t` struct.
|
||||
- `NimBLEUUID`; `msbFirst` parameter has been removed from constructor, caller should reverse the data first or call the new `NimBLEUUID::reverseByteOrder` method after.
|
||||
<br/>
|
||||
|
||||
## Server
|
||||
- `NimBLEServer::disconnect` now returns `bool`, true = success, instead of `int` to be consistent with the rest of the library.
|
||||
- `NimBLEServerCallbacks::onMTUChanged` renamed to `NimBLEServerCallbacks::onMTUChange` to be consistent with the client callback.
|
||||
- `NimBLEServer::getPeerIDInfo` renamed to `NimBLEServer::getPeerInfoByHandle` to better describe it's use.
|
||||
<br/>
|
||||
|
||||
### Services
|
||||
- `NimBLEService::getCharacteristics` now returns a `const std::vector<NimBLECharacteristic*>&` instead of a copy of the vector.
|
||||
<br/>
|
||||
|
||||
### Characteristics
|
||||
- `NimBLECharacteristic::notify` no longer takes a `bool is_notification` parameter, instead `NimBLECharacteristic::indicate` should be called to send indications.
|
||||
<br/>
|
||||
|
||||
#### Characteristic callbacks
|
||||
- `NimBLECharacteristicCallbacks::onNotify` removed as unnecessary, the library does not call notify without app input.
|
||||
- `NimBLECharacteristicCallbacks::onStatus` No longer takes a `status` parameter, refer to the return code parameter for success/failure.
|
||||
<br/>
|
||||
|
||||
### Server Security
|
||||
- `NimBLEServerCallbacks::onPassKeyRequest` has been renamed to `NimBLEServerCallbacks::onPassKeyDisplay` as it is intended that the device should display the passkey for the client to enter.
|
||||
- `NimBLEServerCallbacks::onAuthenticationComplete` now takes a `NimBLEConnInfo&` parameter.
|
||||
<br/>
|
||||
|
||||
## Client
|
||||
- `NimBLEClient::getServices` now returns a const reference to std::vector<NimBLERemoteService*> instead of a pointer to the internal vector.
|
||||
- `NimBLEClient::getConnId` has been renamed to `getConnHandle` to be consistent with bluetooth terminology.
|
||||
- `NimBLEClient::disconnect` now returns a `bool`, true on success, instead of an `int` to be consistent with the rest of the library.
|
||||
<br/>
|
||||
|
||||
### Client callbacks
|
||||
- `NimBLEClientCallbacks::onConfirmPIN` renamed to `NimBLEClientCallbacks::onConfirmPasskey`, takes a `NimBLEConnInfo&` parameter and no longer returns a value. This should be used to prompt a user to confirm the pin on the display (YES/NO) after which the response should be sent with `NimBLEDevice::injectConfirmPasskey`.
|
||||
- `NimBLEClientCallbacks::onPassKeyRequest` has been changed to `NimBLEClientCallbacks::onPassKeyEntry` which takes a `NimBLEConnInfo&` parameter and no longer returns a value. Instead of returning a value this callback should prompt a user to enter a passkey number which is sent later via `NimBLEDevice::injectPassKey`.
|
||||
<br/>
|
||||
|
||||
### Remote Services
|
||||
- `NimBLERemoteService::getCharacteristics` now returns a `const std::vector<NimBLERemoteCharacteristic*>&` instead of non-const `std::vector<NimBLERemoteCharacteristic*>*`.
|
||||
<br/>
|
||||
|
||||
### Remote Characteristics
|
||||
- `NimBLERemoteCharacteristic::getRemoteService` now returns a `const NimBLERemoteService*` instead of non-const.
|
||||
- `NimBLERemoteCharacteristic::registerForNotify`, has been removed, the application should use `NimBLERemoteCharacteristic::subscribe` and `NimBLERemoteCharacteristic::unSubscribe`.
|
||||
|
||||
`NimBLERemoteCharacteristic::readUInt32`
|
||||
`NimBLERemoteCharacteristic::readUInt16`
|
||||
`NimBLERemoteCharacteristic::readUInt8`
|
||||
`NimBLERemoteCharacteristic::readFloat`
|
||||
|
||||
Have been removed, instead the application should use `NimBLERemoteCharacteristic::readValue<type\>`.
|
||||
<br/>
|
||||
|
||||
## Scan
|
||||
- `NimBLEScan::stop` will no longer call the `onScanEnd` callback as the caller should know it has been stopped either by initiating a connection or calling this function itself.
|
||||
- `NimBLEScan::clearDuplicateCache` has been removed as it was problematic and only for the original esp32. The application should stop and start the scanner for the same effect or call `NimBLEScan::start` with the new `bool restart` parameter set to true.
|
||||
- `NimBLEScanResults::getDevice` methods now return `const NimBLEAdvertisedDevice*` instead of a non-const pointer.
|
||||
- `NimBLEScanResults` iterators are now `const_iterator`.
|
||||
- The callback parameter for `NimBLEScan::start` has been removed and the blocking overload of `NimBLEScan::start` has been replaced by an overload of `NimBLEScan::getResults` with the same parameters.
|
||||
|
||||
So if your code prior was this:
|
||||
|
||||
NimBLEScanResults results = pScan->start(10, false);
|
||||
|
||||
It should now be:
|
||||
|
||||
NimBLEScanResults results = pScan->getResults(10000, false); // note the time is now in milliseconds
|
||||
|
||||
- `NimBLEAdvertisedDeviceCallbacks` Has been replaced by `NimBLEScanCallbacks` which contains the following methods:
|
||||
- - `NimBLEScanCallbacks::onResult`, functions the same as the old `NimBLEAdvertisedDeviceCallbacks::onResult` but now takes aa `const NimBLEAdvertisedDevice*` instead of non-const.
|
||||
- - `NimBLEScanCallbacks::onScanEnd`, replaces the scanEnded callback passed to `NimBLEScan::start` and now takes a `const NimBLEScanResults&` and `int reason` parameter.
|
||||
- - `NimBLEScanCallbacks::onDiscovered`, This is called immediately when a device is first scanned, before any scan response data is available and takes a `const NimBLEAdvertisedDevice*` parameter.
|
||||
<br/>
|
||||
|
||||
### Advertised Device
|
||||
- `NimBLEAdvertisedDevice::hasRSSI` removed as redundant, RSSI is always available.
|
||||
- `NimBLEAdvertisedDevice::getPayload` now returns `const std::vector<uint8_t>&` instead of a pointer to internal memory.
|
||||
- `NimBLEAdvertisedDevice` Timestamp removed, if needed then the app should track the time from the callback.
|
||||
<br/>
|
||||
|
||||
## Advertising
|
||||
- `NimBLEAdvertising::setMinPreferred` and `NimBLEAdvertising::setMaxPreferred` have been removed and replaced by `NimBLEAdvertising::setPreferredParams` which takes both the min and max parameters.
|
||||
- Advertising the name and TX power of the device will no longer happen by default and should be set manually by the application using `NimBLEAdvertising::setName` and `NimBLEAdvertising::addTxPower`.
|
||||
- `NimBLEAdvertising::setAdvertisementType` has been renamed to `NimBLEAdvertising::setConnectableMode` to better reflect it's function.
|
||||
- `NimBLEAdvertising::setScanResponse` has been renamed to `NimBLEAdvertising::enableScanResponse` to better reflect it's function.
|
||||
- `NimBLEAdvertising`; Scan response is no longer enabled by default.
|
||||
- `NimBLEAdvertising::start` No longer takes a callback pointer parameter, instead the new method `NimBLEAdvertising::setAdvertisingCompleteCallback` should be used to set the callback function.
|
||||
<br/>
|
||||
|
||||
## Beacons
|
||||
- Removed Eddystone URL as it has been shutdown by google since 2021.
|
||||
- `NimBLEEddystoneTLM::setTemp` now takes an `int16_t` parameter instead of float to be friendly to devices without floating point support.
|
||||
- `NimBLEEddystoneTLM::getTemp` now returns `int16_t` to work with devices that don't have floating point support.
|
||||
- `NimBLEEddystoneTLM::setData` now takes a reference to * `NimBLEEddystoneTLM::BeaconData` instead of `std::string`.
|
||||
- `NimBLEEddystoneTLM::getData` now returns a reference to * `NimBLEEddystoneTLM::BeaconData` instead of `std::string`.
|
||||
- `NimBLEBeacon::setData` now takes `const NimBLEBeacon::BeaconData&` instead of `std::string`.
|
||||
- `NimBLEBeacon::getData` now returns `const NimBLEBeacon::BeaconData&` instead of `std::string`.
|
||||
<br/>
|
||||
|
||||
## Utilities
|
||||
- `NimBLEUtils::dumpGapEvent` function removed.
|
||||
- `NimBLEUtils::buildHexData` replaced with `NimBLEUtils::dataToHexString`, which returns a `std::string` containing the hex string.
|
||||
<br/>
|
@ -1,28 +0,0 @@
|
||||
# Bluetooth 5.x features
|
||||
|
||||
## About extended advertising
|
||||
Extended advertising allows for much more capability and flexibility.
|
||||
|
||||
* Allows for 251 bytes of advertisement data and up to 1650 bytes when chained (configuration dependant) vs 31.
|
||||
|
||||
* New PHY's (physical layers) that allow for faster data rate (2M PHY) or long range/slower data rates (CODED PHY) as well as the original 1M PHY.
|
||||
|
||||
* New periodic advertising, allowing the scanning device to sync with the advertisements of a beacon. This allows for the scanning device to sleep or perform other tasks before the next expected advertisement is sent, preserving cpu cycles and power (To be implemented).
|
||||
<br/>
|
||||
|
||||
## Enabling extended advertising
|
||||
Extended advertising is supported when enabled with the config option `CONFIG_BT_NIMBLE_EXT_ADV` set to a value of 1. This is done in menuconfig under `Component config > Bluetooth > NimBLE options > Enable extended advertising`, or set in `nimconfig.h` for Arduino, or in `build_flags` in PlatformIO.
|
||||
|
||||
When enabled the following will occur:
|
||||
* `NimBLEScan::start` method will scan on both the 1M PHY and the coded PHY standards automatically.
|
||||
|
||||
* `NimBLEClient::connect` will use the primary PHY the device is listening on, unless specified (see below).
|
||||
|
||||
* `NimBLEClient::setConnectPhy` becomes available to specify the PHY's to connect with (default is all).
|
||||
|
||||
* `NimBLEAdvertising` is no longer available for use and is replaced by `NimBLEExtAdvertising`. `NimBLEDevice::getAdvertising` will now return an instance of `NimBLEExtAdvertising`.
|
||||
|
||||
* `NimBLEAdvertisementData` is no longer available for use and is replaced by `NimBLEExtAdvertisement`. This new class is where everything about the advertisement is configured, including the advertisement intervals and advertisement ended callback.
|
||||
|
||||
|
||||
|
117
docs/Command_line_config.md
Normal file
117
docs/Command_line_config.md
Normal file
@ -0,0 +1,117 @@
|
||||
# Arduino command line and platformio config options
|
||||
|
||||
`CONFIG_BT_NIMBLE_MAX_CONNECTIONS`
|
||||
|
||||
Sets the number of simultaneous connections (esp controller max is 9)
|
||||
- Default value is 3
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_ATT_PREFERRED_MTU`
|
||||
|
||||
Sets the default MTU size.
|
||||
- Default value is 255
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_SVC_GAP_DEVICE_NAME`
|
||||
|
||||
Set the default device name
|
||||
- Default value is "nimble"
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_DEBUG`
|
||||
|
||||
If defined, enables debug log messages from the NimBLE host
|
||||
- Uses approx. 32kB of flash memory.
|
||||
<br/>
|
||||
|
||||
`CONFIG_NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT`
|
||||
|
||||
If defined, NimBLE host return codes will be printed as text in debug log messages.
|
||||
- Uses approx. 7kB of flash memory.
|
||||
<br/>
|
||||
|
||||
`CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT`
|
||||
|
||||
If defined, GAP event codes will be printed as text in debug log messages.
|
||||
- Uses approx. 1kB of flash memory.
|
||||
<br/>
|
||||
|
||||
`CONFIG_NIMBLE_CPP_ENABLE_ADVERTISMENT_TYPE_TEXT`
|
||||
|
||||
If defined, advertisment types will be printed as text while scanning in debug log messages.
|
||||
- Uses approx. 250 bytes of flash memory.
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_SVC_GAP_APPEARANCE`
|
||||
|
||||
Set the default appearance.
|
||||
- Default value is 0x00
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_ROLE_CENTRAL_DISABLED`
|
||||
|
||||
If defined, NimBLE Client functions will not be included.
|
||||
- Reduces flash size by approx. 7kB.
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_ROLE_OBSERVER_DISABLED`
|
||||
|
||||
If defined, NimBLE Scan functions will not be included.
|
||||
- Reduces flash size by approx. 26kB.
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_ROLE_PERIPHERAL_DISABLED`
|
||||
|
||||
If defined NimBLE Server functions will not be included.
|
||||
- Reduces flash size by approx. 16kB.
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_ROLE_BROADCASTER_DISABLED`
|
||||
|
||||
If defined, NimBLE Advertising functions will not be included.
|
||||
- Reduces flash size by approx. 5kB.
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_MAX_BONDS`
|
||||
|
||||
Sets the number of devices allowed to store/bond with
|
||||
- Default value is 3
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_MAX_CCCDS`
|
||||
|
||||
Sets the maximum number of CCCD subscriptions to store
|
||||
- Default value is 8
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_RPA_TIMEOUT`
|
||||
|
||||
Sets the random address refresh time in seconds.
|
||||
- Default value is 900
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_MSYS1_BLOCK_COUNT`
|
||||
|
||||
Set the number of msys blocks For prepare write & prepare responses. This may need to be increased if
|
||||
you are sending large blocks of data with a low MTU. E.g: 512 bytes with 23 MTU will fail.
|
||||
- Default value is 12
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL`
|
||||
|
||||
Sets the NimBLE stack to use external PSRAM will be loaded
|
||||
- Must be defined with a value of 1; Default is CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_INTERNAL 1
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_PINNED_TO_CORE`
|
||||
|
||||
Sets the core the NimBLE host stack will run on
|
||||
- Options: 0 or 1
|
||||
<br/>
|
||||
|
||||
`CONFIG_BT_NIMBLE_TASK_STACK_SIZE`
|
||||
|
||||
Set the task stack size for the NimBLE core.
|
||||
- Default is 4096
|
||||
<br/>
|
||||
|
840
docs/Doxyfile
840
docs/Doxyfile
File diff suppressed because it is too large
Load Diff
148
docs/Improvements_and_updates.md
Normal file
148
docs/Improvements_and_updates.md
Normal file
@ -0,0 +1,148 @@
|
||||
# Improvements and updates
|
||||
|
||||
Many improvements have been made to this library vs the original, this is a brief overview of the most significant changes.
|
||||
Refer to the [class documentation](https://h2zero.github.io/esp-nimble-cpp/annotated.html) for futher information on class specifics.
|
||||
|
||||
* [Server](#server)
|
||||
* [Advertising](#advertising)
|
||||
* [Client](#client)
|
||||
* [General](#general)
|
||||
<br/>
|
||||
|
||||
<a name="server"></a>
|
||||
# Server
|
||||
|
||||
`NimBLECharacteristic::setValue(const T &s)`
|
||||
`NimBLEDescriptor::setValue(const T &s)`
|
||||
|
||||
Now use a template to accomodate standard and custom types/values.
|
||||
|
||||
**Example**
|
||||
```
|
||||
struct my_struct{
|
||||
uint8_t one;
|
||||
uint16_t two;
|
||||
uint32_t four;
|
||||
uint64_t eight;
|
||||
float flt;
|
||||
}myStruct;
|
||||
|
||||
myStruct.one = 1;
|
||||
myStruct.two = 2;
|
||||
myStruct.four = 4;
|
||||
myStruct.eight = 8;
|
||||
myStruct.flt = 1234.56;
|
||||
|
||||
pCharacteristic->setValue(myStruct);
|
||||
```
|
||||
This will send the struct to the recieving client when read or a notification sent.
|
||||
|
||||
`NimBLECharacteristic::getValue` now takes an optional timestamp parameter which will update it's value with
|
||||
the time the last value was recieved. In addition an overloaded template has been added to retrieve the value
|
||||
as a type specified by the user.
|
||||
|
||||
**Example**
|
||||
```
|
||||
time_t timestamp;
|
||||
myStruct = pCharacteristic->getValue<myStruct>(×tamp); // timestamp optional
|
||||
```
|
||||
<br/>
|
||||
|
||||
**Advertising will automatically start when a client disconnects.**
|
||||
|
||||
A new method `NimBLEServer::advertiseOnDisconnect(bool)` has been implemented to control this, true(default) = enabled.
|
||||
<br/>
|
||||
|
||||
`NimBLEServer::removeService` takes an additional parameter `bool deleteSvc` that if true will delete the service
|
||||
and all characteristics / descriptors belonging to it and invalidating any pointers to them.
|
||||
|
||||
If false the service is only removed from visibility by clients. The pointers to the service and
|
||||
it's characteristics / descriptors will remain valid and the service can be re-added in the future
|
||||
using `NimBLEServer::addService`.
|
||||
<br/>
|
||||
|
||||
<a name="advertising"></a>
|
||||
# Advertising
|
||||
`NimBLEAdvertising::start`
|
||||
|
||||
Now takes 2 optional parameters, the first is the duration to advertise for (in seconds), the second is a callback
|
||||
that is invoked when advertsing ends and takes a pointer to a `NimBLEAdvertising` object (similar to the `NimBLEScan::start` API).
|
||||
|
||||
This provides an opportunity to update the advertisment data if desired.
|
||||
|
||||
Also now returns a bool value to indicate if advertising successfully started or not.
|
||||
<br/>
|
||||
|
||||
<a name="client"></a>
|
||||
# Client
|
||||
|
||||
`NimBLERemoteCharacteristic::readValue(time_t\*, bool)`
|
||||
`NimBLERemoteDescriptor::readValue(bool)`
|
||||
|
||||
Have been added as templates to allow reading the values as any specified type.
|
||||
|
||||
**Example**
|
||||
```
|
||||
struct my_struct{
|
||||
uint8_t one;
|
||||
uint16_t two;
|
||||
uint32_t four;
|
||||
uint64_t eight;
|
||||
float flt;
|
||||
}myStruct;
|
||||
|
||||
time_t timestamp;
|
||||
myStruct = pRemoteCharacteristic->readValue<myStruct>(×tamp); // timestamp optional
|
||||
```
|
||||
<br/>
|
||||
|
||||
`NimBLERemoteCharacteristic::registerForNotify`
|
||||
Has been **deprecated** as now the internally stored characteristic value is updated when notification/indication is recieved.
|
||||
|
||||
`NimBLERemoteCharacteristic::subscribe` and `NimBLERemoteCharacteristic::unsubscribe` have been implemented to replace it.
|
||||
A callback is no longer requred to get the most recent value unless timing is important. Instead, the application can call `NimBLERemoteCharacteristic::getValue` to
|
||||
get the last updated value any time.
|
||||
<br/>
|
||||
|
||||
The `notifiy_callback` function is now defined as a `std::function` to take advantage of using `std::bind` to specifiy a class member function for the callback.
|
||||
|
||||
Example:
|
||||
```
|
||||
using namespace std::placeholders;
|
||||
notify_callback callback = std::bind(&<ClassName>::<memberFunctionCallbackName>, this, _1, _2, _3, _4);
|
||||
<remoteCharacteristicInstance>->subscribe(true, callback);
|
||||
```
|
||||
|
||||
`NimBLERemoteCharacteristic::readValue` and `NimBLERemoteCharacteristic::getValue` take an optional timestamp parameter which will update it's value with
|
||||
the time the last value was recieved.
|
||||
|
||||
> NimBLEClient::getService
|
||||
> NimBLERemoteService::getCharacteristic
|
||||
> NimBLERemoteCharacteristic::getDescriptor
|
||||
|
||||
These methods will now check the respective vectors for the attribute object and, if not found, will retrieve (only)
|
||||
the specified attribute from the peripheral.
|
||||
|
||||
These changes allow more control for the user to manage the resources used for the attributes.
|
||||
<br/>
|
||||
|
||||
`NimBLEClient::connect()` can now be called without an address or advertised device parameter. This will connect to the
|
||||
device with the address previously set when last connected or set with `NimBLEDevice::setPeerAddress()`.
|
||||
|
||||
<a name="general"></a>
|
||||
# General
|
||||
To reduce resource use all instances of `std::map` have been replaced with `std::vector`.
|
||||
|
||||
Use of `FreeRTOS::Semaphore` has been removed as it was consuming too much ram, the related files have been left in place to accomodate application use.
|
||||
|
||||
Operators `==`, `!=` and `std::string` have been added to `NimBLEAddress` and `NimBLEUUID` for easier comparison and logging.
|
||||
|
||||
New constructor for `NimBLEUUID(uint32_t, uint16_t, uint16_t, uint64_t)` added to lower memory use vs string construction. See: [#21](https://github.com/h2zero/NimBLE-Arduino/pull/21).
|
||||
|
||||
Security/pairing operations are now handled in the respective `NimBLEClientCallbacks` and `NimBLEServerCallbacks` classes, `NimBLESecurity`(deprecated) remains for backward compatibility.
|
||||
|
||||
Configuration options have been added to add or remove debugging information, when disabled (default) significatly reduces binary size.
|
||||
In ESP-IDF the options are in menuconfig: `Main menu -> ESP-NimBLE-cpp configuration`.
|
||||
For Arduino the options must be commented / uncommented in nimconfig.h.
|
||||
<br/>
|
||||
|
@ -4,114 +4,99 @@ This guide describes the required changes to existing projects migrating from th
|
||||
|
||||
**The changes listed here are only the required changes that must be made**, and a short overview of options for migrating existing applications.
|
||||
|
||||
For more information on the improvements and additions please refer to the [class documentation](https://h2zero.github.io/esp-nimble-cpp/annotated.html)
|
||||
For more information on the improvements and additions please refer to the [class documentation](https://h2zero.github.io/esp-nimble-cpp/annotated.html) and [Improvements and updates](Improvements_and_updates.md)
|
||||
|
||||
* [General Changes](#general-information)
|
||||
* [Server](#server-api)
|
||||
* [Services](#services)
|
||||
* [Characteristics](#characteristics)
|
||||
* [Characteristic Callbacks](#characteristic-callbacks)
|
||||
* [Descriptors](#descriptors)
|
||||
* [Descriptor Callbacks](#descriptor-callbacks)
|
||||
* [characteristics](#characteristics)
|
||||
* [descriptors](#descriptors)
|
||||
* [Security](#server-security)
|
||||
* [Advertising](#advertising-api)
|
||||
* [Client](#client-api)
|
||||
* [Remote Services](#remote-services)
|
||||
* [Remote characteristics](#remote-characteristics)
|
||||
* [Client Callbacks](#client-callbacks)
|
||||
* [Security](#client-security)
|
||||
* [BLE scan](#ble-scan)
|
||||
* [General Security](#security-api)
|
||||
* [Configuration](#arduino-configuration)
|
||||
<br/>
|
||||
|
||||
<a name="general-information"></a>
|
||||
## General Information
|
||||
|
||||
### Header Files
|
||||
All classes are accessible by including `NimBLEDevice.h` in your application, no further headers need to be included.
|
||||
|
||||
(Mainly for Arduino) You may choose to include `NimBLELog.h` in your 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.
|
||||
|
||||
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).
|
||||
|
||||
As this parameter is optional no changes to existing code are needed, it is mentioned here for information.
|
||||
|
||||
`BLEAddress::getNative` is now named `NimBLEAddress::getBase` and returns a pointer to `const ble_addr_t` instead of a pointer to the address value.
|
||||
As this paramameter is optional no changes to existing code are needed, it is mentioned here for information.
|
||||
<br/>
|
||||
`BLEAddress::getNative` (`NimBLEAddress::getNative`) returns a uint8_t pointer to the native address byte array.
|
||||
In this library the address bytes are stored in reverse order from the original library. This is due to the way
|
||||
the NimBLE stack expects addresses to be presented to it. All other functions such as `toString` are
|
||||
not affected as the endian change is made within them.
|
||||
<br/>
|
||||
|
||||
<a name="server-api"></a>
|
||||
## Server API
|
||||
Creating a `BLEServer` instance is the same as original, no changes required.
|
||||
For example `BLEDevice::createServer()` will work just as it did before.
|
||||
|
||||
`BLEServerCallbacks` (`NimBLEServerCallbacks`) has new methods for handling security operations.
|
||||
<br/>
|
||||
|
||||
`BLEServerCallbacks::onConnect` (`NimBLEServerCallbacks::onConnect`) only has a single callback declaration which takes an additional (required) parameter `NimBLEConnInfo & connInfo`, which has methods to get information about the connected peer.
|
||||
```
|
||||
void onConnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo)`
|
||||
```
|
||||
<br/>
|
||||
|
||||
`BLEServerCallbacks::onDisconnect` (`NimBLEServerCallbacks::onDisconnect`) only has a single callback declaration which takes 2 additional (required) parameters `NimBLEConnInfo & connInfo`, which provides information about the peer and `int reason`, which gives the reason code for disconnection.
|
||||
|
||||
```
|
||||
void onDisconnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo, int reason)`
|
||||
```
|
||||
<br/>
|
||||
|
||||
`BLEServerCallbacks::onMtuChanged` is now (`NimBLEServerCallbacks::onMtuChange`) and takes the parameter `NimBLEConnInfo & connInfo` instead of `esp_ble_gatts_cb_param_t`, which has methods to get information about the connected peer.
|
||||
|
||||
```
|
||||
onMTUChange(uint16_t MTU, NimBLEConnInfo& connInfo)
|
||||
```
|
||||
|
||||
**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.
|
||||
<br/>
|
||||
|
||||
<a name="characteristics"></a>
|
||||
### Characteristics
|
||||
The constructor for `(Nim)BLECharacteristic` is now private, so if you currently subclass it to add logic you should switch to use `NimBLEService::createCharacteristic` instead. Any custom processing logic previously in a `BLECharacteristic` subclass should be moved to a `NimBLECharacteristicCallbacks` subclass instead, and passed into `NimBLECharacteristic::setCallbacks`.
|
||||
|
||||
`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_WRITE
|
||||
|
||||
#### Is Now
|
||||
> NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE
|
||||
> 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_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:**
|
||||
@ -133,15 +118,8 @@ BLECharacteristic *pCharacteristic = pService->createCharacteristic(
|
||||
```
|
||||
<br/>
|
||||
|
||||
#### Characteristic callbacks
|
||||
|
||||
`BLECharacteristicCallbacks` (`NimBLECharacteristicCallbacks`) has a new method `NimBLECharacteristicCallbacks::onSubscribe` which is called when a client subscribes to notifications/indications.
|
||||
|
||||
`BLECharacteristicCallbacks::onRead` (`NimBLECharacteristicCallbacks::onRead`) only has a single callback declaration, which takes an additional (required) parameter of `NimBLEConnInfo& connInfo`, which provides connection information about the peer.
|
||||
|
||||
`BLECharacteristicCallbacks::onWrite` (`NimBLECharacteristicCallbacks::onWrite`) only has a single callback declaration, which takes an additional (required) parameter of `NimBLEConnInfo& connInfo`, which provides connection information about the peer.
|
||||
|
||||
`BLECharacteristicCallbacks::onStatus` (`NimBLECharacteristicCallbacks::onStatus`) has had the status parameter removed as it was unnecessary since the status code from the BLE stack was also provided. The status code for success is 0 for notifications and BLE_HS_EDONE for indications, any other value is an error.
|
||||
`BLECharacteristicCallbacks` (`NimBLECharacteristicCallbacks`) has a new method `NimBLECharacteristicCallbacks::onSubscribe`
|
||||
which is called when a client subscribes to notifications/indications.
|
||||
|
||||
**Note:** All callback methods have default implementations which allows the application to implement only the methods applicable.
|
||||
<br/>
|
||||
@ -164,7 +142,9 @@ my_struct_t myStruct = pChr->getValue<my_struct_t>();
|
||||
```
|
||||
<br/>
|
||||
|
||||
<a name="descriptors"></a>
|
||||
### Descriptors
|
||||
The previous method `BLECharacteristic::addDescriptor()` has been removed.
|
||||
|
||||
Descriptors are now created using the `NimBLECharacteristic::createDescriptor` method.
|
||||
|
||||
@ -174,7 +154,8 @@ NimBLE automatically creates the 0x2902 descriptor if a characteristic has a not
|
||||
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 a warning message and flag it internally as removed and will not be functional.
|
||||
**Note:** Attempting to create a 0x2902 descriptor will trigger an assert to notify the error,
|
||||
allowing the creation of it would cause a fault in the NimBLE stack.
|
||||
|
||||
All other descriptors are now created just as characteristics are by using the `NimBLECharacteristic::createDescriptor` method (except 0x2904, see below).
|
||||
Which are defined as:
|
||||
@ -191,7 +172,7 @@ NimBLEDescriptor* createDescriptor(NimBLEUUID uuid,
|
||||
NIMBLE_PROPERTY::WRITE,
|
||||
uint16_t max_len = 100);
|
||||
```
|
||||
#### Example
|
||||
##### Example
|
||||
```
|
||||
pDescriptor = pCharacteristic->createDescriptor("ABCD",
|
||||
NIMBLE_PROPERTY::READ |
|
||||
@ -202,78 +183,93 @@ pDescriptor = pCharacteristic->createDescriptor("ABCD",
|
||||
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 specialized class that is created through `NimBLECharacteristic::create2904` which returns a pointer to a `NimBLE2904` instance which has specific
|
||||
functions for handling the data expect in the Characteristic Presentation Format Descriptor specification.
|
||||
<br/>
|
||||
|
||||
#### Descriptor callbacks
|
||||
|
||||
> `BLEDescriptorCallbacks::onRead` (`NimBLEDescriptorCallbacks::onRead`)
|
||||
`BLEDescriptorCallbacks::onWrite` (`NimBLEDescriptorCallbacks::onWrite`)
|
||||
|
||||
The above descriptor callbacks take an additional (required) parameter `NimBLEConnInfo& connInfo`, which contains the connection information of the peer.
|
||||
For the 0x2904, there is a special class that is created when you call `createDescriptor("2904").
|
||||
|
||||
The pointer returned is of the base class `NimBLEDescriptor` but the call will create the derived class of `NimBLE2904` so you must cast the returned pointer to
|
||||
`NimBLE2904` to access the specific class methods.
|
||||
|
||||
##### Example
|
||||
```
|
||||
p2904 = (NimBLE2904*)pCharacteristic->createDescriptor("2904");
|
||||
```
|
||||
<br/>
|
||||
|
||||
<a name="server-security"></a>
|
||||
### Server Security
|
||||
Security is set on the characteristic or descriptor properties by applying one of the following:
|
||||
> NIMBLE_PROPERTY::READ_ENC
|
||||
NIMBLE_PROPERTY::READ_AUTHEN
|
||||
NIMBLE_PROPERTY::READ_AUTHOR
|
||||
NIMBLE_PROPERTY::WRITE_ENC
|
||||
NIMBLE_PROPERTY::WRITE_AUTHEN
|
||||
NIMBLE_PROPERTY::WRITE_AUTHOR
|
||||
|
||||
<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.
|
||||
> NIMBLE_PROPERTY::READ_AUTHEN
|
||||
> NIMBLE_PROPERTY::READ_AUTHOR
|
||||
> NIMBLE_PROPERTY::WRITE_ENC
|
||||
> NIMBLE_PROPERTY::WRITE_AUTHEN
|
||||
> NIMBLE_PROPERTY::WRITE_AUTHOR
|
||||
|
||||
When a peer wants to read or write a characteristic or descriptor with any of these properties applied
|
||||
it will trigger the pairing process. By default the "just-works" pairing will be performed automatically.
|
||||
This can be changed to use passkey authentication or numeric comparison. See [Security API](#security-api) for details.
|
||||
<br/>
|
||||
|
||||
<a name="advertising-api"></a>
|
||||
## Advertising API
|
||||
Advertising works the same as the original API except:
|
||||
> BLEAdvertising::setMinPreferred
|
||||
> BLEAdvertising::setMaxPreferred
|
||||
|
||||
These methods were found to not provide useful functionality and consumed valuable advertising space (6 bytes of 31) if used unknowingly.
|
||||
If you wish to advertise these parameters you can still do so manually via `BLEAdvertisementData::addData` (`NimBLEAdvertisementData::addData`).
|
||||
<br/>
|
||||
|
||||
Calling `NimBLEAdvertising::setAdvertisementData` will entirely replace any data set with `NimBLEAdvertising::addServiceUUID`, or
|
||||
`NimBLEAdvertising::setAppearance` or similar methods. You should set all the data you wish to advertise within the `NimBLEAdvertisementData` instead.
|
||||
|
||||
~~Calling `NimBLEAdvertising::setScanResponseData` without also calling `NimBLEAdvertising::setAdvertisementData` will have no effect.
|
||||
When using custom scan response data you must also use custom advertisement data.~~
|
||||
No longer true as of release 1.2.0 and above, custom scan response is now supported without custom advertisement data.
|
||||
<br/>
|
||||
|
||||
> BLEAdvertising::start (NimBLEAdvertising::start)
|
||||
|
||||
Now takes 2 optional parameters, the first is the duration to advertise for (in milliseconds), the second `NimBLEAddress` to direct advertising to a specific device.
|
||||
Now takes 2 optional parameters, the first is the duration to advertise for (in seconds), the second is a callback
|
||||
that is invoked when advertsing ends and takes a pointer to a `NimBLEAdvertising` object (similar to the `NimBLEScan::start` API).
|
||||
|
||||
This provides an opportunity to update the advertisment data if desired.
|
||||
<br/>
|
||||
|
||||
<a name="client-api"></a>
|
||||
## Client API
|
||||
|
||||
Client instances are created just as before with `BLEDevice::createClient` (`NimBLEDevice::createClient`).
|
||||
|
||||
Multiple client instances can be created, up to the maximum number of connections set in the config file (default: 3). To delete a client instance you must use `NimBLEDevice::deleteClient`.
|
||||
Multiple client instances can be created, up to the maximum number of connections set in the config file (default: 3).
|
||||
To delete a client instance you must use `NimBLEDevice::deleteClient`.
|
||||
|
||||
`BLEClient::connect`(`NimBLEClient::connect`) Has had it's parameters altered.
|
||||
Defined as:
|
||||
> NimBLEClient::connect(bool deleteServices = true, , bool asyncConnect = false, bool exchangeMTU = true);
|
||||
> NimBLEClient::connect(const NimBLEAddress& address, bool deleteAttributes = true, bool asyncConnect = false, bool exchangeMTU = true);
|
||||
> NimBLEClient::connect(const NimBLEAdvertisedDevice* device, bool deleteServices = true, bool asyncConnect = false, bool exchangeMTU = 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 parameter `bool asyncConnect` if true, will cause the client to send the connect command to the stack and return immediately without blocking. The return value will represent wether the command was sent successfully or not and the `NimBLEClientCallbacks::onConnect` or `NimBLEClientCallbacks::onConnectFail` will be called when the operation is complete.
|
||||
|
||||
The parameter `bool exchangeMTU` if true, will cause the client to perform the exchange MTU process upon connecting. If false the MTU exchange will need to be performed by the application by calling `NimBLEClient::exchangeMTU`. If the connection is only sending small payloads it may be advantageous to not exchange the MTU to gain performance in the connection process.
|
||||
The type parameter has been removed and a new bool parameter has been added to indicate if the client should
|
||||
delete the attribute database previously retrieved (if applicable) for the peripheral, default value is true.
|
||||
If set to false the client will use the attribute database it retrieved from the peripheral when previously connected.
|
||||
This allows for faster connections and power saving if the devices dropped connection and are reconnecting.
|
||||
<br/>
|
||||
|
||||
> `BLEClient::getServices` (`NimBLEClient::getServices`)
|
||||
|
||||
This method now takes an optional (bool) parameter to indicate if the services should be retrieved from the server (true) or the currently known database returned (false : default).
|
||||
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.
|
||||
**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.
|
||||
**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:
|
||||
|
||||
@ -284,23 +280,24 @@ This method has been removed.
|
||||
|
||||
> `BLERemoteService::getCharacteristics` (`NimBLERemoteService::getCharacteristics`)
|
||||
|
||||
This method now takes an optional (bool) parameter to indicate if the characteristics should be retrieved from the server (true) or the currently known database returned, default = false.
|
||||
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`)
|
||||
|
||||
Now returns 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`
|
||||
|
||||
Has been removed.
|
||||
> `BLERemoteCharacteristic::registerForNotify` (`NimBLERemoteCharacteristic::registerForNotify`)
|
||||
|
||||
Is now **deprecated**.
|
||||
> `NimBLERemoteCharacteristic::subscribe`
|
||||
> `NimBLERemoteCharacteristic::unsubscribe`
|
||||
|
||||
@ -312,7 +309,7 @@ Are the new methods added to replace it.
|
||||
> `BLERemoteCharacteristic::readUInt32` (`NimBLERemoteCharacteristic::readUInt32`)
|
||||
> `BLERemoteCharacteristic::readFloat` (`NimBLERemoteCharacteristic::readFloat`)
|
||||
|
||||
Are **removed** 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`
|
||||
@ -320,10 +317,10 @@ Are **removed** a template: `NimBLERemoteCharacteristic::readValue<type\>(time_t
|
||||
**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 as a `NimBLEAttValue` instance and use the `NimBLEAttValue::data` member function to obtain the pointer.
|
||||
To obatain a copy of the data, then cast the returned std::string to the type required such as:
|
||||
```
|
||||
NimBLEAttValue value = pChr->readValue();
|
||||
const uint8_t *data = value.data();
|
||||
std::string value = pChr->readValue();
|
||||
uint8_t *data = (uint8_t*)value.data();
|
||||
```
|
||||
Alternatively use the `readValue` template:
|
||||
```
|
||||
@ -333,56 +330,40 @@ my_struct_t myStruct = pChr->readValue<my_struct_t>();
|
||||
|
||||
> `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, default = false.
|
||||
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/>
|
||||
|
||||
### Client callbacks
|
||||
|
||||
> `BLEClientCallbacks::onDisconnect` (`NimBLEClientCallbacks::onDisconnect`)
|
||||
|
||||
This now takes a second parameter `int reason` which provides the reason code for disconnection.
|
||||
<br/>
|
||||
|
||||
<a name="client-security"></a>
|
||||
### Client Security
|
||||
The client will automatically initiate security when the peripheral responds that it's required.
|
||||
The default configuration will use "just-works" pairing with no bonding, if you wish to enable bonding see below.
|
||||
<br/>
|
||||
|
||||
## BLE Scan
|
||||
The scan API is mostly unchanged from the original except for `NimBLEScan::start`, which has the following changes:
|
||||
* The duration parameter is now in milliseconds instead of seconds.
|
||||
* The callback parameter has been removed.
|
||||
* A new parameter `bool restart` has been added, when set to true to restart the scan if already in progress and clear the duplicate cache.
|
||||
|
||||
The blocking overload of `NimBLEScan::start` has been replaced by an overload of `NimBLEScan::getResults` with the same parameters.
|
||||
<br/>
|
||||
|
||||
<a name="security-api"></a>
|
||||
## Security API
|
||||
Security operations have been moved to `BLEDevice` (`NimBLEDevice`).
|
||||
The security callback methods are now incorporated in the `NimBLEServerCallbacks` / `NimBLEClientCallbacks` classes.
|
||||
|
||||
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 onConfirmPasskey(NimBLEConnInfo& connInfo, uint32_t pin)`
|
||||
> `bool onConfirmPIN(uint32_t pin)`
|
||||
|
||||
Receives the pin when using numeric comparison authentication.
|
||||
Call `NimBLEDevice::injectConfirmPasskey(connInfo, true);` to accept or `NimBLEDevice::injectConfirmPasskey(connInfo, false);` to reject.
|
||||
Receives the pin when using numeric comparison authentication, `return true;` to accept.
|
||||
<br/>
|
||||
|
||||
> `void onPassKeyEntry(NimBLEConnInfo& connInfo)`
|
||||
> `uint32_t onPassKeyRequest()`
|
||||
|
||||
Client callback; client should respond with the passkey (pin) by calling `NimBLEDevice::injectPassKey(connInfo, 123456);`
|
||||
For server callback; return the passkey expected from the client.
|
||||
For client callback; return the passkey to send to the server.
|
||||
<br/>
|
||||
|
||||
> `uint32_t onPassKeyDisplay()`
|
||||
> `void onAuthenticationComplete(ble_gap_conn_desc\* desc)`
|
||||
|
||||
Server callback; should return the passkey (pin) expected from the client.
|
||||
<br/>
|
||||
|
||||
> `void onAuthenticationComplete(NimBLEConnInfo& connInfo)`
|
||||
|
||||
Authentication complete, success or failed information is available from the `NimBLEConnInfo` methods.
|
||||
Authentication complete, success or failed information is in `desc`.
|
||||
<br/>
|
||||
|
||||
Security settings and IO capabilities are now set by the following methods of NimBLEDevice.
|
||||
@ -407,11 +388,14 @@ If we are the initiator of the security procedure this sets the keys we will dis
|
||||
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*
|
||||
<br/>
|
||||
|
@ -21,8 +21,9 @@ If you're not creating a server or do not want to advertise a name, simply pass
|
||||
This can be called any time you wish to use BLE functions and does not need to be called from app_main(IDF) or setup(Arduino) but usually is.
|
||||
<br/>
|
||||
|
||||
<a name="creating-a-server"></a>
|
||||
## Creating a Server
|
||||
BLE servers perform 2 tasks, they advertise their 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.
|
||||
|
||||
@ -90,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()`.
|
||||
|
||||
@ -136,6 +137,7 @@ Now if you scan with your phone using nRFConnect or any other BLE app you should
|
||||
For more advanced features and options please see the server examples in the examples folder.
|
||||
<br/>
|
||||
|
||||
<a name="creating-a-client"></a>
|
||||
## Creating a Client
|
||||
|
||||
BLE clients perform 2 tasks, they scan for advertising servers and form connections to them to read and write to their characteristics/descriptors.
|
||||
@ -144,7 +146,7 @@ After initializing the NimBLE stack we create a scan instance by calling `NimBLE
|
||||
|
||||
Once we have created the scan we can start looking for advertising servers.
|
||||
|
||||
To do this we call `NimBLEScan::start(duration)`, the duration parameter is a uint32_t that specifies the number of milliseconds to scan for,
|
||||
To do this we call `NimBLEScan::start(duration)`, the duration parameter is a uint32_t that specifies the number of seconds to scan for,
|
||||
passing 0 will scan forever.
|
||||
|
||||
In this example we will scan for 10 seconds. This is a blocking function (a non blocking overload is also available).
|
||||
@ -160,7 +162,7 @@ void app_main(void)
|
||||
NimBLEDevice::init("");
|
||||
|
||||
NimBLEScan *pScan = NimBLEDevice::getScan();
|
||||
NimBLEScanResults results = pScan->getResults(10 * 1000);
|
||||
NimBLEScanResults results = pScan->start(10);
|
||||
}
|
||||
```
|
||||
<br/>
|
||||
@ -212,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.
|
||||
@ -220,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()`.
|
||||
@ -300,7 +302,7 @@ void app_main(void)
|
||||
NimBLEDevice::init("");
|
||||
|
||||
NimBLEScan *pScan = NimBLEDevice::getScan();
|
||||
NimBLEScanResults results = pScan->start(10 * 1000);
|
||||
NimBLEScanResults results = pScan->start(10);
|
||||
|
||||
NimBLEUUID serviceUuid("ABCD");
|
||||
|
||||
|
@ -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.
|
||||
|
@ -1,4 +1,5 @@
|
||||
# Overview
|
||||
|
||||
This is a C++ BLE library for the ESP32 that uses the NimBLE host stack instead of bluedroid.
|
||||
The aim is to maintain, as much as reasonable, the original bluedroid C++ & Arduino BLE API by while adding new features
|
||||
and making improvements in performance, resource use, and stability.
|
||||
@ -12,8 +13,20 @@ 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+
|
||||
### v4.0+
|
||||
Download as .zip and extract or clone into the components folder in your esp-idf project.
|
||||
|
||||
Run menuconfig, go to `Component config->Bluetooth` enable Bluetooth and in `Bluetooth host` NimBLE.
|
||||
@ -22,6 +35,16 @@ Configure settings in `NimBLE Options`.
|
||||
Call `NimBLEDevice::init` in `app_main`.
|
||||
<br/>
|
||||
|
||||
### v3.2 & v3.3
|
||||
The NimBLE component does not come with these versions of IDF (now included in 3.3.2 and above).
|
||||
A backport that works in these versions has been created and is [available here](https://github.com/h2zero/esp-nimble-component).
|
||||
Download or clone that repo into your project/components folder and run menuconfig.
|
||||
Configure settings in `main menu -> NimBLE Options`.
|
||||
|
||||
`#include "NimBLEDevice.h"` in main.cpp.
|
||||
Call `NimBLEDevice::init` in `app_main`.
|
||||
<br/>
|
||||
|
||||
# Using
|
||||
This library is intended to be compatible with the original ESP32 BLE functions and types with minor changes.
|
||||
|
||||
@ -29,16 +52,32 @@ If you have not used the original Bluedroid library please refer to the [New use
|
||||
|
||||
If you are familiar with the original library, see: [The migration guide](Migration_guide.md) for details.
|
||||
|
||||
Also see [Improvements and updates](Improvements_and_updates.md) for information about non-breaking changes.
|
||||
|
||||
For more advanced usage see [Usage tips](Usage_tips.md) for more performance and optimization.
|
||||
<br/>
|
||||
|
||||
# Sponsors
|
||||
Thank you to all the sponsors who support this project!
|
||||
### Arduino specific
|
||||
See the Refactored_original_examples in the examples folder for highlights of the differences with the original library.
|
||||
|
||||
If you use this library for a commercial product please consider [sponsoring the development](https://github.com/sponsors/h2zero) to ensure the continued updates and maintenance.
|
||||
More advanced examples highlighting many available features are in examples/NimBLE_Server, NimBLE_Client.
|
||||
|
||||
Beacon examples provided by [beegee-tokyo](https://github.com/beegee-tokyo) are in examples/BLE_Beacon_Scanner, BLE_EddystoneTLM_Beacon, BLE_EddystoneURL_Beacon.
|
||||
|
||||
Change the settings in the nimconfig.h file to customize NimBLE to your project, such as increasing max connections (default is 3).
|
||||
<br/>
|
||||
|
||||
### Arduino command line and platformio
|
||||
As an alternative to changing the configuration in nimconfig.h, Arduino command line and platformio.ini options are available.
|
||||
See the command line configuration options available in [Command line config](Command_line_config.md).
|
||||
<br/>
|
||||
|
||||
# Need help? Have a question or suggestion?
|
||||
Come chat on [gitter](https://gitter.im/NimBLE-Arduino/community?utm_source=share-link&utm_medium=link&utm_campaign=share-link) or open an issue at [NimBLE-Arduino](https://github.com/h2zero/NimBLE-Arduino/issues) or [esp-nimble-cpp](https://github.com/h2zero/esp-nimble-cpp/issues)
|
||||
<br/>
|
||||
|
||||
# Acknowledgments
|
||||
|
||||
* [nkolban](https://github.com/nkolban) and [chegewara](https://github.com/chegewara) for the [original esp32 BLE library](https://github.com/nkolban/esp32-snippets/tree/master/cpp_utils) this project was derived from.
|
||||
* [beegee-tokyo](https://github.com/beegee-tokyo) for contributing your time to test/debug and contributing the beacon examples.
|
||||
* [Jeroen88](https://github.com/Jeroen88) for the amazing help debugging and improving the client code.
|
||||
|
@ -3,4 +3,5 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
set(SUPPORTED_TARGETS esp32)
|
||||
project(NimBLE_Client)
|
3
examples/Advanced/NimBLE_Client/Makefile
Normal file
3
examples/Advanced/NimBLE_Client/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
PROJECT_NAME := NimBLE_Client
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
4
examples/Advanced/NimBLE_Client/main/component.mk
Normal file
4
examples/Advanced/NimBLE_Client/main/component.mk
Normal file
@ -0,0 +1,4 @@
|
||||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
372
examples/Advanced/NimBLE_Client/main/main.cpp
Normal file
372
examples/Advanced/NimBLE_Client/main/main.cpp
Normal file
@ -0,0 +1,372 @@
|
||||
|
||||
/** NimBLE_Server Demo:
|
||||
*
|
||||
* Demonstrates many of the available features of the NimBLE client library.
|
||||
*
|
||||
* Created: on March 24 2020
|
||||
* Author: H2zero
|
||||
*
|
||||
*/
|
||||
#include <NimBLEDevice.h>
|
||||
|
||||
extern "C" {void app_main(void);}
|
||||
|
||||
void scanEndedCB(NimBLEScanResults results);
|
||||
|
||||
static NimBLEAdvertisedDevice* advDevice;
|
||||
|
||||
static bool doConnect = false;
|
||||
static uint32_t scanTime = 0; /** 0 = scan forever */
|
||||
|
||||
|
||||
/** None of these are required as they will be handled by the library with defaults. **
|
||||
** Remove as you see fit for your needs */
|
||||
class ClientCallbacks : public NimBLEClientCallbacks {
|
||||
void onConnect(NimBLEClient* pClient) {
|
||||
printf("Connected\n");
|
||||
/** After connection we should change the parameters if we don't need fast response times.
|
||||
* These settings are 150ms interval, 0 latency, 450ms timout.
|
||||
* Timeout should be a multiple of the interval, minimum is 100ms.
|
||||
* I find a multiple of 3-5 * the interval works best for quick response/reconnect.
|
||||
* Min interval: 120 * 1.25ms = 150, Max interval: 120 * 1.25ms = 150, 0 latency, 45 * 10ms = 450ms timeout
|
||||
*/
|
||||
pClient->updateConnParams(120,120,0,45);
|
||||
};
|
||||
|
||||
void onDisconnect(NimBLEClient* pClient) {
|
||||
printf("%s Disconnected - Starting scan\n", pClient->getPeerAddress().toString().c_str());
|
||||
NimBLEDevice::getScan()->start(scanTime, scanEndedCB);
|
||||
};
|
||||
|
||||
/********************* Security handled here **********************
|
||||
****** Note: these are the same return values as defaults ********/
|
||||
uint32_t onPassKeyRequest(){
|
||||
printf("Client Passkey Request\n");
|
||||
/** return the passkey to send to the server */
|
||||
return 123456;
|
||||
};
|
||||
|
||||
bool onConfirmPIN(uint32_t pass_key){
|
||||
printf("The passkey YES/NO number: %d\n", pass_key);
|
||||
/** Return false if passkeys don't match. */
|
||||
return true;
|
||||
};
|
||||
|
||||
/** Pairing process complete, we can check the results in ble_gap_conn_desc */
|
||||
void onAuthenticationComplete(ble_gap_conn_desc* desc){
|
||||
if(!desc->sec_state.encrypted) {
|
||||
printf("Encrypt connection failed - disconnecting\n");
|
||||
/** Find the client with the connection handle provided in desc */
|
||||
NimBLEDevice::getClientByID(desc->conn_handle)->disconnect();
|
||||
return;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/** Define a class to handle the callbacks when advertisments are received */
|
||||
class AdvertisedDeviceCallbacks: public NimBLEAdvertisedDeviceCallbacks {
|
||||
|
||||
void onResult(NimBLEAdvertisedDevice* advertisedDevice) {
|
||||
printf("Advertised Device found: %s\n", advertisedDevice->toString().c_str());
|
||||
if(advertisedDevice->isAdvertisingService(NimBLEUUID("DEAD")))
|
||||
{
|
||||
printf("Found Our Service\n");
|
||||
/** stop scan before connecting */
|
||||
NimBLEDevice::getScan()->stop();
|
||||
/** Save the device reference in a global for the client to use*/
|
||||
advDevice = advertisedDevice;
|
||||
/** Ready to connect now */
|
||||
doConnect = true;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/** Notification / Indication receiving handler callback */
|
||||
void notifyCB(NimBLERemoteCharacteristic* pRemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify){
|
||||
std::string str = (isNotify == true) ? "Notification" : "Indication";
|
||||
str += " from ";
|
||||
str += pRemoteCharacteristic->getRemoteService()->getClient()->getPeerAddress().toString();
|
||||
str += ": Service = " + pRemoteCharacteristic->getRemoteService()->getUUID().toString();
|
||||
str += ", Characteristic = " + pRemoteCharacteristic->getUUID().toString();
|
||||
str += ", Value = " + std::string((char*)pData, length);
|
||||
printf("%s\n", str.c_str());
|
||||
}
|
||||
|
||||
/** Callback to process the results of the last scan or restart it */
|
||||
void scanEndedCB(NimBLEScanResults results){
|
||||
printf("Scan Ended\n");
|
||||
}
|
||||
|
||||
|
||||
/** Create a single global instance of the callback class to be used by all clients */
|
||||
static ClientCallbacks clientCB;
|
||||
|
||||
|
||||
/** Handles the provisioning of clients and connects / interfaces with the server */
|
||||
bool connectToServer() {
|
||||
NimBLEClient* pClient = nullptr;
|
||||
|
||||
/** Check if we have a client we should reuse first **/
|
||||
if(NimBLEDevice::getClientListSize()) {
|
||||
/** Special case when we already know this device, we send false as the
|
||||
* second argument in connect() to prevent refreshing the service database.
|
||||
* This saves considerable time and power.
|
||||
*/
|
||||
pClient = NimBLEDevice::getClientByPeerAddress(advDevice->getAddress());
|
||||
if(pClient){
|
||||
if(!pClient->connect(advDevice, false)) {
|
||||
printf("Reconnect failed\n");
|
||||
return false;
|
||||
}
|
||||
printf("Reconnected client\n");
|
||||
}
|
||||
/** We don't already have a client that knows this device,
|
||||
* we will check for a client that is disconnected that we can use.
|
||||
*/
|
||||
else {
|
||||
pClient = NimBLEDevice::getDisconnectedClient();
|
||||
}
|
||||
}
|
||||
|
||||
/** No client to reuse? Create a new one. */
|
||||
if(!pClient) {
|
||||
if(NimBLEDevice::getClientListSize() >= NIMBLE_MAX_CONNECTIONS) {
|
||||
printf("Max clients reached - no more connections available\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
pClient = NimBLEDevice::createClient();
|
||||
|
||||
printf("New client created\n");
|
||||
|
||||
pClient->setClientCallbacks(&clientCB, false);
|
||||
/** Set initial connection parameters: These settings are 15ms interval, 0 latency, 120ms timout.
|
||||
* These settings are safe for 3 clients to connect reliably, can go faster if you have less
|
||||
* connections. Timeout should be a multiple of the interval, minimum is 100ms.
|
||||
* Min interval: 12 * 1.25ms = 15, Max interval: 12 * 1.25ms = 15, 0 latency, 12 * 10ms = 120ms timeout
|
||||
*/
|
||||
pClient->setConnectionParams(6,6,0,15);
|
||||
/** Set how long we are willing to wait for the connection to complete (seconds), default is 30. */
|
||||
pClient->setConnectTimeout(5);
|
||||
|
||||
|
||||
if (!pClient->connect(advDevice)) {
|
||||
/** Created a client but failed to connect, don't need to keep it as it has no data */
|
||||
NimBLEDevice::deleteClient(pClient);
|
||||
printf("Failed to connect, deleted client\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(!pClient->isConnected()) {
|
||||
if (!pClient->connect(advDevice)) {
|
||||
printf("Failed to connect\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
printf("Connected to: %s RSSI: %d\n",
|
||||
pClient->getPeerAddress().toString().c_str(),
|
||||
pClient->getRssi());
|
||||
|
||||
/** Now we can read/write/subscribe the charateristics of the services we are interested in */
|
||||
NimBLERemoteService* pSvc = nullptr;
|
||||
NimBLERemoteCharacteristic* pChr = nullptr;
|
||||
NimBLERemoteDescriptor* pDsc = nullptr;
|
||||
|
||||
pSvc = pClient->getService("DEAD");
|
||||
if(pSvc) { /** make sure it's not null */
|
||||
pChr = pSvc->getCharacteristic("BEEF");
|
||||
}
|
||||
|
||||
if(pChr) { /** make sure it's not null */
|
||||
if(pChr->canRead()) {
|
||||
printf("%s Value: %s\n",
|
||||
pChr->getUUID().toString().c_str(),
|
||||
pChr->readValue().c_str());
|
||||
}
|
||||
|
||||
if(pChr->canWrite()) {
|
||||
if(pChr->writeValue("Tasty")) {
|
||||
printf("Wrote new value to: %s\n", pChr->getUUID().toString().c_str());
|
||||
}
|
||||
else {
|
||||
/** Disconnect if write failed */
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
|
||||
if(pChr->canRead()) {
|
||||
printf("The value of: %s is now: %s\n",
|
||||
pChr->getUUID().toString().c_str(),
|
||||
pChr->readValue().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
/** registerForNotify() has been deprecated and replaced with subscribe() / unsubscribe().
|
||||
* Subscribe parameter defaults are: notifications=true, notifyCallback=nullptr, response=false.
|
||||
* Unsubscribe parameter defaults are: response=false.
|
||||
*/
|
||||
if(pChr->canNotify()) {
|
||||
//if(!pChr->registerForNotify(notifyCB)) {
|
||||
if(!pChr->subscribe(true, notifyCB)) {
|
||||
/** Disconnect if subscribe failed */
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if(pChr->canIndicate()) {
|
||||
/** Send false as first argument to subscribe to indications instead of notifications */
|
||||
//if(!pChr->registerForNotify(notifyCB, false)) {
|
||||
if(!pChr->subscribe(false, notifyCB)) {
|
||||
/** Disconnect if subscribe failed */
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else{
|
||||
printf("DEAD service not found.\n");
|
||||
}
|
||||
|
||||
pSvc = pClient->getService("BAAD");
|
||||
if(pSvc) { /** make sure it's not null */
|
||||
pChr = pSvc->getCharacteristic("F00D");
|
||||
}
|
||||
|
||||
if(pChr) { /** make sure it's not null */
|
||||
if(pChr->canRead()) {
|
||||
printf("%s Value: %s\n",
|
||||
pChr->getUUID().toString().c_str(),
|
||||
pChr->readValue().c_str());
|
||||
}
|
||||
|
||||
pDsc = pChr->getDescriptor(NimBLEUUID("C01D"));
|
||||
if(pDsc) { /** make sure it's not null */
|
||||
printf("Descriptor: %s Value: %s\n",
|
||||
pDsc->getUUID().toString().c_str(),
|
||||
pDsc->readValue().c_str());
|
||||
}
|
||||
|
||||
if(pChr->canWrite()) {
|
||||
if(pChr->writeValue("No tip!")) {
|
||||
printf("Wrote new value to: %s\n", pChr->getUUID().toString().c_str());
|
||||
}
|
||||
else {
|
||||
/** Disconnect if write failed */
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
|
||||
if(pChr->canRead()) {
|
||||
printf("The value of: %s is now: %s\n",
|
||||
pChr->getUUID().toString().c_str(),
|
||||
pChr->readValue().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
/** registerForNotify() has been deprecated and replaced with subscribe() / unsubscribe().
|
||||
* Subscribe parameter defaults are: notifications=true, notifyCallback=nullptr, response=false.
|
||||
* Unsubscribe parameter defaults are: response=false.
|
||||
*/
|
||||
if(pChr->canNotify()) {
|
||||
//if(!pChr->registerForNotify(notifyCB)) {
|
||||
if(!pChr->subscribe(true, notifyCB)) {
|
||||
/** Disconnect if subscribe failed */
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if(pChr->canIndicate()) {
|
||||
/** Send false as first argument to subscribe to indications instead of notifications */
|
||||
//if(!pChr->registerForNotify(notifyCB, false)) {
|
||||
if(!pChr->subscribe(false, notifyCB)) {
|
||||
/** Disconnect if subscribe failed */
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else{
|
||||
printf("BAAD service not found.\n");
|
||||
}
|
||||
|
||||
printf("Done with this device!\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
void connectTask (void * parameter){
|
||||
/** Loop here until we find a device we want to connect to */
|
||||
for(;;) {
|
||||
if(doConnect) {
|
||||
doConnect = false;
|
||||
/** Found a device we want to connect to, do it now */
|
||||
if(connectToServer()) {
|
||||
printf("Success! we should now be getting notifications, scanning for more!\n");
|
||||
} else {
|
||||
printf("Failed to connect, starting scan\n");
|
||||
}
|
||||
|
||||
NimBLEDevice::getScan()->start(scanTime,scanEndedCB);
|
||||
}
|
||||
vTaskDelay(10/portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void app_main (void){
|
||||
printf("Starting NimBLE Client\n");
|
||||
/** Initialize NimBLE, no device name spcified as we are not advertising */
|
||||
NimBLEDevice::init("");
|
||||
|
||||
/** Set the IO capabilities of the device, each option will trigger a different pairing method.
|
||||
* BLE_HS_IO_KEYBOARD_ONLY - Passkey pairing
|
||||
* BLE_HS_IO_DISPLAY_YESNO - Numeric comparison pairing
|
||||
* BLE_HS_IO_NO_INPUT_OUTPUT - DEFAULT setting - just works pairing
|
||||
*/
|
||||
//NimBLEDevice::setSecurityIOCap(BLE_HS_IO_KEYBOARD_ONLY); // use passkey
|
||||
//NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_YESNO); //use numeric comparison
|
||||
|
||||
/** 2 different ways to set security - both calls achieve the same result.
|
||||
* no bonding, no man in the middle protection, secure connections.
|
||||
*
|
||||
* These are the default values, only shown here for demonstration.
|
||||
*/
|
||||
//NimBLEDevice::setSecurityAuth(false, false, true);
|
||||
NimBLEDevice::setSecurityAuth(/*BLE_SM_PAIR_AUTHREQ_BOND | BLE_SM_PAIR_AUTHREQ_MITM |*/ BLE_SM_PAIR_AUTHREQ_SC);
|
||||
|
||||
/** Optional: set the transmit power, default is -3db */
|
||||
NimBLEDevice::setPower(ESP_PWR_LVL_P9); /** 12db */
|
||||
|
||||
/** Optional: set any devices you don't want to get advertisments from */
|
||||
// NimBLEDevice::addIgnored(NimBLEAddress ("aa:bb:cc:dd:ee:ff"));
|
||||
|
||||
/** create new scan */
|
||||
NimBLEScan* pScan = NimBLEDevice::getScan();
|
||||
|
||||
/** create a callback that gets called when advertisers are found */
|
||||
pScan->setAdvertisedDeviceCallbacks(new AdvertisedDeviceCallbacks());
|
||||
|
||||
/** Set scan interval (how often) and window (how long) in milliseconds */
|
||||
pScan->setInterval(400);
|
||||
pScan->setWindow(100);
|
||||
|
||||
/** Active scan will gather scan response data from advertisers
|
||||
* but will use more energy from both devices
|
||||
*/
|
||||
pScan->setActiveScan(true);
|
||||
/** Start scanning for advertisers for the scan time specified (in seconds) 0 = forever
|
||||
* Optional callback for when scanning stops.
|
||||
*/
|
||||
pScan->start(scanTime, scanEndedCB);
|
||||
|
||||
printf("Scanning for peripherals\n");
|
||||
|
||||
xTaskCreate(connectTask, "connectTask", 5000, NULL, 1, NULL);
|
||||
}
|
||||
|
@ -3,4 +3,5 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
set(SUPPORTED_TARGETS esp32)
|
||||
project(NimBLE_Server)
|
3
examples/Advanced/NimBLE_Server/Makefile
Normal file
3
examples/Advanced/NimBLE_Server/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
PROJECT_NAME := NimBLE_Server
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
4
examples/Advanced/NimBLE_Server/main/component.mk
Normal file
4
examples/Advanced/NimBLE_Server/main/component.mk
Normal file
@ -0,0 +1,4 @@
|
||||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
226
examples/Advanced/NimBLE_Server/main/main.cpp
Normal file
226
examples/Advanced/NimBLE_Server/main/main.cpp
Normal file
@ -0,0 +1,226 @@
|
||||
|
||||
/** NimBLE_Server Demo:
|
||||
*
|
||||
* Demonstrates many of the available features of the NimBLE server library.
|
||||
*
|
||||
* Created: on March 22 2020
|
||||
* Author: H2zero
|
||||
*
|
||||
*/
|
||||
#include "NimBLEDevice.h"
|
||||
#include "NimBLELog.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
extern "C" {void app_main(void);}
|
||||
|
||||
static NimBLEServer* pServer;
|
||||
|
||||
/** None of these are required as they will be handled by the library with defaults. **
|
||||
** Remove as you see fit for your needs */
|
||||
class ServerCallbacks: public NimBLEServerCallbacks {
|
||||
void onConnect(NimBLEServer* pServer) {
|
||||
printf("Client connected\n");
|
||||
NimBLEDevice::startAdvertising();
|
||||
};
|
||||
/** Alternative onConnect() method to extract details of the connection.
|
||||
* See: src/ble_gap.h for the details of the ble_gap_conn_desc struct.
|
||||
*/
|
||||
void onConnect(NimBLEServer* pServer, ble_gap_conn_desc* desc) {
|
||||
printf("Client address: %s\n", NimBLEAddress(desc->peer_ota_addr).toString().c_str());
|
||||
/** We can use the connection handle here to ask for different connection parameters.
|
||||
* Args: connection handle, min connection interval, max connection interval
|
||||
* latency, supervision timeout.
|
||||
* Units; Min/Max Intervals: 1.25 millisecond increments.
|
||||
* Latency: number of intervals allowed to skip.
|
||||
* Timeout: 10 millisecond increments, try for 3x interval time for best results.
|
||||
*/
|
||||
pServer->updateConnParams(desc->conn_handle, 24, 48, 0, 18);
|
||||
};
|
||||
void onDisconnect(NimBLEServer* pServer) {
|
||||
printf("Client disconnected - start advertising\n");
|
||||
NimBLEDevice::startAdvertising();
|
||||
};
|
||||
|
||||
/********************* Security handled here **********************
|
||||
****** Note: these are the same return values as defaults ********/
|
||||
uint32_t onPassKeyRequest(){
|
||||
printf("Server Passkey Request\n");
|
||||
/** This should return a random 6 digit number for security
|
||||
* or make your own static passkey as done here.
|
||||
*/
|
||||
return 123456;
|
||||
};
|
||||
|
||||
bool onConfirmPIN(uint32_t pass_key){
|
||||
printf("The passkey YES/NO number: %d\n", pass_key);
|
||||
/** Return false if passkeys don't match. */
|
||||
return true;
|
||||
};
|
||||
|
||||
void onAuthenticationComplete(ble_gap_conn_desc* desc){
|
||||
/** Check that encryption was successful, if not we disconnect the client */
|
||||
if(!desc->sec_state.encrypted) {
|
||||
/** NOTE: createServer returns the current server reference unless one is not already created */
|
||||
NimBLEDevice::createServer()->disconnect(desc->conn_handle);
|
||||
printf("Encrypt connection failed - disconnecting client\n");
|
||||
return;
|
||||
}
|
||||
printf("Starting BLE work!");
|
||||
};
|
||||
};
|
||||
|
||||
/** Handler class for characteristic actions */
|
||||
class CharacteristicCallbacks: public NimBLECharacteristicCallbacks {
|
||||
void onRead(NimBLECharacteristic* pCharacteristic){
|
||||
printf("%s : onRead(), value: %s\n",
|
||||
pCharacteristic->getUUID().toString().c_str(),
|
||||
pCharacteristic->getValue().c_str());
|
||||
};
|
||||
|
||||
void onWrite(NimBLECharacteristic* pCharacteristic) {
|
||||
printf("%s : onWrite(), value: %s\n",
|
||||
pCharacteristic->getUUID().toString().c_str(),
|
||||
pCharacteristic->getValue().c_str());
|
||||
};
|
||||
/** Called before notification or indication is sent,
|
||||
* the value can be changed here before sending if desired.
|
||||
*/
|
||||
void onNotify(NimBLECharacteristic* pCharacteristic) {
|
||||
printf("Sending notification to clients\n");
|
||||
};
|
||||
|
||||
|
||||
/** The status returned in status is defined in NimBLECharacteristic.h.
|
||||
* The value returned in code is the NimBLE host return code.
|
||||
*/
|
||||
void onStatus(NimBLECharacteristic* pCharacteristic, Status status, int code) {
|
||||
printf("Notification/Indication status code: %d , return code: %d, %s\n",
|
||||
status,
|
||||
code,
|
||||
NimBLEUtils::returnCodeToString(code));
|
||||
};
|
||||
};
|
||||
|
||||
/** Handler class for descriptor actions */
|
||||
class DescriptorCallbacks : public NimBLEDescriptorCallbacks {
|
||||
void onWrite(NimBLEDescriptor* pDescriptor) {
|
||||
std::string dscVal((char*)pDescriptor->getValue(), pDescriptor->getLength());
|
||||
printf("Descriptor witten value: %s\n", dscVal.c_str());
|
||||
};
|
||||
|
||||
void onRead(NimBLEDescriptor* pDescriptor) {
|
||||
printf("%s Descriptor read\n", pDescriptor->getUUID().toString().c_str());
|
||||
};;
|
||||
};
|
||||
|
||||
|
||||
/** Define callback instances globally to use for multiple Charateristics \ Descriptors */
|
||||
static DescriptorCallbacks dscCallbacks;
|
||||
static CharacteristicCallbacks chrCallbacks;
|
||||
|
||||
void notifyTask(void * parameter){
|
||||
for(;;) {
|
||||
if(pServer->getConnectedCount()) {
|
||||
NimBLEService* pSvc = pServer->getServiceByUUID("BAAD");
|
||||
if(pSvc) {
|
||||
NimBLECharacteristic* pChr = pSvc->getCharacteristic("F00D");
|
||||
if(pChr) {
|
||||
pChr->notify(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
vTaskDelay(2000/portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void app_main(void) {
|
||||
printf("Starting NimBLE Server\n");
|
||||
|
||||
/** sets device name */
|
||||
NimBLEDevice::init("NimBLE");
|
||||
|
||||
/** Set the IO capabilities of the device, each option will trigger a different pairing method.
|
||||
* BLE_HS_IO_DISPLAY_ONLY - Passkey pairing
|
||||
* BLE_HS_IO_DISPLAY_YESNO - Numeric comparison pairing
|
||||
* BLE_HS_IO_NO_INPUT_OUTPUT - DEFAULT setting - just works pairing
|
||||
*/
|
||||
//NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_ONLY); // use passkey
|
||||
//NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_YESNO); //use numeric comparison
|
||||
|
||||
/** 2 different ways to set security - both calls achieve the same result.
|
||||
* no bonding, no man in the middle protection, secure connections.
|
||||
*
|
||||
* These are the default values, only shown here for demonstration.
|
||||
*/
|
||||
//NimBLEDevice::setSecurityAuth(false, false, true);
|
||||
NimBLEDevice::setSecurityAuth(/*BLE_SM_PAIR_AUTHREQ_BOND | BLE_SM_PAIR_AUTHREQ_MITM |*/ BLE_SM_PAIR_AUTHREQ_SC);
|
||||
|
||||
pServer = NimBLEDevice::createServer();
|
||||
pServer->setCallbacks(new ServerCallbacks());
|
||||
|
||||
NimBLEService* pDeadService = pServer->createService("DEAD");
|
||||
NimBLECharacteristic* pBeefCharacteristic = pDeadService->createCharacteristic(
|
||||
"BEEF",
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE |
|
||||
/** Require a secure connection for read and write access */
|
||||
NIMBLE_PROPERTY::READ_ENC | // only allow reading if paired / encrypted
|
||||
NIMBLE_PROPERTY::WRITE_ENC // only allow writing if paired / encrypted
|
||||
);
|
||||
|
||||
pBeefCharacteristic->setValue("Burger");
|
||||
pBeefCharacteristic->setCallbacks(&chrCallbacks);
|
||||
|
||||
/** 2902 and 2904 descriptors are a special case, when createDescriptor is called with
|
||||
* either of those uuid's it will create the associated class with the correct properties
|
||||
* and sizes. However we must cast the returned reference to the correct type as the method
|
||||
* only returns a pointer to the base NimBLEDescriptor class.
|
||||
*/
|
||||
NimBLE2904* pBeef2904 = (NimBLE2904*)pBeefCharacteristic->createDescriptor("2904");
|
||||
pBeef2904->setFormat(NimBLE2904::FORMAT_UTF8);
|
||||
pBeef2904->setCallbacks(&dscCallbacks);
|
||||
|
||||
|
||||
NimBLEService* pBaadService = pServer->createService("BAAD");
|
||||
NimBLECharacteristic* pFoodCharacteristic = pBaadService->createCharacteristic(
|
||||
"F00D",
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE |
|
||||
NIMBLE_PROPERTY::NOTIFY
|
||||
);
|
||||
|
||||
pFoodCharacteristic->setValue("Fries");
|
||||
pFoodCharacteristic->setCallbacks(&chrCallbacks);
|
||||
|
||||
/** Custom descriptor: Arguments are UUID, Properties, max length in bytes of the value */
|
||||
NimBLEDescriptor* pC01Ddsc = pFoodCharacteristic->createDescriptor(
|
||||
"C01D",
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE|
|
||||
NIMBLE_PROPERTY::WRITE_ENC, // only allow writing if paired / encrypted
|
||||
20
|
||||
);
|
||||
pC01Ddsc->setValue("Send it back!");
|
||||
pC01Ddsc->setCallbacks(&dscCallbacks);
|
||||
|
||||
/** Start the services when finished creating all Characteristics and Descriptors */
|
||||
pDeadService->start();
|
||||
pBaadService->start();
|
||||
|
||||
NimBLEAdvertising* pAdvertising = NimBLEDevice::getAdvertising();
|
||||
/** Add the services to the advertisment data **/
|
||||
pAdvertising->addServiceUUID(pDeadService->getUUID());
|
||||
pAdvertising->addServiceUUID(pBaadService->getUUID());
|
||||
/** If your device is battery powered you may consider setting scan response
|
||||
* to false as it will extend battery life at the expense of less data sent.
|
||||
*/
|
||||
pAdvertising->setScanResponse(true);
|
||||
pAdvertising->start();
|
||||
|
||||
printf("Advertising Started\n");
|
||||
|
||||
xTaskCreate(notifyTask, "notifyTask", 5000, NULL, 1, NULL);
|
||||
}
|
@ -1,144 +0,0 @@
|
||||
|
||||
/**
|
||||
* NimBLE Extended Client Demo:
|
||||
*
|
||||
* Demonstrates the Bluetooth 5.x client capabilities.
|
||||
*
|
||||
* Created: on April 2 2022
|
||||
* Author: H2zero
|
||||
*/
|
||||
|
||||
#include <NimBLEDevice.h>
|
||||
|
||||
#define SERVICE_UUID "ABCD"
|
||||
#define CHARACTERISTIC_UUID "1234"
|
||||
|
||||
static const NimBLEAdvertisedDevice* advDevice;
|
||||
static bool doConnect = false;
|
||||
static uint32_t scanTimeMs = 10 * 1000; // In milliseconds, 0 = scan forever
|
||||
|
||||
/** Define the PHY's to use when connecting to peer devices, can be 1, 2, or all 3 (default).*/
|
||||
static uint8_t connectPhys = BLE_GAP_LE_PHY_CODED_MASK | BLE_GAP_LE_PHY_1M_MASK /*| BLE_GAP_LE_PHY_2M_MASK */;
|
||||
|
||||
/** Define a class to handle the callbacks for client connection events */
|
||||
class ClientCallbacks : public NimBLEClientCallbacks {
|
||||
void onConnect(NimBLEClient* pClient) override { printf("Connected\n"); };
|
||||
|
||||
void onDisconnect(NimBLEClient* pClient, int reason) override {
|
||||
printf("%s Disconnected, reason = %d - Starting scan\n", pClient->getPeerAddress().toString().c_str(), reason);
|
||||
NimBLEDevice::getScan()->start(scanTimeMs);
|
||||
}
|
||||
} clientCallbacks;
|
||||
|
||||
/** Define a class to handle the callbacks when advertisements are received */
|
||||
class scanCallbacks : public NimBLEScanCallbacks {
|
||||
void onResult(const NimBLEAdvertisedDevice* advertisedDevice) override {
|
||||
printf("Advertised Device found: %s\n", advertisedDevice->toString().c_str());
|
||||
if (advertisedDevice->isAdvertisingService(NimBLEUUID("ABCD"))) {
|
||||
printf("Found Our Service\n");
|
||||
doConnect = true;
|
||||
/** Save the device reference in a global for the client to use*/
|
||||
advDevice = advertisedDevice;
|
||||
/** stop scan before connecting */
|
||||
NimBLEDevice::getScan()->stop();
|
||||
}
|
||||
}
|
||||
|
||||
/** Callback to process the results of the completed scan or restart it */
|
||||
void onScanEnd(const NimBLEScanResults& results, int rc) override { printf("Scan Ended\n"); }
|
||||
} scanCallbacks;
|
||||
|
||||
/** Handles the provisioning of clients and connects / interfaces with the server */
|
||||
bool connectToServer() {
|
||||
NimBLEClient* pClient = nullptr;
|
||||
|
||||
pClient = NimBLEDevice::createClient();
|
||||
pClient->setClientCallbacks(&clientCallbacks, false);
|
||||
|
||||
/**
|
||||
* Set the PHY's to use for this connection. This is a bitmask that represents the PHY's:
|
||||
* * 0x01 BLE_GAP_LE_PHY_1M_MASK
|
||||
* * 0x02 BLE_GAP_LE_PHY_2M_MASK
|
||||
* * 0x04 BLE_GAP_LE_PHY_CODED_MASK
|
||||
* Combine these with OR ("|"), eg BLE_GAP_LE_PHY_1M_MASK | BLE_GAP_LE_PHY_2M_MASK | BLE_GAP_LE_PHY_CODED_MASK;
|
||||
*/
|
||||
pClient->setConnectPhy(connectPhys);
|
||||
|
||||
/** Set how long we are willing to wait for the connection to complete (milliseconds), default is 30000. */
|
||||
pClient->setConnectTimeout(10 * 1000);
|
||||
|
||||
if (!pClient->connect(advDevice)) {
|
||||
/** Created a client but failed to connect, don't need to keep it as it has no data */
|
||||
NimBLEDevice::deleteClient(pClient);
|
||||
printf("Failed to connect, deleted client\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
printf("Connected to: %s RSSI: %d\n", pClient->getPeerAddress().toString().c_str(), pClient->getRssi());
|
||||
|
||||
/** Now we can read/write/subscribe the characteristics of the services we are interested in */
|
||||
NimBLERemoteService* pSvc = nullptr;
|
||||
NimBLERemoteCharacteristic* pChr = nullptr;
|
||||
|
||||
pSvc = pClient->getService(SERVICE_UUID);
|
||||
if (pSvc) {
|
||||
pChr = pSvc->getCharacteristic(CHARACTERISTIC_UUID);
|
||||
if (pChr) {
|
||||
if (pChr->canRead()) {
|
||||
std::string value = pChr->readValue();
|
||||
printf("Characteristic value: %s\n", value.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
printf("ABCD service not found.\n");
|
||||
}
|
||||
|
||||
NimBLEDevice::deleteClient(pClient);
|
||||
printf("Done with this device!\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
extern "C" void app_main(void) {
|
||||
printf("Starting NimBLE Client\n");
|
||||
|
||||
/** Initialize NimBLE and set the device name */
|
||||
NimBLEDevice::init("NimBLE Extended Client");
|
||||
|
||||
/** Create aNimBLE Scan instance and set the callbacks for scan events */
|
||||
NimBLEScan* pScan = NimBLEDevice::getScan();
|
||||
pScan->setScanCallbacks(&scanCallbacks);
|
||||
|
||||
/** Set scan interval (how often) and window (how long) in milliseconds */
|
||||
pScan->setInterval(97);
|
||||
pScan->setWindow(67);
|
||||
|
||||
/**
|
||||
* Active scan will gather scan response data from advertisers
|
||||
* but will use more energy from both devices
|
||||
*/
|
||||
pScan->setActiveScan(true);
|
||||
|
||||
/**
|
||||
* Start scanning for advertisers for the scan time specified (in milliseconds) 0 = forever
|
||||
* Optional callback for when scanning stops.
|
||||
*/
|
||||
pScan->start(scanTimeMs);
|
||||
|
||||
printf("Scanning for peripherals\n");
|
||||
|
||||
/** Loop here until we find a device we want to connect to */
|
||||
for (;;) {
|
||||
if (doConnect) {
|
||||
if (connectToServer()) {
|
||||
printf("Success!, scanning for more!\n");
|
||||
} else {
|
||||
printf("Failed to connect, starting scan\n");
|
||||
}
|
||||
|
||||
doConnect = false;
|
||||
NimBLEDevice::getScan()->start(scanTimeMs);
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
}
|
||||
}
|
@ -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,4 +0,0 @@
|
||||
set(COMPONENT_SRCS "main.cpp")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||
|
||||
register_component()
|
@ -1,69 +0,0 @@
|
||||
/**
|
||||
* NimBLE Extended Scanner Demo:
|
||||
*
|
||||
* Demonstrates the Bluetooth 5.x scanning capabilities of the NimBLE library.
|
||||
*
|
||||
* Created: on November 28, 2024
|
||||
* Author: H2zero
|
||||
*/
|
||||
|
||||
#include <NimBLEDevice.h>
|
||||
|
||||
static uint32_t scanTimeMs = 10 * 1000; // In milliseconds, 0 = scan forever
|
||||
static NimBLEScan::Phy scanPhy = NimBLEScan::Phy::SCAN_ALL;
|
||||
|
||||
/** Define a class to handle the callbacks when advertisements are received */
|
||||
class ScanCallbacks : public NimBLEScanCallbacks {
|
||||
void onResult(const NimBLEAdvertisedDevice* advertisedDevice) {
|
||||
printf("Advertised Device found: %s\n PHY1: %d\n PHY2: %d\n",
|
||||
advertisedDevice->toString().c_str(),
|
||||
advertisedDevice->getPrimaryPhy(),
|
||||
advertisedDevice->getSecondaryPhy());
|
||||
}
|
||||
|
||||
/** Callback to process the results of the completed scan or restart it */
|
||||
void onScanEnd(const NimBLEScanResults& scanResults, int reason) {
|
||||
printf("Scan Ended, reason: %d; found %d devices\n", reason, scanResults.getCount());
|
||||
|
||||
/** Try Different PHY's */
|
||||
switch (scanPhy) {
|
||||
case NimBLEScan::Phy::SCAN_ALL:
|
||||
printf("Scanning only 1M PHY\n");
|
||||
scanPhy = NimBLEScan::Phy::SCAN_1M;
|
||||
break;
|
||||
case NimBLEScan::Phy::SCAN_1M:
|
||||
printf("Scanning only CODED PHY\n");
|
||||
scanPhy = NimBLEScan::Phy::SCAN_CODED;
|
||||
break;
|
||||
case NimBLEScan::Phy::SCAN_CODED:
|
||||
printf("Scanning all PHY's\n");
|
||||
scanPhy = NimBLEScan::Phy::SCAN_ALL;
|
||||
break;
|
||||
}
|
||||
|
||||
NimBLEScan* pScan = NimBLEDevice::getScan();
|
||||
pScan->setPhy(scanPhy);
|
||||
pScan->start(scanTimeMs);
|
||||
}
|
||||
} scanCallbacks;
|
||||
|
||||
extern "C" void app_main(void) {
|
||||
printf("Starting Extended Scanner\n");
|
||||
|
||||
/** Initialize NimBLE and set the device name */
|
||||
NimBLEDevice::init("NimBLE Extended Scanner");
|
||||
NimBLEScan* pScan = NimBLEDevice::getScan();
|
||||
|
||||
/** Set the callbacks that the scanner will call on events. */
|
||||
pScan->setScanCallbacks(&scanCallbacks);
|
||||
|
||||
/** Use active scanning to obtain scan response data from advertisers */
|
||||
pScan->setActiveScan(true);
|
||||
|
||||
/** Set the initial PHY's to scan on, default is SCAN_ALL */
|
||||
pScan->setPhy(scanPhy);
|
||||
|
||||
/** Start scanning for scanTimeMs */
|
||||
pScan->start(scanTimeMs);
|
||||
printf("Scanning for peripherals\n");
|
||||
}
|
@ -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,140 +0,0 @@
|
||||
/**
|
||||
* NimBLE Extended Server Demo:
|
||||
*
|
||||
* Demonstrates the Bluetooth 5.x extended advertising capabilities.
|
||||
*
|
||||
* This demo will advertise a long data string on the CODED and 1M Phy's and
|
||||
* starts a server allowing connection over either PHY's. It will advertise for
|
||||
* 5 seconds then sleep for 20 seconds, if a client connects it will sleep once
|
||||
* it has disconnected then repeats.
|
||||
*
|
||||
* Created: on April 2 2022
|
||||
* Author: H2zero
|
||||
*/
|
||||
|
||||
#include <NimBLEDevice.h>
|
||||
#include <esp_sleep.h>
|
||||
|
||||
#define SERVICE_UUID "ABCD"
|
||||
#define CHARACTERISTIC_UUID "1234"
|
||||
|
||||
/** Time in milliseconds to advertise */
|
||||
static uint32_t advTime = 5000;
|
||||
|
||||
/** Time to sleep between advertisements */
|
||||
static uint32_t sleepSeconds = 20;
|
||||
|
||||
/** Primary PHY used for advertising, can be one of BLE_HCI_LE_PHY_1M or BLE_HCI_LE_PHY_CODED */
|
||||
static uint8_t primaryPhy = BLE_HCI_LE_PHY_CODED;
|
||||
|
||||
/**
|
||||
* Secondary PHY used for advertising and connecting,
|
||||
* can be one of BLE_HCI_LE_PHY_1M, BLE_HCI_LE_PHY_2M or BLE_HCI_LE_PHY_CODED
|
||||
*/
|
||||
static uint8_t secondaryPhy = BLE_HCI_LE_PHY_1M;
|
||||
|
||||
/** Handler class for server events */
|
||||
class ServerCallbacks : public NimBLEServerCallbacks {
|
||||
void onConnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo) override {
|
||||
printf("Client connected:: %s\n", connInfo.getAddress().toString().c_str());
|
||||
}
|
||||
|
||||
void onDisconnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo, int reason) override {
|
||||
printf("Client disconnected - sleeping for %" PRIu32 " seconds\n", sleepSeconds);
|
||||
esp_deep_sleep_start();
|
||||
}
|
||||
} serverCallbacks;
|
||||
|
||||
/** Callback class to handle advertising events */
|
||||
class AdvertisingCallbacks : public NimBLEExtAdvertisingCallbacks {
|
||||
void onStopped(NimBLEExtAdvertising* pAdv, int reason, uint8_t instId) override {
|
||||
/* Check the reason advertising stopped, don't sleep if client is connecting */
|
||||
printf("Advertising instance %u stopped\n", instId);
|
||||
switch (reason) {
|
||||
case 0:
|
||||
printf("Client connecting\n");
|
||||
return;
|
||||
case BLE_HS_ETIMEOUT:
|
||||
printf("Time expired - sleeping for %" PRIu32 " seconds\n", sleepSeconds);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
esp_deep_sleep_start();
|
||||
}
|
||||
} advertisingCallbacks;
|
||||
|
||||
extern "C"
|
||||
void app_main(void) {
|
||||
/** Initialize NimBLE and set the device name */
|
||||
NimBLEDevice::init("Extended advertiser");
|
||||
|
||||
/** Create the server and add the services/characteristics/descriptors */
|
||||
NimBLEServer* pServer = NimBLEDevice::createServer();
|
||||
pServer->setCallbacks(&serverCallbacks);
|
||||
|
||||
NimBLEService* pService = pServer->createService(SERVICE_UUID);
|
||||
NimBLECharacteristic* pCharacteristic =
|
||||
pService->createCharacteristic(CHARACTERISTIC_UUID,
|
||||
NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::NOTIFY);
|
||||
|
||||
pCharacteristic->setValue("Hello World");
|
||||
|
||||
/** Start the service */
|
||||
pService->start();
|
||||
|
||||
/**
|
||||
* Create an extended advertisement with the instance ID 0 and set the PHY's.
|
||||
* Multiple instances can be added as long as the instance ID is incremented.
|
||||
*/
|
||||
NimBLEExtAdvertisement extAdv(primaryPhy, secondaryPhy);
|
||||
|
||||
/** Set the advertisement as connectable */
|
||||
extAdv.setConnectable(true);
|
||||
|
||||
/** As per Bluetooth specification, extended advertising cannot be both scannable and connectable */
|
||||
extAdv.setScannable(false); // The default is false, set here for demonstration.
|
||||
|
||||
/** Extended advertising allows for 251 bytes (minus header bytes ~20) in a single advertisement or up to 1650 if chained */
|
||||
extAdv.setServiceData(NimBLEUUID(SERVICE_UUID),
|
||||
std::string("Extended Advertising Demo.\r\n"
|
||||
"Extended advertising allows for "
|
||||
"251 bytes of data in a single advertisement,\r\n"
|
||||
"or up to 1650 bytes with chaining.\r\n"
|
||||
"This example message is 226 bytes long "
|
||||
"and is using CODED_PHY for long range."));
|
||||
|
||||
extAdv.setCompleteServices16({NimBLEUUID(SERVICE_UUID)});
|
||||
extAdv.setName("Extended advertiser");
|
||||
|
||||
/** When extended advertising is enabled `NimBLEDevice::getAdvertising` returns a pointer to `NimBLEExtAdvertising */
|
||||
NimBLEExtAdvertising* pAdvertising = NimBLEDevice::getAdvertising();
|
||||
|
||||
/** Set the callbacks for advertising events */
|
||||
pAdvertising->setCallbacks(&advertisingCallbacks);
|
||||
|
||||
/**
|
||||
* NimBLEExtAdvertising::setInstanceData takes the instance ID and
|
||||
* a reference to a `NimBLEExtAdvertisement` object. This sets the data
|
||||
* that will be advertised for this instance ID, returns true if successful.
|
||||
*
|
||||
* Note: It is safe to create the advertisement as a local variable if setInstanceData
|
||||
* is called before exiting the code block as the data will be copied.
|
||||
*/
|
||||
if (pAdvertising->setInstanceData(0, extAdv)) {
|
||||
/**
|
||||
* NimBLEExtAdvertising::start takes the advertisement instance ID to start
|
||||
* and a duration in milliseconds or a max number of advertisements to send (or both).
|
||||
*/
|
||||
if (pAdvertising->start(0, advTime)) {
|
||||
printf("Started advertising\n");
|
||||
} else {
|
||||
printf("Failed to start advertising\n");
|
||||
}
|
||||
} else {
|
||||
printf("Failed to register advertisement data\n");
|
||||
}
|
||||
|
||||
esp_sleep_enable_timer_wakeup(sleepSeconds * 1000000);
|
||||
}
|
@ -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,168 +0,0 @@
|
||||
/**
|
||||
* NimBLE Multi Advertiser Demo:
|
||||
*
|
||||
* Demonstrates the Bluetooth 5.x extended advertising capabilities.
|
||||
*
|
||||
* This demo will advertise 2 advertisements, and extended scannable instance
|
||||
* and a connectable legacy instance. They will advertise for 5 seconds then
|
||||
* sleep for 20 seconds. The extended scannable instance will use the scan
|
||||
* request callback to update it's data when a scan response is requested.
|
||||
*
|
||||
* Created: on April 9 2022
|
||||
* Author: H2zero
|
||||
*/
|
||||
|
||||
#include <NimBLEDevice.h>
|
||||
#include <esp_sleep.h>
|
||||
|
||||
#define SERVICE_UUID "ABCD"
|
||||
#define CHARACTERISTIC_UUID "1234"
|
||||
|
||||
/** Time in milliseconds to advertise */
|
||||
static uint32_t advTime = 5000;
|
||||
|
||||
/** Time to sleep between advertisements */
|
||||
static uint32_t sleepTime = 20;
|
||||
|
||||
/** Primary PHY used for advertising, can be one of BLE_HCI_LE_PHY_1M or BLE_HCI_LE_PHY_CODED */
|
||||
static uint8_t primaryPhy = BLE_HCI_LE_PHY_CODED;
|
||||
|
||||
/**
|
||||
* Secondary PHY used for advertising and connecting,
|
||||
* can be one of BLE_HCI_LE_PHY_1M, BLE_HCI_LE_PHY_2M or BLE_HCI_LE_PHY_CODED
|
||||
*/
|
||||
static uint8_t secondaryPhy = BLE_HCI_LE_PHY_1M;
|
||||
|
||||
/** Handler class for server events */
|
||||
class ServerCallbacks : public NimBLEServerCallbacks {
|
||||
void onConnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo) override {
|
||||
printf("Client connected: %s\n", connInfo.getAddress().toString().c_str());
|
||||
}
|
||||
|
||||
void onDisconnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo, int reason) override {
|
||||
printf("Client disconnected\n");
|
||||
// if still advertising we won't sleep yet.
|
||||
if (!pServer->getAdvertising()->isAdvertising()) {
|
||||
printf("Sleeping for %" PRIu32 " seconds\n", sleepTime);
|
||||
esp_deep_sleep_start();
|
||||
}
|
||||
}
|
||||
} serverCallbacks;
|
||||
|
||||
/** Callback class to handle advertising events */
|
||||
class AdvCallbacks : public NimBLEExtAdvertisingCallbacks {
|
||||
void onStopped(NimBLEExtAdvertising* pAdv, int reason, uint8_t instId) override {
|
||||
/* Check the reason advertising stopped, don't sleep if client is connecting */
|
||||
printf("Advertising instance %u stopped\n", instId);
|
||||
switch (reason) {
|
||||
case 0:
|
||||
printf(" client connecting\n");
|
||||
return;
|
||||
case BLE_HS_ETIMEOUT:
|
||||
printf("Time expired - sleeping for %" PRIu32 " seconds\n", sleepTime);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
esp_deep_sleep_start();
|
||||
}
|
||||
|
||||
bool m_updatedSR = false;
|
||||
|
||||
void onScanRequest(NimBLEExtAdvertising* pAdv, uint8_t instId, NimBLEAddress addr) override {
|
||||
printf("Scan request for instance %u\n", instId);
|
||||
// if the data has already been updated we don't need to change it again.
|
||||
if (!m_updatedSR) {
|
||||
printf("Updating scan data\n");
|
||||
NimBLEExtAdvertisement sr;
|
||||
sr.setServiceData(NimBLEUUID(SERVICE_UUID), std::string("Hello from scan response!"));
|
||||
pAdv->setScanResponseData(instId, sr);
|
||||
m_updatedSR = true;
|
||||
}
|
||||
}
|
||||
} advCallbacks;
|
||||
|
||||
extern "C" void app_main(void) {
|
||||
/** Initialize NimBLE and set the device name */
|
||||
NimBLEDevice::init("Multi advertiser");
|
||||
|
||||
/** Create a server for our legacy advertiser */
|
||||
NimBLEServer* pServer = NimBLEDevice::createServer();
|
||||
pServer->setCallbacks(&serverCallbacks);
|
||||
|
||||
NimBLEService* pService = pServer->createService(SERVICE_UUID);
|
||||
NimBLECharacteristic* pCharacteristic =
|
||||
pService->createCharacteristic(CHARACTERISTIC_UUID,
|
||||
NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::NOTIFY);
|
||||
|
||||
pCharacteristic->setValue("Hello World");
|
||||
|
||||
/** Start the service */
|
||||
pService->start();
|
||||
|
||||
/** Create our multi advertising instances */
|
||||
|
||||
/** extended scannable instance advertising on coded and 1m PHY's. */
|
||||
NimBLEExtAdvertisement extScannable(primaryPhy, secondaryPhy);
|
||||
|
||||
/** Legacy advertising as a connectable device. */
|
||||
NimBLEExtAdvertisement legacyConnectable;
|
||||
|
||||
/** Optional scan response data. */
|
||||
NimBLEExtAdvertisement legacyScanResponse;
|
||||
|
||||
/** As per Bluetooth specification, extended advertising cannot be both scannable and connectable */
|
||||
extScannable.setScannable(true);
|
||||
extScannable.setConnectable(false);
|
||||
|
||||
/** Set the initial data */
|
||||
extScannable.setServiceData(NimBLEUUID(SERVICE_UUID), std::string("Scan me!"));
|
||||
|
||||
/** Enable the scan response callback, we will use this to update the data. */
|
||||
extScannable.enableScanRequestCallback(true);
|
||||
|
||||
/** Optional custom address for this advertisment. */
|
||||
legacyConnectable.setAddress(NimBLEAddress("DE:AD:BE:EF:BA:AD"));
|
||||
|
||||
/** Set the advertising data. */
|
||||
legacyConnectable.setName("Legacy");
|
||||
legacyConnectable.setCompleteServices16({NimBLEUUID(SERVICE_UUID)});
|
||||
|
||||
/** Set the legacy and connectable flags. */
|
||||
legacyConnectable.setLegacyAdvertising(true);
|
||||
legacyConnectable.setConnectable(true);
|
||||
|
||||
/** Put some data in the scan response if desired. */
|
||||
legacyScanResponse.setServiceData(NimBLEUUID(SERVICE_UUID), "Legacy SR");
|
||||
|
||||
/** Get the advertising ready */
|
||||
NimBLEExtAdvertising* pAdvertising = NimBLEDevice::getAdvertising();
|
||||
|
||||
/** Set the callbacks to handle advertising events */
|
||||
pAdvertising->setCallbacks(&advCallbacks);
|
||||
|
||||
/**
|
||||
* Set instance data.
|
||||
* Up to 5 instances can be used if configured in menuconfig, instance 0 is always available.
|
||||
*
|
||||
* We will set the extended scannable data on instance 0 and the legacy data on instance 1.
|
||||
* Note that the legacy scan response data needs to be set to the same instance (1).
|
||||
*/
|
||||
if (pAdvertising->setInstanceData(0, extScannable) && pAdvertising->setInstanceData(1, legacyConnectable) &&
|
||||
pAdvertising->setScanResponseData(1, legacyScanResponse)) {
|
||||
/**
|
||||
* NimBLEExtAdvertising::start takes the advertisement instance ID to start
|
||||
* and a duration in milliseconds or a max number of advertisements to send (or both).
|
||||
*/
|
||||
if (pAdvertising->start(0, advTime) && pAdvertising->start(1, advTime)) {
|
||||
printf("Started advertising\n");
|
||||
} else {
|
||||
printf("Failed to start advertising\n");
|
||||
}
|
||||
} else {
|
||||
printf("Failed to register advertisement data\n");
|
||||
}
|
||||
|
||||
esp_sleep_enable_timer_wakeup(sleepTime * 1000000);
|
||||
}
|
@ -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,6 +0,0 @@
|
||||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(Continuous_scan)
|
@ -1,46 +0,0 @@
|
||||
/**
|
||||
* Continuous Scan Example
|
||||
*
|
||||
* This example demonstrates how to continuously scan for BLE devices.
|
||||
* When devices are found the onDiscovered and onResults callbacks will be called with the device data.
|
||||
* The scan will not store the results, only the callbacks will be used
|
||||
* When the scan timeout is reached the onScanEnd callback will be called and the scan will be restarted.
|
||||
* This will clear the duplicate cache in the controller and allow the same devices to be reported again.
|
||||
*
|
||||
* Created: on March 24 2020
|
||||
* Author: H2zero
|
||||
*/
|
||||
|
||||
#include <NimBLEDevice.h>
|
||||
|
||||
static constexpr uint32_t scanTime = 30 * 1000; // 30 seconds scan time.
|
||||
|
||||
class scanCallbacks : public NimBLEScanCallbacks {
|
||||
/** Initial discovery, advertisement data only. */
|
||||
void onDiscovered(const NimBLEAdvertisedDevice* advertisedDevice) override {
|
||||
printf("Discovered Device: %s\n", advertisedDevice->toString().c_str());
|
||||
}
|
||||
|
||||
/**
|
||||
* If active scanning the result here will have the scan response data.
|
||||
* If not active scanning then this will be the same as onDiscovered.
|
||||
*/
|
||||
void onResult(const NimBLEAdvertisedDevice* advertisedDevice) override {
|
||||
printf("Device result: %s\n", advertisedDevice->toString().c_str());
|
||||
}
|
||||
|
||||
void onScanEnd(const NimBLEScanResults& results, int reason) override {
|
||||
printf("Scan ended reason = %d; restarting scan\n", reason);
|
||||
NimBLEDevice::getScan()->start(scanTime, false, true);
|
||||
}
|
||||
} scanCallbacks;
|
||||
|
||||
extern "C" void app_main() {
|
||||
NimBLEDevice::init(""); // Initialize the device, you can specify a device name if you want.
|
||||
NimBLEScan* pBLEScan = NimBLEDevice::getScan(); // Create the scan object.
|
||||
pBLEScan->setScanCallbacks(&scanCallbacks, false); // Set the callback for when devices are discovered, no duplicates.
|
||||
pBLEScan->setActiveScan(true); // Set active scanning, this will get more data from the advertiser.
|
||||
pBLEScan->setMaxResults(0); // Do not store the scan results, use callback only.
|
||||
pBLEScan->start(scanTime, false, true); // duration, not a continuation of last scan, restart to get all devices again.
|
||||
printf("Scanning...\n");
|
||||
}
|
@ -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,6 +0,0 @@
|
||||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(NimBLE_Async_Client)
|
@ -1,83 +0,0 @@
|
||||
|
||||
/**
|
||||
* NimBLE_Async_client Demo:
|
||||
*
|
||||
* Demonstrates asynchronous client operations.
|
||||
*
|
||||
* Created: on November 4, 2024
|
||||
* Author: H2zero
|
||||
*/
|
||||
|
||||
#include <NimBLEDevice.h>
|
||||
|
||||
static constexpr uint32_t scanTimeMs = 5 * 1000;
|
||||
|
||||
class ClientCallbacks : public NimBLEClientCallbacks {
|
||||
void onConnect(NimBLEClient* pClient) override {
|
||||
printf("Connected to: %s\n", pClient->getPeerAddress().toString().c_str());
|
||||
}
|
||||
|
||||
void onDisconnect(NimBLEClient* pClient, int reason) override {
|
||||
printf("%s Disconnected, reason = %d - Starting scan\n", pClient->getPeerAddress().toString().c_str(), reason);
|
||||
NimBLEDevice::getScan()->start(scanTimeMs);
|
||||
}
|
||||
} clientCallbacks;
|
||||
|
||||
class ScanCallbacks : public NimBLEScanCallbacks {
|
||||
void onResult(const NimBLEAdvertisedDevice* advertisedDevice) override {
|
||||
printf("Advertised Device found: %s\n", advertisedDevice->toString().c_str());
|
||||
if (advertisedDevice->haveName() && advertisedDevice->getName() == "NimBLE-Server") {
|
||||
printf("Found Our Device\n");
|
||||
|
||||
/** Async connections can be made directly in the scan callbacks */
|
||||
auto pClient = NimBLEDevice::getDisconnectedClient();
|
||||
if (!pClient) {
|
||||
pClient = NimBLEDevice::createClient(advertisedDevice->getAddress());
|
||||
if (!pClient) {
|
||||
printf("Failed to create client\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
pClient->setClientCallbacks(&clientCallbacks, false);
|
||||
if (!pClient->connect(true, true, false)) { // delete attributes, async connect, no MTU exchange
|
||||
NimBLEDevice::deleteClient(pClient);
|
||||
printf("Failed to connect\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void onScanEnd(const NimBLEScanResults& results, int reason) override {
|
||||
printf("Scan Ended\n");
|
||||
NimBLEDevice::getScan()->start(scanTimeMs);
|
||||
}
|
||||
} scanCallbacks;
|
||||
|
||||
extern "C" void app_main(void) {
|
||||
printf("Starting NimBLE Async Client\n");
|
||||
NimBLEDevice::init("Async-Client");
|
||||
NimBLEDevice::setPower(3); /** +3db */
|
||||
|
||||
NimBLEScan* pScan = NimBLEDevice::getScan();
|
||||
pScan->setScanCallbacks(&scanCallbacks);
|
||||
pScan->setInterval(45);
|
||||
pScan->setWindow(15);
|
||||
pScan->setActiveScan(true);
|
||||
pScan->start(scanTimeMs);
|
||||
|
||||
for (;;) {
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
auto pClients = NimBLEDevice::getConnectedClients();
|
||||
if (!pClients.size()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto& pClient : pClients) {
|
||||
printf("%s\n", pClient->toString().c_str());
|
||||
NimBLEDevice::deleteClient(pClient);
|
||||
}
|
||||
|
||||
NimBLEDevice::getScan()->start(scanTimeMs);
|
||||
}
|
||||
}
|
@ -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,304 +0,0 @@
|
||||
|
||||
/** NimBLE_Client Demo:
|
||||
*
|
||||
* Demonstrates many of the available features of the NimBLE client library.
|
||||
*
|
||||
* Created: on March 24 2020
|
||||
* Author: H2zero
|
||||
*/
|
||||
|
||||
#include <NimBLEDevice.h>
|
||||
|
||||
static const NimBLEAdvertisedDevice* advDevice;
|
||||
static bool doConnect = false;
|
||||
static uint32_t scanTimeMs = 5000; /** scan time in milliseconds, 0 = scan forever */
|
||||
|
||||
/** None of these are required as they will be handled by the library with defaults. **
|
||||
** Remove as you see fit for your needs */
|
||||
class ClientCallbacks : public NimBLEClientCallbacks {
|
||||
void onConnect(NimBLEClient* pClient) override { printf("Connected\n"); }
|
||||
|
||||
void onDisconnect(NimBLEClient* pClient, int reason) override {
|
||||
printf("%s Disconnected, reason = %d - Starting scan\n", pClient->getPeerAddress().toString().c_str(), reason);
|
||||
NimBLEDevice::getScan()->start(scanTimeMs, false, true);
|
||||
}
|
||||
|
||||
/********************* Security handled here *********************/
|
||||
void onPassKeyEntry(NimBLEConnInfo& connInfo) override {
|
||||
printf("Server Passkey Entry\n");
|
||||
/**
|
||||
* This should prompt the user to enter the passkey displayed
|
||||
* on the peer device.
|
||||
*/
|
||||
NimBLEDevice::injectPassKey(connInfo, 123456);
|
||||
}
|
||||
|
||||
void onConfirmPasskey(NimBLEConnInfo& connInfo, uint32_t pass_key) override {
|
||||
printf("The passkey YES/NO number: %" PRIu32 "\n", pass_key);
|
||||
/** Inject false if passkeys don't match. */
|
||||
NimBLEDevice::injectConfirmPasskey(connInfo, true);
|
||||
}
|
||||
|
||||
/** Pairing process complete, we can check the results in connInfo */
|
||||
void onAuthenticationComplete(NimBLEConnInfo& connInfo) override {
|
||||
if (!connInfo.isEncrypted()) {
|
||||
printf("Encrypt connection failed - disconnecting\n");
|
||||
/** Find the client with the connection handle provided in connInfo */
|
||||
NimBLEDevice::getClientByHandle(connInfo.getConnHandle())->disconnect();
|
||||
return;
|
||||
}
|
||||
}
|
||||
} clientCallbacks;
|
||||
|
||||
/** Define a class to handle the callbacks when scan events are received */
|
||||
class ScanCallbacks : public NimBLEScanCallbacks {
|
||||
void onResult(const NimBLEAdvertisedDevice* advertisedDevice) override {
|
||||
printf("Advertised Device found: %s\n", advertisedDevice->toString().c_str());
|
||||
if (advertisedDevice->isAdvertisingService(NimBLEUUID("DEAD"))) {
|
||||
printf("Found Our Service\n");
|
||||
/** stop scan before connecting */
|
||||
NimBLEDevice::getScan()->stop();
|
||||
/** Save the device reference in a global for the client to use*/
|
||||
advDevice = advertisedDevice;
|
||||
/** Ready to connect now */
|
||||
doConnect = true;
|
||||
}
|
||||
}
|
||||
|
||||
/** Callback to process the results of the completed scan or restart it */
|
||||
void onScanEnd(const NimBLEScanResults& results, int reason) override {
|
||||
printf("Scan Ended, reason: %d, device count: %d; Restarting scan\n", reason, results.getCount());
|
||||
NimBLEDevice::getScan()->start(scanTimeMs, false, true);
|
||||
}
|
||||
} scanCallbacks;
|
||||
|
||||
/** Notification / Indication receiving handler callback */
|
||||
void notifyCB(NimBLERemoteCharacteristic* pRemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify) {
|
||||
std::string str = (isNotify == true) ? "Notification" : "Indication";
|
||||
str += " from ";
|
||||
str += pRemoteCharacteristic->getClient()->getPeerAddress().toString();
|
||||
str += ": Service = " + pRemoteCharacteristic->getRemoteService()->getUUID().toString();
|
||||
str += ", Characteristic = " + pRemoteCharacteristic->getUUID().toString();
|
||||
str += ", Value = " + std::string((char*)pData, length);
|
||||
printf("%s\n", str.c_str());
|
||||
}
|
||||
|
||||
/** Handles the provisioning of clients and connects / interfaces with the server */
|
||||
bool connectToServer() {
|
||||
NimBLEClient* pClient = nullptr;
|
||||
|
||||
/** Check if we have a client we should reuse first **/
|
||||
if (NimBLEDevice::getCreatedClientCount()) {
|
||||
/**
|
||||
* Special case when we already know this device, we send false as the
|
||||
* second argument in connect() to prevent refreshing the service database.
|
||||
* This saves considerable time and power.
|
||||
*/
|
||||
pClient = NimBLEDevice::getClientByPeerAddress(advDevice->getAddress());
|
||||
if (pClient) {
|
||||
if (!pClient->connect(advDevice, false)) {
|
||||
printf("Reconnect failed\n");
|
||||
return false;
|
||||
}
|
||||
printf("Reconnected client\n");
|
||||
} else {
|
||||
/**
|
||||
* We don't already have a client that knows this device,
|
||||
* check for a client that is disconnected that we can use.
|
||||
*/
|
||||
pClient = NimBLEDevice::getDisconnectedClient();
|
||||
}
|
||||
}
|
||||
|
||||
/** No client to reuse? Create a new one. */
|
||||
if (!pClient) {
|
||||
if (NimBLEDevice::getCreatedClientCount() >= NIMBLE_MAX_CONNECTIONS) {
|
||||
printf("Max clients reached - no more connections available\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
pClient = NimBLEDevice::createClient();
|
||||
|
||||
printf("New client created\n");
|
||||
|
||||
pClient->setClientCallbacks(&clientCallbacks, false);
|
||||
/**
|
||||
* Set initial connection parameters:
|
||||
* These settings are safe for 3 clients to connect reliably, can go faster if you have less
|
||||
* connections. Timeout should be a multiple of the interval, minimum is 100ms.
|
||||
* Min interval: 12 * 1.25ms = 15, Max interval: 12 * 1.25ms = 15, 0 latency, 150 * 10ms = 1500ms timeout
|
||||
*/
|
||||
pClient->setConnectionParams(12, 12, 0, 150);
|
||||
|
||||
/** Set how long we are willing to wait for the connection to complete (milliseconds), default is 30000. */
|
||||
pClient->setConnectTimeout(5 * 1000);
|
||||
|
||||
if (!pClient->connect(advDevice)) {
|
||||
/** Created a client but failed to connect, don't need to keep it as it has no data */
|
||||
NimBLEDevice::deleteClient(pClient);
|
||||
printf("Failed to connect, deleted client\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pClient->isConnected()) {
|
||||
if (!pClient->connect(advDevice)) {
|
||||
printf("Failed to connect\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
printf("Connected to: %s RSSI: %d\n", pClient->getPeerAddress().toString().c_str(), pClient->getRssi());
|
||||
|
||||
/** Now we can read/write/subscribe the characteristics of the services we are interested in */
|
||||
NimBLERemoteService* pSvc = nullptr;
|
||||
NimBLERemoteCharacteristic* pChr = nullptr;
|
||||
NimBLERemoteDescriptor* pDsc = nullptr;
|
||||
|
||||
pSvc = pClient->getService("DEAD");
|
||||
if (pSvc) {
|
||||
pChr = pSvc->getCharacteristic("BEEF");
|
||||
}
|
||||
|
||||
if (pChr) {
|
||||
if (pChr->canRead()) {
|
||||
printf("%s Value: %s\n", pChr->getUUID().toString().c_str(), pChr->readValue().c_str());
|
||||
}
|
||||
|
||||
if (pChr->canWrite()) {
|
||||
if (pChr->writeValue("Tasty")) {
|
||||
printf("Wrote new value to: %s\n", pChr->getUUID().toString().c_str());
|
||||
} else {
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pChr->canRead()) {
|
||||
printf("The value of: %s is now: %s\n", pChr->getUUID().toString().c_str(), pChr->readValue().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if (pChr->canNotify()) {
|
||||
if (!pChr->subscribe(true, notifyCB)) {
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
} else if (pChr->canIndicate()) {
|
||||
/** Send false as first argument to subscribe to indications instead of notifications */
|
||||
if (!pChr->subscribe(false, notifyCB)) {
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
printf("DEAD service not found.\n");
|
||||
}
|
||||
|
||||
pSvc = pClient->getService("BAAD");
|
||||
if (pSvc) {
|
||||
pChr = pSvc->getCharacteristic("F00D");
|
||||
if (pChr) {
|
||||
if (pChr->canRead()) {
|
||||
printf("%s Value: %s\n", pChr->getUUID().toString().c_str(), pChr->readValue().c_str());
|
||||
}
|
||||
|
||||
pDsc = pChr->getDescriptor(NimBLEUUID("C01D"));
|
||||
if (pDsc) {
|
||||
printf("Descriptor: %s Value: %s\n", pDsc->getUUID().toString().c_str(), pDsc->readValue().c_str());
|
||||
}
|
||||
|
||||
if (pChr->canWrite()) {
|
||||
if (pChr->writeValue("No tip!")) {
|
||||
printf("Wrote new value to: %s\n", pChr->getUUID().toString().c_str());
|
||||
} else {
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pChr->canRead()) {
|
||||
printf("The value of: %s is now: %s\n", pChr->getUUID().toString().c_str(), pChr->readValue().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if (pChr->canNotify()) {
|
||||
if (!pChr->subscribe(true, notifyCB)) {
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
} else if (pChr->canIndicate()) {
|
||||
/** Send false as first argument to subscribe to indications instead of notifications */
|
||||
if (!pChr->subscribe(false, notifyCB)) {
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
printf("BAAD service not found.\n");
|
||||
}
|
||||
|
||||
printf("Done with this device!\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
extern "C" void app_main(void) {
|
||||
printf("Starting NimBLE Client\n");
|
||||
/** Initialize NimBLE and set the device name */
|
||||
NimBLEDevice::init("NimBLE-Client");
|
||||
|
||||
/**
|
||||
* Set the IO capabilities of the device, each option will trigger a different pairing method.
|
||||
* BLE_HS_IO_KEYBOARD_ONLY - Passkey pairing
|
||||
* BLE_HS_IO_DISPLAY_YESNO - Numeric comparison pairing
|
||||
* BLE_HS_IO_NO_INPUT_OUTPUT - DEFAULT setting - just works pairing
|
||||
*/
|
||||
// NimBLEDevice::setSecurityIOCap(BLE_HS_IO_KEYBOARD_ONLY); // use passkey
|
||||
// NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_YESNO); //use numeric comparison
|
||||
|
||||
/**
|
||||
* 2 different ways to set security - both calls achieve the same result.
|
||||
* no bonding, no man in the middle protection, BLE secure connections.
|
||||
* These are the default values, only shown here for demonstration.
|
||||
*/
|
||||
// NimBLEDevice::setSecurityAuth(false, false, true);
|
||||
|
||||
NimBLEDevice::setSecurityAuth(/*BLE_SM_PAIR_AUTHREQ_BOND | BLE_SM_PAIR_AUTHREQ_MITM |*/ BLE_SM_PAIR_AUTHREQ_SC);
|
||||
|
||||
/** Optional: set the transmit power */
|
||||
NimBLEDevice::setPower(3); /** 3dbm */
|
||||
NimBLEScan* pScan = NimBLEDevice::getScan();
|
||||
|
||||
/** Set the callbacks to call when scan events occur, no duplicates */
|
||||
pScan->setScanCallbacks(&scanCallbacks, false);
|
||||
|
||||
/** Set scan interval (how often) and window (how long) in milliseconds */
|
||||
pScan->setInterval(100);
|
||||
pScan->setWindow(100);
|
||||
|
||||
/**
|
||||
* Active scan will gather scan response data from advertisers
|
||||
* but will use more energy from both devices
|
||||
*/
|
||||
pScan->setActiveScan(true);
|
||||
|
||||
/** Start scanning for advertisers */
|
||||
pScan->start(scanTimeMs);
|
||||
printf("Scanning for peripherals\n");
|
||||
|
||||
/** Loop here until we find a device we want to connect to */
|
||||
for (;;) {
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
|
||||
if (doConnect) {
|
||||
doConnect = false;
|
||||
/** Found a device we want to connect to, do it now */
|
||||
if (connectToServer()) {
|
||||
printf("Success! we should now be getting notifications, scanning for more!\n");
|
||||
} else {
|
||||
printf("Failed to connect, starting scan\n");
|
||||
}
|
||||
|
||||
NimBLEDevice::getScan()->start(scanTimeMs, false, true);
|
||||
}
|
||||
}
|
||||
}
|
@ -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,218 +0,0 @@
|
||||
|
||||
/**
|
||||
* NimBLE_Server Demo:
|
||||
*
|
||||
* Demonstrates many of the available features of the NimBLE server library.
|
||||
*
|
||||
* Created: on March 22 2020
|
||||
* Author: H2zero
|
||||
*/
|
||||
|
||||
#include <NimBLEDevice.h>
|
||||
|
||||
static NimBLEServer* pServer;
|
||||
|
||||
/** None of these are required as they will be handled by the library with defaults. **
|
||||
** Remove as you see fit for your needs */
|
||||
class ServerCallbacks : public NimBLEServerCallbacks {
|
||||
void onConnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo) override {
|
||||
printf("Client address: %s\n", connInfo.getAddress().toString().c_str());
|
||||
|
||||
/**
|
||||
* We can use the connection handle here to ask for different connection parameters.
|
||||
* Args: connection handle, min connection interval, max connection interval
|
||||
* latency, supervision timeout.
|
||||
* Units; Min/Max Intervals: 1.25 millisecond increments.
|
||||
* Latency: number of intervals allowed to skip.
|
||||
* Timeout: 10 millisecond increments.
|
||||
*/
|
||||
pServer->updateConnParams(connInfo.getConnHandle(), 24, 48, 0, 18);
|
||||
}
|
||||
|
||||
void onDisconnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo, int reason) override {
|
||||
printf("Client disconnected - start advertising\n");
|
||||
NimBLEDevice::startAdvertising();
|
||||
}
|
||||
|
||||
void onMTUChange(uint16_t MTU, NimBLEConnInfo& connInfo) override {
|
||||
printf("MTU updated: %u for connection ID: %u\n", MTU, connInfo.getConnHandle());
|
||||
}
|
||||
|
||||
/********************* Security handled here *********************/
|
||||
uint32_t onPassKeyDisplay() override {
|
||||
printf("Server Passkey Display\n");
|
||||
/**
|
||||
* This should return a random 6 digit number for security
|
||||
* or make your own static passkey as done here.
|
||||
*/
|
||||
return 123456;
|
||||
}
|
||||
|
||||
void onConfirmPassKey(NimBLEConnInfo& connInfo, uint32_t pass_key) override {
|
||||
printf("The passkey YES/NO number: %" PRIu32 "\n", pass_key);
|
||||
/** Inject false if passkeys don't match. */
|
||||
NimBLEDevice::injectConfirmPasskey(connInfo, true);
|
||||
}
|
||||
|
||||
void onAuthenticationComplete(NimBLEConnInfo& connInfo) override {
|
||||
/** Check that encryption was successful, if not we disconnect the client */
|
||||
if (!connInfo.isEncrypted()) {
|
||||
NimBLEDevice::getServer()->disconnect(connInfo.getConnHandle());
|
||||
printf("Encrypt connection failed - disconnecting client\n");
|
||||
return;
|
||||
}
|
||||
|
||||
printf("Secured connection to: %s\n", connInfo.getAddress().toString().c_str());
|
||||
}
|
||||
} serverCallbacks;
|
||||
|
||||
/** Handler class for characteristic actions */
|
||||
class CharacteristicCallbacks : public NimBLECharacteristicCallbacks {
|
||||
void onRead(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo) override {
|
||||
printf("%s : onRead(), value: %s\n",
|
||||
pCharacteristic->getUUID().toString().c_str(),
|
||||
pCharacteristic->getValue().c_str());
|
||||
}
|
||||
|
||||
void onWrite(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo) override {
|
||||
printf("%s : onWrite(), value: %s\n",
|
||||
pCharacteristic->getUUID().toString().c_str(),
|
||||
pCharacteristic->getValue().c_str());
|
||||
}
|
||||
|
||||
/**
|
||||
* The value returned in code is the NimBLE host return code.
|
||||
*/
|
||||
void onStatus(NimBLECharacteristic* pCharacteristic, int code) override {
|
||||
printf("Notification/Indication return code: %d, %s\n", code, NimBLEUtils::returnCodeToString(code));
|
||||
}
|
||||
|
||||
/** Peer subscribed to notifications/indications */
|
||||
void onSubscribe(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo, uint16_t subValue) override {
|
||||
std::string str = "Client ID: ";
|
||||
str += connInfo.getConnHandle();
|
||||
str += " Address: ";
|
||||
str += connInfo.getAddress().toString();
|
||||
if (subValue == 0) {
|
||||
str += " Unsubscribed to ";
|
||||
} else if (subValue == 1) {
|
||||
str += " Subscribed to notifications for ";
|
||||
} else if (subValue == 2) {
|
||||
str += " Subscribed to indications for ";
|
||||
} else if (subValue == 3) {
|
||||
str += " Subscribed to notifications and indications for ";
|
||||
}
|
||||
str += std::string(pCharacteristic->getUUID());
|
||||
|
||||
printf("%s\n", str.c_str());
|
||||
}
|
||||
} chrCallbacks;
|
||||
|
||||
/** Handler class for descriptor actions */
|
||||
class DescriptorCallbacks : public NimBLEDescriptorCallbacks {
|
||||
void onWrite(NimBLEDescriptor* pDescriptor, NimBLEConnInfo& connInfo) override {
|
||||
std::string dscVal = pDescriptor->getValue();
|
||||
printf("Descriptor written value: %s\n", dscVal.c_str());
|
||||
}
|
||||
|
||||
void onRead(NimBLEDescriptor* pDescriptor, NimBLEConnInfo& connInfo) override {
|
||||
printf("%s Descriptor read\n", pDescriptor->getUUID().toString().c_str());
|
||||
}
|
||||
} dscCallbacks;
|
||||
|
||||
extern "C" void app_main(void) {
|
||||
printf("Starting NimBLE Server\n");
|
||||
|
||||
/** Initialize NimBLE and set the device name */
|
||||
NimBLEDevice::init("NimBLE");
|
||||
|
||||
/**
|
||||
* Set the IO capabilities of the device, each option will trigger a different pairing method.
|
||||
* BLE_HS_IO_DISPLAY_ONLY - Passkey pairing
|
||||
* BLE_HS_IO_DISPLAY_YESNO - Numeric comparison pairing
|
||||
* BLE_HS_IO_NO_INPUT_OUTPUT - DEFAULT setting - just works pairing
|
||||
*/
|
||||
// NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_ONLY); // use passkey
|
||||
// NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_YESNO); //use numeric comparison
|
||||
|
||||
/**
|
||||
* 2 different ways to set security - both calls achieve the same result.
|
||||
* no bonding, no man in the middle protection, BLE secure connections.
|
||||
*
|
||||
* These are the default values, only shown here for demonstration.
|
||||
*/
|
||||
// NimBLEDevice::setSecurityAuth(false, false, true);
|
||||
|
||||
NimBLEDevice::setSecurityAuth(/*BLE_SM_PAIR_AUTHREQ_BOND | BLE_SM_PAIR_AUTHREQ_MITM |*/ BLE_SM_PAIR_AUTHREQ_SC);
|
||||
pServer = NimBLEDevice::createServer();
|
||||
pServer->setCallbacks(&serverCallbacks);
|
||||
|
||||
NimBLEService* pDeadService = pServer->createService("DEAD");
|
||||
NimBLECharacteristic* pBeefCharacteristic =
|
||||
pDeadService->createCharacteristic("BEEF",
|
||||
NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE |
|
||||
/** Require a secure connection for read and write access */
|
||||
NIMBLE_PROPERTY::READ_ENC | // only allow reading if paired / encrypted
|
||||
NIMBLE_PROPERTY::WRITE_ENC // only allow writing if paired / encrypted
|
||||
);
|
||||
|
||||
pBeefCharacteristic->setValue("Burger");
|
||||
pBeefCharacteristic->setCallbacks(&chrCallbacks);
|
||||
|
||||
/**
|
||||
* 2902 and 2904 descriptors are a special case, when createDescriptor is called with
|
||||
* either of those uuid's it will create the associated class with the correct properties
|
||||
* and sizes. However we must cast the returned reference to the correct type as the method
|
||||
* only returns a pointer to the base NimBLEDescriptor class.
|
||||
*/
|
||||
NimBLE2904* pBeef2904 = pBeefCharacteristic->create2904();
|
||||
pBeef2904->setFormat(NimBLE2904::FORMAT_UTF8);
|
||||
pBeef2904->setCallbacks(&dscCallbacks);
|
||||
|
||||
NimBLEService* pBaadService = pServer->createService("BAAD");
|
||||
NimBLECharacteristic* pFoodCharacteristic =
|
||||
pBaadService->createCharacteristic("F00D", NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::NOTIFY);
|
||||
|
||||
pFoodCharacteristic->setValue("Fries");
|
||||
pFoodCharacteristic->setCallbacks(&chrCallbacks);
|
||||
|
||||
/** Custom descriptor: Arguments are UUID, Properties, max length of the value in bytes */
|
||||
NimBLEDescriptor* pC01Ddsc =
|
||||
pFoodCharacteristic->createDescriptor("C01D",
|
||||
NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::WRITE_ENC,
|
||||
20);
|
||||
pC01Ddsc->setValue("Send it back!");
|
||||
pC01Ddsc->setCallbacks(&dscCallbacks);
|
||||
|
||||
/** Start the services when finished creating all Characteristics and Descriptors */
|
||||
pDeadService->start();
|
||||
pBaadService->start();
|
||||
|
||||
/** Create an advertising instance and add the services to the advertised data */
|
||||
NimBLEAdvertising* pAdvertising = NimBLEDevice::getAdvertising();
|
||||
pAdvertising->setName("NimBLE-Server");
|
||||
pAdvertising->addServiceUUID(pDeadService->getUUID());
|
||||
pAdvertising->addServiceUUID(pBaadService->getUUID());
|
||||
/**
|
||||
* If your device is battery powered you may consider setting scan response
|
||||
* to false as it will extend battery life at the expense of less data sent.
|
||||
*/
|
||||
pAdvertising->enableScanResponse(true);
|
||||
pAdvertising->start();
|
||||
|
||||
printf("Advertising Started\n");
|
||||
|
||||
/** Loop here and send notifications to connected peers */
|
||||
for (;;) {
|
||||
if (pServer->getConnectedCount()) {
|
||||
NimBLEService* pSvc = pServer->getServiceByUUID("BAAD");
|
||||
if (pSvc) {
|
||||
NimBLECharacteristic* pChr = pSvc->getCharacteristic("F00D");
|
||||
if (pChr) {
|
||||
pChr->notify();
|
||||
}
|
||||
}
|
||||
}
|
||||
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
@ -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
|
@ -3,4 +3,5 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(NimBLE_extended_scan)
|
||||
set(SUPPORTED_TARGETS esp32)
|
||||
project(BLE_client)
|
3
examples/basic/BLE_client/Makefile
Normal file
3
examples/basic/BLE_client/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
PROJECT_NAME := BLE_client
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
4
examples/basic/BLE_client/main/component.mk
Normal file
4
examples/basic/BLE_client/main/component.mk
Normal file
@ -0,0 +1,4 @@
|
||||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
200
examples/basic/BLE_client/main/main.cpp
Normal file
200
examples/basic/BLE_client/main/main.cpp
Normal file
@ -0,0 +1,200 @@
|
||||
/**
|
||||
* A BLE client example that is rich in capabilities.
|
||||
* There is a lot new capabilities implemented.
|
||||
* author unknown
|
||||
* updated by chegewara
|
||||
* updated for NimBLE by H2zero
|
||||
*/
|
||||
|
||||
/** NimBLE differences highlighted in comment blocks **/
|
||||
|
||||
/*******original********
|
||||
#include "BLEDevice.h"
|
||||
***********************/
|
||||
#include "NimBLEDevice.h"
|
||||
|
||||
extern "C"{void app_main(void);}
|
||||
|
||||
// The remote service we wish to connect to.
|
||||
static BLEUUID serviceUUID("4fafc201-1fb5-459e-8fcc-c5c9c331914b");
|
||||
// The characteristic of the remote service we are interested in.
|
||||
static BLEUUID charUUID("beb5483e-36e1-4688-b7f5-ea07361b26a8");
|
||||
|
||||
static bool doConnect = false;
|
||||
static bool connected = false;
|
||||
static bool doScan = false;
|
||||
static BLERemoteCharacteristic* pRemoteCharacteristic;
|
||||
static BLEAdvertisedDevice* myDevice;
|
||||
|
||||
static void notifyCallback(
|
||||
BLERemoteCharacteristic* pBLERemoteCharacteristic,
|
||||
uint8_t* pData,
|
||||
size_t length,
|
||||
bool isNotify) {
|
||||
printf("Notify callback for characteristic %s of data length %d data: %s\n",
|
||||
pBLERemoteCharacteristic->getUUID().toString().c_str(),
|
||||
length,
|
||||
(char*)pData);
|
||||
}
|
||||
|
||||
/** None of these are required as they will be handled by the library with defaults. **
|
||||
** Remove as you see fit for your needs */
|
||||
class MyClientCallback : public BLEClientCallbacks {
|
||||
void onConnect(BLEClient* pclient) {
|
||||
}
|
||||
|
||||
void onDisconnect(BLEClient* pclient) {
|
||||
connected = false;
|
||||
printf("onDisconnect");
|
||||
}
|
||||
/***************** New - Security handled here ********************
|
||||
****** Note: these are the same return values as defaults ********/
|
||||
uint32_t onPassKeyRequest(){
|
||||
printf("Client PassKeyRequest\n");
|
||||
return 123456;
|
||||
}
|
||||
bool onConfirmPIN(uint32_t pass_key){
|
||||
printf("The passkey YES/NO number: %d\n", pass_key);
|
||||
return true;
|
||||
}
|
||||
|
||||
void onAuthenticationComplete(ble_gap_conn_desc desc){
|
||||
printf("Starting BLE work!\n");
|
||||
}
|
||||
/*******************************************************************/
|
||||
};
|
||||
|
||||
bool connectToServer() {
|
||||
printf("Forming a connection to %s\n", myDevice->getAddress().toString().c_str());
|
||||
|
||||
BLEClient* pClient = BLEDevice::createClient();
|
||||
printf(" - Created client\n");
|
||||
|
||||
pClient->setClientCallbacks(new MyClientCallback());
|
||||
|
||||
// Connect to the remove BLE Server.
|
||||
pClient->connect(myDevice); // if you pass BLEAdvertisedDevice instead of address, it will be recognized type of peer device address (public or private)
|
||||
printf(" - Connected to server\n");
|
||||
|
||||
// Obtain a reference to the service we are after in the remote BLE server.
|
||||
BLERemoteService* pRemoteService = pClient->getService(serviceUUID);
|
||||
if (pRemoteService == nullptr) {
|
||||
printf("Failed to find our service UUID: %s\n", serviceUUID.toString().c_str());
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
printf(" - Found our service\n");
|
||||
|
||||
|
||||
// Obtain a reference to the characteristic in the service of the remote BLE server.
|
||||
pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID);
|
||||
if (pRemoteCharacteristic == nullptr) {
|
||||
printf("Failed to find our characteristic UUID: %s\n", charUUID.toString().c_str());
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
printf(" - Found our characteristic\n");
|
||||
|
||||
// Read the value of the characteristic.
|
||||
if(pRemoteCharacteristic->canRead()) {
|
||||
std::string value = pRemoteCharacteristic->readValue();
|
||||
printf("The characteristic value was: %s\n", value.c_str());
|
||||
}
|
||||
/** registerForNotify() has been deprecated and replaced with subscribe() / unsubscribe().
|
||||
* Subscribe parameter defaults are: notifications=true, notifyCallback=nullptr, response=false.
|
||||
* Unsubscribe parameter defaults are: response=false.
|
||||
*/
|
||||
if(pRemoteCharacteristic->canNotify()) {
|
||||
//pRemoteCharacteristic->registerForNotify(notifyCallback);
|
||||
pRemoteCharacteristic->subscribe(true, notifyCallback);
|
||||
}
|
||||
|
||||
connected = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan for BLE servers and find the first one that advertises the service we are looking for.
|
||||
*/
|
||||
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
|
||||
/**
|
||||
* Called for each advertising BLE server.
|
||||
*/
|
||||
|
||||
/*** Only a reference to the advertised device is passed now
|
||||
void onResult(BLEAdvertisedDevice advertisedDevice) { **/
|
||||
void onResult(BLEAdvertisedDevice* advertisedDevice) {
|
||||
printf("BLE Advertised Device found: %s\n", advertisedDevice->toString().c_str());
|
||||
|
||||
// We have found a device, let us now see if it contains the service we are looking for.
|
||||
/********************************************************************************
|
||||
if (advertisedDevice.haveServiceUUID() && advertisedDevice.isAdvertisingService(serviceUUID)) {
|
||||
********************************************************************************/
|
||||
if (advertisedDevice->haveServiceUUID() && advertisedDevice->isAdvertisingService(serviceUUID)) {
|
||||
|
||||
BLEDevice::getScan()->stop();
|
||||
/*******************************************************************
|
||||
myDevice = new BLEAdvertisedDevice(advertisedDevice);
|
||||
*******************************************************************/
|
||||
myDevice = advertisedDevice; /** Just save the reference now, no need to copy the object */
|
||||
doConnect = true;
|
||||
doScan = true;
|
||||
|
||||
} // Found our server
|
||||
} // onResult
|
||||
}; // MyAdvertisedDeviceCallbacks
|
||||
|
||||
|
||||
// This is the Arduino main loop function.
|
||||
void connectTask (void * parameter){
|
||||
for(;;) {
|
||||
// If the flag "doConnect" is true then we have scanned for and found the desired
|
||||
// BLE Server with which we wish to connect. Now we connect to it. Once we are
|
||||
// connected we set the connected flag to be true.
|
||||
if (doConnect == true) {
|
||||
if (connectToServer()) {
|
||||
printf("We are now connected to the BLE Server.\n");
|
||||
} else {
|
||||
printf("We have failed to connect to the server; there is nothin more we will do.\n");
|
||||
}
|
||||
doConnect = false;
|
||||
}
|
||||
|
||||
// If we are connected to a peer BLE Server, update the characteristic each time we are reached
|
||||
// with the current time since boot.
|
||||
if (connected) {
|
||||
char buf[256];
|
||||
snprintf(buf, 256, "Time since boot: %lu", (unsigned long)(esp_timer_get_time() / 1000000ULL));
|
||||
printf("Setting new characteristic value to %s\n", buf);
|
||||
|
||||
// Set the characteristic's value to be the array of bytes that is actually a string.
|
||||
/*** Note: write value now returns true if successful, false otherwise - try again or disconnect ***/
|
||||
pRemoteCharacteristic->writeValue((uint8_t*)buf, strlen(buf), false);
|
||||
}else if(doScan){
|
||||
BLEDevice::getScan()->start(0); // this is just eample to start scan after disconnect, most likely there is better way to do it in arduino
|
||||
}
|
||||
|
||||
vTaskDelay(1000/portTICK_PERIOD_MS); // Delay a second between loops.
|
||||
}
|
||||
|
||||
vTaskDelete(NULL);
|
||||
} // End of loop
|
||||
|
||||
|
||||
void app_main(void) {
|
||||
printf("Starting BLE Client application...\n");
|
||||
BLEDevice::init("");
|
||||
|
||||
// Retrieve a Scanner and set the callback we want to use to be informed when we
|
||||
// have detected a new device. Specify that we want active scanning and start the
|
||||
// scan to run for 5 seconds.
|
||||
BLEScan* pBLEScan = BLEDevice::getScan();
|
||||
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
|
||||
pBLEScan->setInterval(1349);
|
||||
pBLEScan->setWindow(449);
|
||||
pBLEScan->setActiveScan(true);
|
||||
|
||||
xTaskCreate(connectTask, "connectTask", 5000, NULL, 1, NULL);
|
||||
pBLEScan->start(5, false);
|
||||
} // End of setup.
|
||||
|
@ -3,4 +3,5 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(NimBLE_multi_advertiser)
|
||||
set(SUPPORTED_TARGETS esp32)
|
||||
project(BLE_notify)
|
3
examples/basic/BLE_notify/Makefile
Normal file
3
examples/basic/BLE_notify/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
PROJECT_NAME := BLE_notify
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
4
examples/basic/BLE_notify/main/component.mk
Normal file
4
examples/basic/BLE_notify/main/component.mk
Normal file
@ -0,0 +1,4 @@
|
||||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
155
examples/basic/BLE_notify/main/main.cpp
Normal file
155
examples/basic/BLE_notify/main/main.cpp
Normal file
@ -0,0 +1,155 @@
|
||||
/*
|
||||
Video: https://www.youtube.com/watch?v=oCMOYS71NIU
|
||||
Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleNotify.cpp
|
||||
Ported to Arduino ESP32 by Evandro Copercini
|
||||
updated by chegewara
|
||||
Refactored back to IDF by H2zero
|
||||
|
||||
Create a BLE server that, once we receive a connection, will send periodic notifications.
|
||||
The service advertises itself as: 4fafc201-1fb5-459e-8fcc-c5c9c331914b
|
||||
And has a characteristic of: beb5483e-36e1-4688-b7f5-ea07361b26a8
|
||||
|
||||
The design of creating the BLE server is:
|
||||
1. Create a BLE Server
|
||||
2. Create a BLE Service
|
||||
3. Create a BLE Characteristic on the Service
|
||||
4. Create a BLE Descriptor on the characteristic
|
||||
5. Start the service.
|
||||
6. Start advertising.
|
||||
|
||||
A connect hander associated with the server starts a background task that performs notification
|
||||
every couple of seconds.
|
||||
*/
|
||||
|
||||
/** NimBLE differences highlighted in comment blocks **/
|
||||
|
||||
/*******original********
|
||||
#include <BLEDevice.h>
|
||||
#include <BLEServer.h>
|
||||
#include <BLEUtils.h>
|
||||
#include <BLE2902.h>
|
||||
***********************/
|
||||
#include <NimBLEDevice.h>
|
||||
|
||||
extern "C" {void app_main(void);}
|
||||
|
||||
BLEServer* pServer = NULL;
|
||||
BLECharacteristic* pCharacteristic = NULL;
|
||||
bool deviceConnected = false;
|
||||
bool oldDeviceConnected = false;
|
||||
uint32_t value = 0;
|
||||
|
||||
// See the following for generating UUIDs:
|
||||
// https://www.uuidgenerator.net/
|
||||
|
||||
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
|
||||
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
|
||||
|
||||
/** None of these are required as they will be handled by the library with defaults. **
|
||||
** Remove as you see fit for your needs */
|
||||
class MyServerCallbacks: public BLEServerCallbacks {
|
||||
void onConnect(BLEServer* pServer) {
|
||||
deviceConnected = true;
|
||||
};
|
||||
|
||||
void onDisconnect(BLEServer* pServer) {
|
||||
deviceConnected = false;
|
||||
}
|
||||
/***************** New - Security handled here ********************
|
||||
****** Note: these are the same return values as defaults ********/
|
||||
uint32_t onPassKeyRequest(){
|
||||
printf("Server PassKeyRequest\n");
|
||||
return 123456;
|
||||
}
|
||||
|
||||
bool onConfirmPIN(uint32_t pass_key){
|
||||
printf("The passkey YES/NO number: %d\n", pass_key);
|
||||
return true;
|
||||
}
|
||||
|
||||
void onAuthenticationComplete(ble_gap_conn_desc desc){
|
||||
printf("Starting BLE work!\n");
|
||||
}
|
||||
/*******************************************************************/
|
||||
};
|
||||
|
||||
void connectedTask (void * parameter){
|
||||
for(;;) {
|
||||
// notify changed value
|
||||
if (deviceConnected) {
|
||||
pCharacteristic->setValue((uint8_t*)&value, 4);
|
||||
pCharacteristic->notify();
|
||||
value++;
|
||||
vTaskDelay(100/portTICK_PERIOD_MS); // bluetooth stack will go into congestion, if too many packets are sent
|
||||
}
|
||||
// disconnecting
|
||||
if (!deviceConnected && oldDeviceConnected) {
|
||||
vTaskDelay(500/portTICK_PERIOD_MS); // give the bluetooth stack the chance to get things ready
|
||||
pServer->startAdvertising(); // restart advertising
|
||||
printf("start advertising\n");
|
||||
oldDeviceConnected = deviceConnected;
|
||||
}
|
||||
// connecting
|
||||
if (deviceConnected && !oldDeviceConnected) {
|
||||
// do stuff here on connecting
|
||||
oldDeviceConnected = deviceConnected;
|
||||
}
|
||||
|
||||
vTaskDelay(10/portTICK_PERIOD_MS); // Delay between loops to reset watchdog timer
|
||||
}
|
||||
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void app_main(void) {
|
||||
// Create the BLE Device
|
||||
BLEDevice::init("ESP32");
|
||||
|
||||
// Create the BLE Server
|
||||
pServer = BLEDevice::createServer();
|
||||
pServer->setCallbacks(new MyServerCallbacks());
|
||||
|
||||
// Create the BLE Service
|
||||
BLEService *pService = pServer->createService(SERVICE_UUID);
|
||||
|
||||
// Create a BLE Characteristic
|
||||
pCharacteristic = pService->createCharacteristic(
|
||||
CHARACTERISTIC_UUID,
|
||||
/******* Enum Type NIMBLE_PROPERTY now *******
|
||||
BLECharacteristic::PROPERTY_READ |
|
||||
BLECharacteristic::PROPERTY_WRITE |
|
||||
BLECharacteristic::PROPERTY_NOTIFY |
|
||||
BLECharacteristic::PROPERTY_INDICATE
|
||||
);
|
||||
**********************************************/
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE |
|
||||
NIMBLE_PROPERTY::NOTIFY |
|
||||
NIMBLE_PROPERTY::INDICATE
|
||||
);
|
||||
|
||||
// https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml
|
||||
// Create a BLE Descriptor
|
||||
/***************************************************
|
||||
NOTE: DO NOT create a 2902 descriptor.
|
||||
it will be created automatically if notifications
|
||||
or indications are enabled on a characteristic.
|
||||
|
||||
pCharacteristic->addDescriptor(new BLE2902());
|
||||
****************************************************/
|
||||
// Start the service
|
||||
pService->start();
|
||||
|
||||
// Start advertising
|
||||
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
|
||||
pAdvertising->addServiceUUID(SERVICE_UUID);
|
||||
pAdvertising->setScanResponse(false);
|
||||
/** This method had been removed **
|
||||
pAdvertising->setMinPreferred(0x0); // set value to 0x00 to not advertise this parameter
|
||||
**/
|
||||
|
||||
xTaskCreate(connectedTask, "connectedTask", 5000, NULL, 1, NULL);
|
||||
|
||||
BLEDevice::startAdvertising();
|
||||
printf("Waiting a client connection to notify...\n");
|
||||
}
|
@ -3,4 +3,5 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(NimBLE_extended_server)
|
||||
set(SUPPORTED_TARGETS esp32)
|
||||
project(BLE_scan)
|
3
examples/basic/BLE_scan/Makefile
Normal file
3
examples/basic/BLE_scan/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
PROJECT_NAME := BLE_scan
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
4
examples/basic/BLE_scan/main/component.mk
Normal file
4
examples/basic/BLE_scan/main/component.mk
Normal file
@ -0,0 +1,4 @@
|
||||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
52
examples/basic/BLE_scan/main/main.cpp
Normal file
52
examples/basic/BLE_scan/main/main.cpp
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleScan.cpp
|
||||
Ported to Arduino ESP32 by Evandro Copercini
|
||||
Refactored back to IDF by H2zero
|
||||
*/
|
||||
|
||||
/** NimBLE differences highlighted in comment blocks **/
|
||||
|
||||
/*******original********
|
||||
#include <BLEDevice.h>
|
||||
#include <BLEUtils.h>
|
||||
#include <BLEScan.h>
|
||||
#include <BLEAdvertisedDevice.h>
|
||||
***********************/
|
||||
|
||||
#include <NimBLEDevice.h>
|
||||
|
||||
extern "C"{void app_main(void);}
|
||||
|
||||
int scanTime = 5; //In seconds
|
||||
BLEScan* pBLEScan;
|
||||
|
||||
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
|
||||
void onResult(BLEAdvertisedDevice* advertisedDevice) {
|
||||
printf("Advertised Device: %s \n", advertisedDevice->toString().c_str());
|
||||
}
|
||||
};
|
||||
|
||||
void scanTask (void * parameter){
|
||||
for(;;) {
|
||||
// put your main code here, to run repeatedly:
|
||||
BLEScanResults foundDevices = pBLEScan->start(scanTime, false);
|
||||
printf("Devices found: %d\n", foundDevices.getCount());
|
||||
printf("Scan done!\n");
|
||||
pBLEScan->clearResults(); // delete results fromBLEScan buffer to release memory
|
||||
vTaskDelay(2000/portTICK_PERIOD_MS); // Delay a second between loops.
|
||||
}
|
||||
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void app_main(void) {
|
||||
printf("Scanning...\n");
|
||||
|
||||
BLEDevice::init("");
|
||||
pBLEScan = BLEDevice::getScan(); //create new scan
|
||||
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
|
||||
pBLEScan->setActiveScan(true); //active scan uses more power, but get results faster
|
||||
pBLEScan->setInterval(100);
|
||||
pBLEScan->setWindow(99); // less or equal setInterval value
|
||||
xTaskCreate(scanTask, "scanTask", 5000, NULL, 1, NULL);
|
||||
}
|
7
examples/basic/BLE_server/CMakeLists.txt
Normal file
7
examples/basic/BLE_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(BLE_server)
|
3
examples/basic/BLE_server/Makefile
Normal file
3
examples/basic/BLE_server/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
PROJECT_NAME := BLE_server
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
4
examples/basic/BLE_server/main/component.mk
Normal file
4
examples/basic/BLE_server/main/component.mk
Normal file
@ -0,0 +1,4 @@
|
||||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
57
examples/basic/BLE_server/main/main.cpp
Normal file
57
examples/basic/BLE_server/main/main.cpp
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleServer.cpp
|
||||
Ported to Arduino ESP32 by Evandro Copercini
|
||||
updates by chegewara
|
||||
Refactored back to IDF by H2zero
|
||||
*/
|
||||
|
||||
/** NimBLE differences highlighted in comment blocks **/
|
||||
|
||||
/*******original********
|
||||
#include <BLEDevice.h>
|
||||
#include <BLEUtils.h>
|
||||
#include <BLEServer.h>
|
||||
***********************/
|
||||
|
||||
#include <NimBLEDevice.h>
|
||||
|
||||
extern "C"{void app_main(void);}
|
||||
|
||||
// See the following for generating UUIDs:
|
||||
// https://www.uuidgenerator.net/
|
||||
|
||||
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
|
||||
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
|
||||
|
||||
void app_main(void) {
|
||||
printf("Starting BLE work!\n");
|
||||
|
||||
BLEDevice::init("Long name works now");
|
||||
BLEServer *pServer = BLEDevice::createServer();
|
||||
BLEService *pService = pServer->createService(SERVICE_UUID);
|
||||
BLECharacteristic *pCharacteristic = pService->createCharacteristic(
|
||||
CHARACTERISTIC_UUID,
|
||||
/***** Enum Type NIMBLE_PROPERTY now *****
|
||||
BLECharacteristic::PROPERTY_READ |
|
||||
BLECharacteristic::PROPERTY_WRITE
|
||||
);
|
||||
*****************************************/
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE
|
||||
);
|
||||
|
||||
pCharacteristic->setValue("Hello World says Neil");
|
||||
pService->start();
|
||||
// BLEAdvertising *pAdvertising = pServer->getAdvertising(); // this still is working for backward compatibility
|
||||
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
|
||||
pAdvertising->addServiceUUID(SERVICE_UUID);
|
||||
pAdvertising->setScanResponse(true);
|
||||
|
||||
/** These methods have been removed **
|
||||
pAdvertising->setMinPreferred(0x06); // functions that help with iPhone connections issue
|
||||
pAdvertising->setMinPreferred(0x12);
|
||||
*/
|
||||
|
||||
BLEDevice::startAdvertising();
|
||||
printf("Characteristic defined! Now you can read it in your phone!\n");
|
||||
}
|
@ -3,4 +3,5 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(NimBLE_extended_client)
|
||||
set(SUPPORTED_TARGETS esp32)
|
||||
project(BLE_uart)
|
3
examples/basic/BLE_uart/Makefile
Normal file
3
examples/basic/BLE_uart/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
PROJECT_NAME := BLE_uart
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
4
examples/basic/BLE_uart/main/component.mk
Normal file
4
examples/basic/BLE_uart/main/component.mk
Normal file
@ -0,0 +1,4 @@
|
||||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
167
examples/basic/BLE_uart/main/main.cpp
Normal file
167
examples/basic/BLE_uart/main/main.cpp
Normal file
@ -0,0 +1,167 @@
|
||||
/*
|
||||
Video: https://www.youtube.com/watch?v=oCMOYS71NIU
|
||||
Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleNotify.cpp
|
||||
Ported to Arduino ESP32 by Evandro Copercini
|
||||
Refactored back to IDF by H2zero
|
||||
|
||||
Create a BLE server that, once we receive a connection, will send periodic notifications.
|
||||
The service advertises itself as: 6E400001-B5A3-F393-E0A9-E50E24DCCA9E
|
||||
Has a characteristic of: 6E400002-B5A3-F393-E0A9-E50E24DCCA9E - used for receiving data with "WRITE"
|
||||
Has a characteristic of: 6E400003-B5A3-F393-E0A9-E50E24DCCA9E - used to send data with "NOTIFY"
|
||||
|
||||
The design of creating the BLE server is:
|
||||
1. Create a BLE Server
|
||||
2. Create a BLE Service
|
||||
3. Create a BLE Characteristic on the Service
|
||||
4. Create a BLE Descriptor on the characteristic
|
||||
5. Start the service.
|
||||
6. Start advertising.
|
||||
|
||||
In this example rxValue is the data received (only accessible inside that function).
|
||||
And txValue is the data to be sent, in this example just a byte incremented every second.
|
||||
*/
|
||||
|
||||
/** NimBLE differences highlighted in comment blocks **/
|
||||
|
||||
/*******original********
|
||||
#include <BLEDevice.h>
|
||||
#include <BLEServer.h>
|
||||
#include <BLEUtils.h>
|
||||
#include <BLE2902.h>
|
||||
***********************/
|
||||
#include <NimBLEDevice.h>
|
||||
|
||||
extern "C"{void app_main(void);}
|
||||
|
||||
BLEServer *pServer = NULL;
|
||||
BLECharacteristic * pTxCharacteristic;
|
||||
bool deviceConnected = false;
|
||||
bool oldDeviceConnected = false;
|
||||
uint8_t txValue = 0;
|
||||
|
||||
// See the following for generating UUIDs:
|
||||
// https://www.uuidgenerator.net/
|
||||
|
||||
#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID
|
||||
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
|
||||
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
|
||||
|
||||
|
||||
/** None of these are required as they will be handled by the library with defaults. **
|
||||
** Remove as you see fit for your needs */
|
||||
class MyServerCallbacks: public BLEServerCallbacks {
|
||||
void onConnect(BLEServer* pServer) {
|
||||
deviceConnected = true;
|
||||
};
|
||||
|
||||
void onDisconnect(BLEServer* pServer) {
|
||||
deviceConnected = false;
|
||||
}
|
||||
/***************** New - Security handled here ********************
|
||||
****** Note: these are the same return values as defaults ********/
|
||||
uint32_t onPassKeyRequest(){
|
||||
printf("Server PassKeyRequest\n");
|
||||
return 123456;
|
||||
}
|
||||
|
||||
bool onConfirmPIN(uint32_t pass_key){
|
||||
printf("The passkey YES/NO number: %d\n", pass_key);
|
||||
return true;
|
||||
}
|
||||
|
||||
void onAuthenticationComplete(ble_gap_conn_desc desc){
|
||||
printf("Starting BLE work!\n");
|
||||
}
|
||||
/*******************************************************************/
|
||||
};
|
||||
|
||||
class MyCallbacks: public BLECharacteristicCallbacks {
|
||||
void onWrite(BLECharacteristic *pCharacteristic) {
|
||||
std::string rxValue = pCharacteristic->getValue();
|
||||
|
||||
if (rxValue.length() > 0) {
|
||||
printf("*********\n");
|
||||
printf("Received Value: ");
|
||||
for (int i = 0; i < rxValue.length(); i++)
|
||||
printf("%d", rxValue[i]);
|
||||
|
||||
printf("\n*********\n");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void connectedTask (void * parameter){
|
||||
for(;;) {
|
||||
if (deviceConnected) {
|
||||
pTxCharacteristic->setValue(&txValue, 1);
|
||||
pTxCharacteristic->notify();
|
||||
txValue++;
|
||||
}
|
||||
|
||||
// disconnecting
|
||||
if (!deviceConnected && oldDeviceConnected) {
|
||||
pServer->startAdvertising(); // restart advertising
|
||||
printf("start advertising\n");
|
||||
oldDeviceConnected = deviceConnected;
|
||||
}
|
||||
// connecting
|
||||
if (deviceConnected && !oldDeviceConnected) {
|
||||
// do stuff here on connecting
|
||||
oldDeviceConnected = deviceConnected;
|
||||
}
|
||||
|
||||
vTaskDelay(10/portTICK_PERIOD_MS); // Delay between loops to reset watchdog timer
|
||||
}
|
||||
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void app_main(void) {
|
||||
// Create the BLE Device
|
||||
BLEDevice::init("UART Service");
|
||||
|
||||
// Create the BLE Server
|
||||
pServer = BLEDevice::createServer();
|
||||
pServer->setCallbacks(new MyServerCallbacks());
|
||||
|
||||
// Create the BLE Service
|
||||
BLEService *pService = pServer->createService(SERVICE_UUID);
|
||||
|
||||
// Create a BLE Characteristic
|
||||
pTxCharacteristic = pService->createCharacteristic(
|
||||
CHARACTERISTIC_UUID_TX,
|
||||
/******* Enum Type NIMBLE_PROPERTY now *******
|
||||
BLECharacteristic::PROPERTY_NOTIFY
|
||||
);
|
||||
**********************************************/
|
||||
NIMBLE_PROPERTY::NOTIFY
|
||||
);
|
||||
|
||||
/***************************************************
|
||||
NOTE: DO NOT create a 2902 descriptor
|
||||
it will be created automatically if notifications
|
||||
or indications are enabled on a characteristic.
|
||||
|
||||
pCharacteristic->addDescriptor(new BLE2902());
|
||||
****************************************************/
|
||||
|
||||
BLECharacteristic * pRxCharacteristic = pService->createCharacteristic(
|
||||
CHARACTERISTIC_UUID_RX,
|
||||
/******* Enum Type NIMBLE_PROPERTY now *******
|
||||
BLECharacteristic::PROPERTY_WRITE
|
||||
);
|
||||
*********************************************/
|
||||
NIMBLE_PROPERTY::WRITE
|
||||
);
|
||||
|
||||
pRxCharacteristic->setCallbacks(new MyCallbacks());
|
||||
|
||||
// Start the service
|
||||
pService->start();
|
||||
|
||||
xTaskCreate(connectedTask, "connectedTask", 5000, NULL, 1, NULL);
|
||||
|
||||
// Start advertising
|
||||
pServer->getAdvertising()->start();
|
||||
printf("Waiting a client connection to notify...\n");
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
## IDF Component Manager Manifest File
|
||||
version: "2.0.1"
|
||||
license: "Apache-2.0"
|
||||
description: "C++ wrapper for the NimBLE BLE stack"
|
||||
url: "https://github.com/h2zero/esp-nimble-cpp"
|
||||
repository: "https://github.com/h2zero/esp-nimble-cpp"
|
||||
maintainers:
|
||||
- Ryan Powell <ryan@nable-embedded.io>
|
||||
documentation: "https://h2zero.github.io/esp-nimble-cpp/"
|
||||
tags:
|
||||
- BLE
|
||||
- NimBLE
|
||||
dependencies:
|
||||
espressif/esp_hosted:
|
||||
version: "*"
|
||||
rules:
|
||||
- if: "target in [esp32p4]"
|
||||
espressif/esp_wifi_remote:
|
||||
version: "*"
|
||||
rules:
|
||||
- if: "target in [esp32p4]"
|
||||
idf:
|
||||
version: ">=5.3.0"
|
||||
rules:
|
||||
- if: "target in [esp32p4]"
|
23
library.json
23
library.json
@ -1,23 +0,0 @@
|
||||
{
|
||||
"name": "esp-nimble-cpp",
|
||||
"version": "2.0.1",
|
||||
"description": "C++ wrapper for the NimBLE BLE stack",
|
||||
"keywords": [
|
||||
"BLE",
|
||||
"espidf",
|
||||
"espressif",
|
||||
"esp32",
|
||||
"nimble"
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/h2zero/esp-nimble-cpp"
|
||||
},
|
||||
"authors": {
|
||||
"name": "Ryan Powell",
|
||||
"email": "ryan@nable-embedded.io",
|
||||
"url": "https://github.com/h2zero/esp-nimble-cpp",
|
||||
"maintainer": true
|
||||
}
|
||||
}
|
316
src/FreeRTOS.cpp
Normal file
316
src/FreeRTOS.cpp
Normal file
@ -0,0 +1,316 @@
|
||||
/*
|
||||
* FreeRTOS.cpp
|
||||
*
|
||||
* Created on: Feb 24, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "NimBLELog.h"
|
||||
|
||||
#include <freertos/FreeRTOS.h> // Include the base FreeRTOS definitions
|
||||
#include <freertos/task.h> // Include the task definitions
|
||||
#include <freertos/semphr.h> // Include the semaphore definitions
|
||||
#include <string>
|
||||
|
||||
static const char* LOG_TAG = "FreeRTOS";
|
||||
|
||||
|
||||
/**
|
||||
* Sleep for the specified number of milliseconds.
|
||||
* @param[in] ms The period in milliseconds for which to sleep.
|
||||
*/
|
||||
void FreeRTOS::sleep(uint32_t ms) {
|
||||
::vTaskDelay(ms / portTICK_PERIOD_MS);
|
||||
} // sleep
|
||||
|
||||
|
||||
/**
|
||||
* Start a new task.
|
||||
* @param[in] task The function pointer to the function to be run in the task.
|
||||
* @param[in] taskName A string identifier for the task.
|
||||
* @param[in] param An optional parameter to be passed to the started task.
|
||||
* @param[in] stackSize An optional paremeter supplying the size of the stack in which to run the task.
|
||||
*/
|
||||
void FreeRTOS::startTask(void task(void*), std::string taskName, void* param, uint32_t stackSize) {
|
||||
::xTaskCreate(task, taskName.data(), stackSize, param, 5, NULL);
|
||||
} // startTask
|
||||
|
||||
|
||||
/**
|
||||
* Delete the task.
|
||||
* @param[in] pTask An optional handle to the task to be deleted. If not supplied the calling task will be deleted.
|
||||
*/
|
||||
void FreeRTOS::deleteTask(TaskHandle_t pTask) {
|
||||
::vTaskDelete(pTask);
|
||||
} // deleteTask
|
||||
|
||||
|
||||
/**
|
||||
* Get the time in milliseconds since the %FreeRTOS scheduler started.
|
||||
* @return The time in milliseconds since the %FreeRTOS scheduler started.
|
||||
*/
|
||||
uint32_t FreeRTOS::getTimeSinceStart() {
|
||||
return (uint32_t) (xTaskGetTickCount() * portTICK_PERIOD_MS);
|
||||
} // getTimeSinceStart
|
||||
|
||||
|
||||
/**
|
||||
* @brief Wait for a semaphore to be released by trying to take it and
|
||||
* then releasing it again.
|
||||
* @param [in] owner A debug tag.
|
||||
* @return The value associated with the semaphore.
|
||||
*/
|
||||
uint32_t FreeRTOS::Semaphore::wait(std::string owner) {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> wait: Semaphore waiting: %s for %s", toString().c_str(), owner.c_str());
|
||||
|
||||
if (m_usePthreads) {
|
||||
pthread_mutex_lock(&m_pthread_mutex);
|
||||
} else {
|
||||
xSemaphoreTake(m_semaphore, portMAX_DELAY);
|
||||
}
|
||||
|
||||
if (m_usePthreads) {
|
||||
pthread_mutex_unlock(&m_pthread_mutex);
|
||||
} else {
|
||||
xSemaphoreGive(m_semaphore);
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< wait: Semaphore released: %s", toString().c_str());
|
||||
return m_value;
|
||||
} // wait
|
||||
|
||||
|
||||
/**
|
||||
* @brief Wait for a semaphore to be released in a given period of time by trying to take it and
|
||||
* then releasing it again. The value associated with the semaphore can be taken by value() call after return
|
||||
* @param [in] owner A debug tag.
|
||||
* @param [in] timeoutMs timeout to wait in ms.
|
||||
* @return True if we took the semaphore within timeframe.
|
||||
*/
|
||||
bool FreeRTOS::Semaphore::timedWait(std::string owner, uint32_t timeoutMs) {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> wait: Semaphore waiting: %s for %s", toString().c_str(), owner.c_str());
|
||||
|
||||
if (m_usePthreads && timeoutMs != portMAX_DELAY) {
|
||||
assert(false); // We apparently don't have a timed wait for pthreads.
|
||||
}
|
||||
|
||||
auto ret = pdTRUE;
|
||||
|
||||
if (m_usePthreads) {
|
||||
pthread_mutex_lock(&m_pthread_mutex);
|
||||
} else {
|
||||
ret = xSemaphoreTake(m_semaphore, timeoutMs);
|
||||
}
|
||||
|
||||
if (m_usePthreads) {
|
||||
pthread_mutex_unlock(&m_pthread_mutex);
|
||||
} else {
|
||||
xSemaphoreGive(m_semaphore);
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< wait: Semaphore %s released: %d", toString().c_str(), ret);
|
||||
return ret;
|
||||
} // wait
|
||||
|
||||
|
||||
/**
|
||||
* @brief Construct a semaphore, the semaphore is given when created.
|
||||
* @param [in] name A name string to provide debugging support.
|
||||
*/
|
||||
FreeRTOS::Semaphore::Semaphore(std::string name) {
|
||||
m_usePthreads = false; // Are we using pThreads or FreeRTOS?
|
||||
if (m_usePthreads) {
|
||||
pthread_mutex_init(&m_pthread_mutex, nullptr);
|
||||
} else {
|
||||
//m_semaphore = xSemaphoreCreateMutex();
|
||||
m_semaphore = xSemaphoreCreateBinary();
|
||||
xSemaphoreGive(m_semaphore);
|
||||
}
|
||||
|
||||
m_name = name;
|
||||
m_owner = std::string("<N/A>");
|
||||
m_value = 0;
|
||||
}
|
||||
|
||||
|
||||
FreeRTOS::Semaphore::~Semaphore() {
|
||||
if (m_usePthreads) {
|
||||
pthread_mutex_destroy(&m_pthread_mutex);
|
||||
} else {
|
||||
vSemaphoreDelete(m_semaphore);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Give the semaphore.
|
||||
*/
|
||||
void FreeRTOS::Semaphore::give() {
|
||||
NIMBLE_LOGD(LOG_TAG, "Semaphore giving: %s", toString().c_str());
|
||||
m_owner = std::string("<N/A>");
|
||||
|
||||
if (m_usePthreads) {
|
||||
pthread_mutex_unlock(&m_pthread_mutex);
|
||||
} else {
|
||||
xSemaphoreGive(m_semaphore);
|
||||
}
|
||||
// #if defined(ARDUINO_ARCH_ESP32) && !defined(DONT_USE_ARDUINO_BULLSHIT)
|
||||
// FreeRTOS::sleep(10);
|
||||
// #endif
|
||||
|
||||
} // Semaphore::give
|
||||
|
||||
|
||||
/**
|
||||
* @brief Give a semaphore.
|
||||
* The Semaphore is given with an associated value.
|
||||
* @param [in] value The value to associate with the semaphore.
|
||||
*/
|
||||
void FreeRTOS::Semaphore::give(uint32_t value) {
|
||||
m_value = value;
|
||||
give();
|
||||
} // give
|
||||
|
||||
|
||||
/**
|
||||
* @brief Give a semaphore from an ISR.
|
||||
*/
|
||||
void FreeRTOS::Semaphore::giveFromISR() {
|
||||
BaseType_t higherPriorityTaskWoken;
|
||||
if (m_usePthreads) {
|
||||
assert(false);
|
||||
} else {
|
||||
xSemaphoreGiveFromISR(m_semaphore, &higherPriorityTaskWoken);
|
||||
}
|
||||
} // giveFromISR
|
||||
|
||||
|
||||
/**
|
||||
* @brief Take a semaphore.
|
||||
* Take a semaphore and wait indefinitely.
|
||||
* @param [in] owner The new owner (for debugging)
|
||||
* @return True if we took the semaphore.
|
||||
*/
|
||||
bool FreeRTOS::Semaphore::take(std::string owner) {
|
||||
NIMBLE_LOGD(LOG_TAG, "Semaphore taking: %s for %s", toString().c_str(), owner.c_str());
|
||||
bool rc = false;
|
||||
if (m_usePthreads) {
|
||||
pthread_mutex_lock(&m_pthread_mutex);
|
||||
} else {
|
||||
rc = ::xSemaphoreTake(m_semaphore, portMAX_DELAY) == pdTRUE;
|
||||
}
|
||||
m_owner = owner;
|
||||
if (rc) {
|
||||
NIMBLE_LOGD(LOG_TAG, "Semaphore taken: %s", toString().c_str());
|
||||
} else {
|
||||
NIMBLE_LOGE(LOG_TAG, "Semaphore NOT taken: %s", toString().c_str());
|
||||
}
|
||||
return rc;
|
||||
} // Semaphore::take
|
||||
|
||||
|
||||
/**
|
||||
* @brief Take a semaphore.
|
||||
* Take a semaphore but return if we haven't obtained it in the given period of milliseconds.
|
||||
* @param [in] timeoutMs Timeout in milliseconds.
|
||||
* @param [in] owner The new owner (for debugging)
|
||||
* @return True if we took the semaphore.
|
||||
*/
|
||||
bool FreeRTOS::Semaphore::take(uint32_t timeoutMs, std::string owner) {
|
||||
NIMBLE_LOGD(LOG_TAG, "Semaphore taking: %s for %s", toString().c_str(), owner.c_str());
|
||||
bool rc = false;
|
||||
if (m_usePthreads) {
|
||||
assert(false); // We apparently don't have a timed wait for pthreads.
|
||||
} else {
|
||||
rc = ::xSemaphoreTake(m_semaphore, timeoutMs / portTICK_PERIOD_MS) == pdTRUE;
|
||||
}
|
||||
m_owner = owner;
|
||||
if (rc) {
|
||||
NIMBLE_LOGD(LOG_TAG, "Semaphore taken: %s", toString().c_str());
|
||||
} else {
|
||||
NIMBLE_LOGE(LOG_TAG, "Semaphore NOT taken: %s", toString().c_str());
|
||||
}
|
||||
return rc;
|
||||
} // Semaphore::take
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a string representation of the semaphore.
|
||||
* @return A string representation of the semaphore.
|
||||
*/
|
||||
std::string FreeRTOS::Semaphore::toString() {
|
||||
char hex[9];
|
||||
std::string res = "name: " + m_name + " (0x";
|
||||
snprintf(hex, sizeof(hex), "%08lx", (uint32_t)m_semaphore);
|
||||
res += hex;
|
||||
res += "), owner: " + m_owner;
|
||||
return res;
|
||||
} // toString
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the name of the semaphore.
|
||||
* @param [in] name The name of the semaphore.
|
||||
*/
|
||||
void FreeRTOS::Semaphore::setName(std::string name) {
|
||||
m_name = name;
|
||||
} // setName
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a ring buffer.
|
||||
* @param [in] length The amount of storage to allocate for the ring buffer.
|
||||
* @param [in] type The type of buffer. One of RINGBUF_TYPE_NOSPLIT, RINGBUF_TYPE_ALLOWSPLIT, RINGBUF_TYPE_BYTEBUF.
|
||||
*/
|
||||
#ifdef ESP_IDF_VERSION //Quick hack to detect if using IDF version that replaced ringbuf_type_t
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0)
|
||||
Ringbuffer::Ringbuffer(size_t length, RingbufferType_t type) {
|
||||
#else
|
||||
Ringbuffer::Ringbuffer(size_t length, ringbuf_type_t type) {
|
||||
#endif
|
||||
#else
|
||||
Ringbuffer::Ringbuffer(size_t length, ringbuf_type_t type) {
|
||||
#endif
|
||||
m_handle = ::xRingbufferCreate(length, type);
|
||||
} // Ringbuffer
|
||||
|
||||
|
||||
Ringbuffer::~Ringbuffer() {
|
||||
::vRingbufferDelete(m_handle);
|
||||
} // ~Ringbuffer
|
||||
|
||||
|
||||
/**
|
||||
* @brief Receive data from the buffer.
|
||||
* @param [out] size On return, the size of data returned.
|
||||
* @param [in] wait How long to wait.
|
||||
* @return A pointer to the storage retrieved.
|
||||
*/
|
||||
void* Ringbuffer::receive(size_t* size, TickType_t wait) {
|
||||
return ::xRingbufferReceive(m_handle, size, wait);
|
||||
} // receive
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return an item.
|
||||
* @param [in] item The item to be returned/released.
|
||||
*/
|
||||
void Ringbuffer::returnItem(void* item) {
|
||||
::vRingbufferReturnItem(m_handle, item);
|
||||
} // returnItem
|
||||
|
||||
|
||||
/**
|
||||
* @brief Send data to the buffer.
|
||||
* @param [in] data The data to place into the buffer.
|
||||
* @param [in] length The length of data to place into the buffer.
|
||||
* @param [in] wait How long to wait before giving up. The default is to wait indefinitely.
|
||||
* @return
|
||||
*/
|
||||
bool Ringbuffer::send(void* data, size_t length, TickType_t wait) {
|
||||
return ::xRingbufferSend(m_handle, data, length, wait) == pdTRUE;
|
||||
} // send
|
||||
|
||||
|
89
src/FreeRTOS.h
Normal file
89
src/FreeRTOS.h
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* FreeRTOS.h
|
||||
*
|
||||
* Created on: Feb 24, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef MAIN_FREERTOS_H_
|
||||
#define MAIN_FREERTOS_H_
|
||||
|
||||
#include <freertos/FreeRTOS.h> // Include the base FreeRTOS definitions.
|
||||
#include <freertos/task.h> // Include the task definitions.
|
||||
#include <freertos/semphr.h> // Include the semaphore definitions.
|
||||
#include <freertos/ringbuf.h> // Include the ringbuffer definitions.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <pthread.h>
|
||||
|
||||
|
||||
/**
|
||||
* @brief Interface to %FreeRTOS functions.
|
||||
*/
|
||||
class FreeRTOS {
|
||||
public:
|
||||
static void sleep(uint32_t ms);
|
||||
static void startTask(void task(void*), std::string taskName, void* param = nullptr, uint32_t stackSize = 2048);
|
||||
static void deleteTask(TaskHandle_t pTask = nullptr);
|
||||
|
||||
static uint32_t getTimeSinceStart();
|
||||
|
||||
/**
|
||||
* @brief A binary semaphore class that operates like a mutex, it is already given when constructed.
|
||||
*/
|
||||
class Semaphore {
|
||||
public:
|
||||
Semaphore(std::string owner = "<Unknown>");
|
||||
~Semaphore();
|
||||
void give();
|
||||
void give(uint32_t value);
|
||||
void giveFromISR();
|
||||
void setName(std::string name);
|
||||
bool take(std::string owner = "<Unknown>");
|
||||
bool take(uint32_t timeoutMs, std::string owner = "<Unknown>");
|
||||
std::string toString();
|
||||
bool timedWait(std::string owner = "<Unknown>", uint32_t timeoutMs = portMAX_DELAY);
|
||||
uint32_t wait(std::string owner = "<Unknown>");
|
||||
/**
|
||||
* @brief Get the value of the semaphore.
|
||||
* @return The value stored if the semaphore was given with give(value);
|
||||
*/
|
||||
uint32_t value(){ return m_value; };
|
||||
|
||||
private:
|
||||
SemaphoreHandle_t m_semaphore;
|
||||
pthread_mutex_t m_pthread_mutex;
|
||||
std::string m_name;
|
||||
std::string m_owner;
|
||||
uint32_t m_value;
|
||||
bool m_usePthreads;
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief A wrapper class for a freeRTOS ringbuffer.
|
||||
*/
|
||||
class Ringbuffer {
|
||||
public:
|
||||
#ifdef ESP_IDF_VERSION //Quick hack to detect if using IDF version that replaced ringbuf_type_t
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0)
|
||||
Ringbuffer(size_t length, RingbufferType_t type = RINGBUF_TYPE_NOSPLIT);
|
||||
#else
|
||||
Ringbuffer(size_t length, ringbuf_type_t type = RINGBUF_TYPE_NOSPLIT);
|
||||
#endif
|
||||
#else
|
||||
Ringbuffer(size_t length, ringbuf_type_t type = RINGBUF_TYPE_NOSPLIT);
|
||||
#endif
|
||||
~Ringbuffer();
|
||||
|
||||
void* receive(size_t* size, TickType_t wait = portMAX_DELAY);
|
||||
void returnItem(void* item);
|
||||
bool send(void* data, size_t length, TickType_t wait = portMAX_DELAY);
|
||||
private:
|
||||
RingbufHandle_t m_handle;
|
||||
};
|
||||
|
||||
#endif /* MAIN_FREERTOS_H_ */
|
@ -25,9 +25,9 @@
|
||||
#define HID_VERSION_1_11 (0x0111)
|
||||
|
||||
/* HID Class */
|
||||
#define BLE_HID_CLASS (3)
|
||||
#define BLE_HID_SUBCLASS_NONE (0)
|
||||
#define BLE_HID_PROTOCOL_NONE (0)
|
||||
#define HID_CLASS (3)
|
||||
#define HID_SUBCLASS_NONE (0)
|
||||
#define HID_PROTOCOL_NONE (0)
|
||||
|
||||
/* Descriptors */
|
||||
#define HID_DESCRIPTOR (33)
|
||||
@ -45,8 +45,13 @@
|
||||
/* of data as per HID Class standard */
|
||||
|
||||
/* Main items */
|
||||
#if defined(ARDUINO_ARCH_ESP32) && !defined(DONT_USE_ARDUINO_BULLSHIT)
|
||||
#define HIDINPUT(size) (0x80 | size)
|
||||
#define HIDOUTPUT(size) (0x90 | size)
|
||||
#else
|
||||
#define INPUT(size) (0x80 | size)
|
||||
#define OUTPUT(size) (0x90 | size)
|
||||
#endif
|
||||
#define FEATURE(size) (0xb0 | size)
|
||||
#define COLLECTION(size) (0xa0 | size)
|
||||
#define END_COLLECTION(size) (0xc0 | size)
|
||||
|
@ -1,74 +1,90 @@
|
||||
/*
|
||||
* Copyright 2020-2024 Ryan Powell <ryan@nable-embedded.io> and
|
||||
* esp-nimble-cpp, NimBLE-Arduino contributors.
|
||||
* NimBLE2904.cpp
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* Created: on March 13, 2020
|
||||
* Author H2zero
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Originally:
|
||||
*
|
||||
* 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.
|
||||
* BLE2904.cpp
|
||||
*
|
||||
* Created on: Dec 23, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
/*
|
||||
* See also:
|
||||
* https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.characteristic_presentation_format.xml
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
|
||||
#include "NimBLE2904.h"
|
||||
|
||||
NimBLE2904::NimBLE2904(NimBLECharacteristic* pChr)
|
||||
: NimBLEDescriptor(NimBLEUUID((uint16_t)0x2904), BLE_GATT_CHR_F_READ, sizeof(NimBLE2904Data), pChr) {
|
||||
setValue(m_data);
|
||||
} // NimBLE2904
|
||||
|
||||
NimBLE2904::NimBLE2904(NimBLECharacteristic* pCharacterisitic)
|
||||
: NimBLEDescriptor(NimBLEUUID((uint16_t) 0x2904),
|
||||
BLE_GATT_CHR_F_READ,
|
||||
sizeof(BLE2904_Data),
|
||||
pCharacterisitic)
|
||||
{
|
||||
m_data.m_format = 0;
|
||||
m_data.m_exponent = 0;
|
||||
m_data.m_namespace = 1; // 1 = Bluetooth SIG Assigned Numbers
|
||||
m_data.m_unit = 0;
|
||||
m_data.m_description = 0;
|
||||
setValue((uint8_t*) &m_data, sizeof(m_data));
|
||||
} // BLE2904
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the description.
|
||||
* @param [in] description The description value to set.
|
||||
*/
|
||||
void NimBLE2904::setDescription(uint16_t description) {
|
||||
m_data.m_description = description;
|
||||
setValue(m_data);
|
||||
} // setDescription
|
||||
setValue((uint8_t*) &m_data, sizeof(m_data));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the exponent.
|
||||
* @param [in] exponent The exponent value to set.
|
||||
*/
|
||||
void NimBLE2904::setExponent(int8_t exponent) {
|
||||
m_data.m_exponent = exponent;
|
||||
setValue(m_data);
|
||||
setValue((uint8_t*) &m_data, sizeof(m_data));
|
||||
} // setExponent
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the format.
|
||||
* @param [in] format The format value to set.
|
||||
*/
|
||||
void NimBLE2904::setFormat(uint8_t format) {
|
||||
m_data.m_format = format;
|
||||
setValue(m_data);
|
||||
setValue((uint8_t*) &m_data, sizeof(m_data));
|
||||
} // setFormat
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the namespace.
|
||||
* @param [in] namespace_value The namespace value toset.
|
||||
*/
|
||||
void NimBLE2904::setNamespace(uint8_t namespace_value) {
|
||||
m_data.m_namespace = namespace_value;
|
||||
setValue(m_data);
|
||||
setValue((uint8_t*) &m_data, sizeof(m_data));
|
||||
} // setNamespace
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the units for this value.
|
||||
* @brief Set the units for this value. It should be one of the encoded values defined here:
|
||||
* https://www.bluetooth.com/specifications/assigned-numbers/units
|
||||
* @param [in] unit The type of units of this characteristic as defined by assigned numbers.
|
||||
* @details See https://www.bluetooth.com/specifications/assigned-numbers/units
|
||||
*/
|
||||
void NimBLE2904::setUnit(uint16_t unit) {
|
||||
m_data.m_unit = unit;
|
||||
setValue(m_data);
|
||||
setValue((uint8_t*) &m_data, sizeof(m_data));
|
||||
} // setUnit
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
#endif
|
||||
|
@ -1,44 +1,48 @@
|
||||
/*
|
||||
* Copyright 2020-2024 Ryan Powell <ryan@nable-embedded.io> and
|
||||
* esp-nimble-cpp, NimBLE-Arduino contributors.
|
||||
* NimBLE2904.h
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* Created: on March 13, 2020
|
||||
* Author H2zero
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Originally:
|
||||
*
|
||||
* 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.
|
||||
* BLE2904.h
|
||||
*
|
||||
* Created on: Dec 23, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef NIMBLE_CPP_2904_H_
|
||||
#define NIMBLE_CPP_2904_H_
|
||||
#ifndef MAIN_NIMBLE2904_H_
|
||||
#define MAIN_NIMBLE2904_H_
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
|
||||
#include "NimBLEDescriptor.h"
|
||||
|
||||
struct NimBLE2904Data {
|
||||
uint8_t m_format{0};
|
||||
int8_t m_exponent{0};
|
||||
uint16_t m_unit{0x2700}; // Unitless; See https://www.bluetooth.com/specifications/assigned-numbers/units
|
||||
uint8_t m_namespace{1}; // 1 = Bluetooth SIG Assigned Numbers
|
||||
uint16_t m_description{0}; // unknown description
|
||||
struct BLE2904_Data {
|
||||
uint8_t m_format;
|
||||
int8_t m_exponent;
|
||||
uint16_t m_unit; // See https://www.bluetooth.com/specifications/assigned-numbers/units
|
||||
uint8_t m_namespace;
|
||||
uint16_t m_description;
|
||||
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
/**
|
||||
* @brief Descriptor for Characteristic Presentation Format.
|
||||
*
|
||||
* This is a convenience descriptor for the Characteristic Presentation Format which has a UUID of 0x2904.
|
||||
*
|
||||
* See also:
|
||||
* https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.characteristic_presentation_format.xml
|
||||
*/
|
||||
class NimBLE2904: public NimBLEDescriptor {
|
||||
public:
|
||||
NimBLE2904(NimBLECharacteristic* pChr = nullptr);
|
||||
NimBLE2904(NimBLECharacteristic* pCharacterisitic = nullptr);
|
||||
static const uint8_t FORMAT_BOOLEAN = 1;
|
||||
static const uint8_t FORMAT_UINT2 = 2;
|
||||
static const uint8_t FORMAT_UINT4 = 3;
|
||||
@ -66,7 +70,6 @@ class NimBLE2904 : public NimBLEDescriptor {
|
||||
static const uint8_t FORMAT_UTF8 = 25;
|
||||
static const uint8_t FORMAT_UTF16 = 26;
|
||||
static const uint8_t FORMAT_OPAQUE = 27;
|
||||
static const uint8_t FORMAT_MEDASN1 = 28;
|
||||
|
||||
void setDescription(uint16_t);
|
||||
void setExponent(int8_t exponent);
|
||||
@ -76,8 +79,9 @@ class NimBLE2904 : public NimBLEDescriptor {
|
||||
|
||||
private:
|
||||
friend class NimBLECharacteristic;
|
||||
NimBLE2904Data m_data{};
|
||||
}; // NimBLE2904
|
||||
BLE2904_Data m_data;
|
||||
}; // BLE2904
|
||||
|
||||
#endif // CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL
|
||||
#endif // NIMBLE_CPP_2904_H_
|
||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
#endif /* MAIN_NIMBLE2904_H_ */
|
||||
|
@ -1,99 +1,115 @@
|
||||
/*
|
||||
* Copyright 2020-2024 Ryan Powell <ryan@nable-embedded.io> and
|
||||
* esp-nimble-cpp, NimBLE-Arduino contributors.
|
||||
* NimBLEAddress.cpp
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* Created: on Jan 24 2020
|
||||
* Author H2zero
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Originally:
|
||||
*
|
||||
* 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.
|
||||
* BLEAddress.cpp
|
||||
*
|
||||
* Created on: Jul 2, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
# include "NimBLEAddress.h"
|
||||
# include "NimBLELog.h"
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_NIMBLE_ENABLED)
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "NimBLEAddress.h"
|
||||
#include "NimBLEUtils.h"
|
||||
#include "NimBLELog.h"
|
||||
|
||||
static const char* LOG_TAG = "NimBLEAddress";
|
||||
|
||||
/*************************************************
|
||||
* NOTE: NimBLE address bytes are in INVERSE ORDER!
|
||||
* We will accommodate that fact in these methods.
|
||||
* We will accomodate that fact in these methods.
|
||||
*************************************************/
|
||||
|
||||
/**
|
||||
* @brief Create an address from the native NimBLE representation.
|
||||
* @param [in] address The native NimBLE address.
|
||||
*/
|
||||
NimBLEAddress::NimBLEAddress(ble_addr_t address) : ble_addr_t{address} {}
|
||||
NimBLEAddress::NimBLEAddress(ble_addr_t address) {
|
||||
memcpy(m_address, address.val, 6);
|
||||
m_addrType = address.type;
|
||||
} // NimBLEAddress
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create an address from a hex string.
|
||||
* @brief Create a blank address, i.e. 00:00:00:00:00:00, type 0.
|
||||
*/
|
||||
NimBLEAddress::NimBLEAddress() {
|
||||
NimBLEAddress("");
|
||||
} // NimBLEAddress
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create an address from a hex string
|
||||
*
|
||||
* A hex string is of the format:
|
||||
* ```
|
||||
* 00:00:00:00:00:00
|
||||
* ```
|
||||
* which is 17 characters in length.
|
||||
* @param [in] addr The hex string representation of the address.
|
||||
* @param [in] type The type of the address, should be one of:
|
||||
* * BLE_ADDR_PUBLIC (0)
|
||||
* * BLE_ADDR_RANDOM (1)
|
||||
*
|
||||
* @param [in] stringAddress The hex string representation of the address.
|
||||
* @param [in] type The type of the address.
|
||||
*/
|
||||
NimBLEAddress::NimBLEAddress(const std::string& addr, uint8_t type) {
|
||||
this->type = type;
|
||||
NimBLEAddress::NimBLEAddress(const std::string &stringAddress, uint8_t type) {
|
||||
m_addrType = type;
|
||||
|
||||
if (addr.length() == BLE_DEV_ADDR_LEN) {
|
||||
std::reverse_copy(addr.data(), addr.data() + BLE_DEV_ADDR_LEN, this->val);
|
||||
if (stringAddress.length() == 0) {
|
||||
memset(m_address, 0, 6);
|
||||
return;
|
||||
}
|
||||
|
||||
if (addr.length() == 17) {
|
||||
std::string mac{addr};
|
||||
mac.erase(std::remove(mac.begin(), mac.end(), ':'), mac.end());
|
||||
uint64_t address = std::stoull(mac, nullptr, 16);
|
||||
memcpy(this->val, &address, sizeof this->val);
|
||||
if (stringAddress.length() == 6) {
|
||||
std::reverse_copy(stringAddress.data(), stringAddress.data() + 6, m_address);
|
||||
return;
|
||||
}
|
||||
|
||||
*this = NimBLEAddress{};
|
||||
NIMBLE_LOGE(LOG_TAG, "Invalid address '%s'", addr.c_str());
|
||||
if (stringAddress.length() != 17) {
|
||||
memset(m_address, 0, sizeof m_address); // "00:00:00:00:00:00" represents an invalid address
|
||||
NIMBLE_LOGD(LOG_TAG, "Invalid address '%s'", stringAddress.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
int data[6];
|
||||
if(sscanf(stringAddress.c_str(), "%x:%x:%x:%x:%x:%x", &data[5], &data[4], &data[3], &data[2], &data[1], &data[0]) != 6) {
|
||||
memset(m_address, 0, sizeof m_address); // "00:00:00:00:00:00" represents an invalid address
|
||||
NIMBLE_LOGD(LOG_TAG, "Invalid address '%s'", stringAddress.c_str());
|
||||
}
|
||||
for(size_t index = 0; index < sizeof m_address; index++) {
|
||||
m_address[index] = data[index];
|
||||
}
|
||||
} // NimBLEAddress
|
||||
|
||||
|
||||
/**
|
||||
* @brief Constructor for compatibility with bluedroid esp library using native ESP representation.
|
||||
* @param [in] address A uint8_t[6] or esp_bd_addr_t containing the address.
|
||||
* @param [in] type The type of the address should be one of:
|
||||
* * BLE_ADDR_PUBLIC (0)
|
||||
* * BLE_ADDR_RANDOM (1)
|
||||
* @param [in] type The type of the address.
|
||||
*/
|
||||
NimBLEAddress::NimBLEAddress(const uint8_t address[BLE_DEV_ADDR_LEN], uint8_t type) {
|
||||
std::reverse_copy(address, address + BLE_DEV_ADDR_LEN, this->val);
|
||||
this->type = type;
|
||||
NimBLEAddress::NimBLEAddress(uint8_t address[6], uint8_t type) {
|
||||
std::reverse_copy(address, address + sizeof m_address, m_address);
|
||||
m_addrType = type;
|
||||
} // NimBLEAddress
|
||||
|
||||
|
||||
/**
|
||||
* @brief Constructor for address using a hex value.\n
|
||||
* Use the same byte order, so use 0xa4c1385def16 for "a4:c1:38:5d:ef:16"
|
||||
* @param [in] address uint64_t containing the address.
|
||||
* @param [in] type The type of the address should be one of:
|
||||
* * BLE_ADDR_PUBLIC (0)
|
||||
* * BLE_ADDR_RANDOM (1)
|
||||
* @param [in] type The type of the address.
|
||||
*/
|
||||
NimBLEAddress::NimBLEAddress(const uint64_t &address, uint8_t type) {
|
||||
memcpy(this->val, &address, sizeof this->val);
|
||||
this->type = type;
|
||||
memcpy(m_address, &address, sizeof m_address);
|
||||
m_addrType = type;
|
||||
} // NimBLEAddress
|
||||
|
||||
|
||||
/**
|
||||
* @brief Determine if this address equals another.
|
||||
* @param [in] otherAddress The other address to compare against.
|
||||
@ -103,72 +119,34 @@ bool NimBLEAddress::equals(const NimBLEAddress& otherAddress) const {
|
||||
return *this == otherAddress;
|
||||
} // equals
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the NimBLE base struct of the address.
|
||||
* @return A read only reference to the NimBLE base struct of the address.
|
||||
* @brief Get the native representation of the address.
|
||||
* @return a pointer to the uint8_t[6] array of the address.
|
||||
*/
|
||||
const ble_addr_t* NimBLEAddress::getBase() const {
|
||||
return reinterpret_cast<const ble_addr_t*>(this);
|
||||
} // getBase
|
||||
const uint8_t *NimBLEAddress::getNative() const {
|
||||
return m_address;
|
||||
} // getNative
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the address type.
|
||||
* @return The address type.
|
||||
*/
|
||||
uint8_t NimBLEAddress::getType() const {
|
||||
return this->type;
|
||||
return m_addrType;
|
||||
} // getType
|
||||
|
||||
/**
|
||||
* @brief Get the address value.
|
||||
* @return A read only reference to the address value.
|
||||
*/
|
||||
const uint8_t* NimBLEAddress::getVal() const {
|
||||
return this->val;
|
||||
} // getVal
|
||||
|
||||
/**
|
||||
* @brief Determine if this address is a Resolvable Private Address.
|
||||
* @return True if the address is a RPA.
|
||||
*/
|
||||
bool NimBLEAddress::isRpa() const {
|
||||
return BLE_ADDR_IS_RPA(this);
|
||||
} // isRpa
|
||||
|
||||
/**
|
||||
* @brief Determine if this address is a Non-Resolvable Private Address.
|
||||
* @return True if the address is a NRPA.
|
||||
*/
|
||||
bool NimBLEAddress::isNrpa() const {
|
||||
return BLE_ADDR_IS_NRPA(this);
|
||||
} // isNrpa
|
||||
|
||||
/**
|
||||
* @brief Determine if this address is a Static Address.
|
||||
* @return True if the address is a Static Address.
|
||||
*/
|
||||
bool NimBLEAddress::isStatic() const {
|
||||
return BLE_ADDR_IS_STATIC(this);
|
||||
} // isStatic
|
||||
|
||||
/**
|
||||
* @brief Determine if this address is a Public Address.
|
||||
* @return True if the address is a Public Address.
|
||||
*/
|
||||
bool NimBLEAddress::isPublic() const {
|
||||
return this->type == BLE_ADDR_PUBLIC;
|
||||
} // isPublic
|
||||
|
||||
/**
|
||||
* @brief Determine if this address is a NULL Address.
|
||||
* @return True if the address is a NULL Address.
|
||||
*/
|
||||
bool NimBLEAddress::isNull() const {
|
||||
return *this == NimBLEAddress{};
|
||||
} // isNull
|
||||
|
||||
/**
|
||||
* @brief Convert a BLE address to a string.
|
||||
*
|
||||
* A string representation of an address is in the format:
|
||||
*
|
||||
* ```
|
||||
* xx:xx:xx:xx:xx:xx
|
||||
* ```
|
||||
*
|
||||
* @return The string representation of the address.
|
||||
* @deprecated Use std::string() operator instead.
|
||||
*/
|
||||
@ -176,57 +154,43 @@ std::string NimBLEAddress::toString() const {
|
||||
return std::string(*this);
|
||||
} // toString
|
||||
|
||||
/**
|
||||
* @brief Reverse the byte order of the address.
|
||||
* @return A reference to this address.
|
||||
*/
|
||||
const NimBLEAddress& NimBLEAddress::reverseByteOrder() {
|
||||
std::reverse(this->val, this->val + BLE_DEV_ADDR_LEN);
|
||||
return *this;
|
||||
} // reverseByteOrder
|
||||
|
||||
/**
|
||||
* @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 {
|
||||
if (this->type != rhs.type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return memcmp(rhs.val, this->val, sizeof this->val) == 0;
|
||||
return memcmp(rhs.m_address, m_address, sizeof m_address) == 0;
|
||||
} // operator ==
|
||||
|
||||
|
||||
/**
|
||||
* @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);
|
||||
} // operator !=
|
||||
|
||||
|
||||
/**
|
||||
* @brief Convenience operator to convert this address to string representation.
|
||||
* @details This allows passing NimBLEAddress to functions that accept std::string and/or it's methods as a parameter.
|
||||
* @brief Convienience operator to convert this address to string representation.
|
||||
* @details This allows passing NimBLEAddress to functions
|
||||
* that accept std::string and/or or it's methods as a parameter.
|
||||
*/
|
||||
NimBLEAddress::operator std::string() const {
|
||||
char buffer[18];
|
||||
snprintf(buffer,
|
||||
sizeof(buffer),
|
||||
"%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
this->val[5],
|
||||
this->val[4],
|
||||
this->val[3],
|
||||
this->val[2],
|
||||
this->val[1],
|
||||
this->val[0]);
|
||||
return std::string{buffer};
|
||||
snprintf(buffer, sizeof(buffer), "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
m_address[5], m_address[4], m_address[3],
|
||||
m_address[2], m_address[1], m_address[0]);
|
||||
return std::string(buffer);
|
||||
} // operator std::string
|
||||
|
||||
|
||||
/**
|
||||
* @brief 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;
|
||||
memcpy(&address, this->val, sizeof this->val);
|
||||
memcpy(&address, m_address, sizeof m_address);
|
||||
return address;
|
||||
} // operator uint64_t
|
||||
|
||||
|
@ -1,70 +1,57 @@
|
||||
/*
|
||||
* Copyright 2020-2024 Ryan Powell <ryan@nable-embedded.io> and
|
||||
* esp-nimble-cpp, NimBLE-Arduino contributors.
|
||||
* NimBLEAddress.h
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* Created: on Jan 24 2020
|
||||
* Author H2zero
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Originally:
|
||||
*
|
||||
* 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.
|
||||
* BLEAddress.h
|
||||
*
|
||||
* Created on: Jul 2, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef NIMBLE_CPP_ADDRESS_H_
|
||||
#define NIMBLE_CPP_ADDRESS_H_
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
#ifndef COMPONENTS_NIMBLEADDRESS_H_
|
||||
#define COMPONENTS_NIMBLEADDRESS_H_
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_NIMBLE_ENABLED)
|
||||
|
||||
# if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
#include "nimble/ble.h"
|
||||
# else
|
||||
# include "nimble/nimble/include/nimble/ble.h"
|
||||
# endif
|
||||
|
||||
/**** FIX COMPILATION ****/
|
||||
#undef min
|
||||
#undef max
|
||||
/**************************/
|
||||
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
/**
|
||||
* @brief A BLE device address.
|
||||
* @brief A %BLE device address.
|
||||
*
|
||||
* Every BLE device has a unique address which can be used to identify it and form connections.
|
||||
* Every %BLE device has a unique address which can be used to identify it and form connections.
|
||||
*/
|
||||
class NimBLEAddress : private ble_addr_t {
|
||||
class NimBLEAddress {
|
||||
public:
|
||||
/**
|
||||
* @brief Create a blank address, i.e. 00:00:00:00:00:00, type 0.
|
||||
*/
|
||||
NimBLEAddress() = default;
|
||||
NimBLEAddress(const ble_addr_t address);
|
||||
NimBLEAddress(const uint8_t address[BLE_DEV_ADDR_LEN], uint8_t type);
|
||||
NimBLEAddress(const std::string& stringAddress, uint8_t type);
|
||||
NimBLEAddress(const uint64_t& address, uint8_t type);
|
||||
|
||||
bool isRpa() const;
|
||||
bool isNrpa() const;
|
||||
bool isStatic() const;
|
||||
bool isPublic() const;
|
||||
bool isNull() const;
|
||||
NimBLEAddress();
|
||||
NimBLEAddress(ble_addr_t address);
|
||||
NimBLEAddress(uint8_t address[6], uint8_t type = BLE_ADDR_PUBLIC);
|
||||
NimBLEAddress(const std::string &stringAddress, uint8_t type = BLE_ADDR_PUBLIC);
|
||||
NimBLEAddress(const uint64_t &address, uint8_t type = BLE_ADDR_PUBLIC);
|
||||
bool equals(const NimBLEAddress &otherAddress) const;
|
||||
const ble_addr_t* getBase() const;
|
||||
const uint8_t* getNative() const;
|
||||
std::string toString() const;
|
||||
uint8_t getType() const;
|
||||
const uint8_t* getVal() const;
|
||||
const NimBLEAddress& reverseByteOrder();
|
||||
|
||||
bool operator ==(const NimBLEAddress & rhs) const;
|
||||
bool operator !=(const NimBLEAddress & rhs) const;
|
||||
operator std::string() const;
|
||||
operator uint64_t() const;
|
||||
|
||||
private:
|
||||
uint8_t m_address[6];
|
||||
uint8_t m_addrType;
|
||||
};
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
#endif /* NIMBLE_CPP_ADDRESS_H_ */
|
||||
#endif /* COMPONENTS_NIMBLEADDRESS_H_ */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,40 +1,35 @@
|
||||
/*
|
||||
* Copyright 2020-2024 Ryan Powell <ryan@nable-embedded.io> and
|
||||
* esp-nimble-cpp, NimBLE-Arduino contributors.
|
||||
* NimBLEAdvertisedDevice.h
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* Created: on Jan 24 2020
|
||||
* Author H2zero
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Originally:
|
||||
*
|
||||
* 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.
|
||||
* BLEAdvertisedDevice.h
|
||||
*
|
||||
* Created on: Jul 3, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef NIMBLE_CPP_ADVERTISED_DEVICE_H_
|
||||
#define NIMBLE_CPP_ADVERTISED_DEVICE_H_
|
||||
#ifndef COMPONENTS_NIMBLEADVERTISEDDEVICE_H_
|
||||
#define COMPONENTS_NIMBLEADVERTISEDDEVICE_H_
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||
|
||||
#include "NimBLEAddress.h"
|
||||
#include "NimBLEScan.h"
|
||||
#include "NimBLEUUID.h"
|
||||
|
||||
# if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
#include "host/ble_hs_adv.h"
|
||||
# include "host/ble_gap.h"
|
||||
# else
|
||||
# include "nimble/nimble/host/include/host/ble_hs_adv.h"
|
||||
# include "nimble/nimble/host/include/host/ble_gap.h"
|
||||
# endif
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
|
||||
class NimBLEScan;
|
||||
/**
|
||||
* @brief A representation of a %BLE advertised device found by a scan.
|
||||
@ -44,59 +39,16 @@ class NimBLEScan;
|
||||
*/
|
||||
class NimBLEAdvertisedDevice {
|
||||
public:
|
||||
NimBLEAdvertisedDevice() = default;
|
||||
NimBLEAdvertisedDevice();
|
||||
|
||||
uint8_t getAdvType() const;
|
||||
uint8_t getAdvFlags() const;
|
||||
uint16_t getAppearance() const;
|
||||
uint16_t getAdvInterval() const;
|
||||
uint16_t getMinInterval() const;
|
||||
uint16_t getMaxInterval() const;
|
||||
uint8_t getManufacturerDataCount() const;
|
||||
const NimBLEAddress& getAddress() const;
|
||||
std::string getManufacturerData(uint8_t index = 0) const;
|
||||
std::string getURI() const;
|
||||
std::string getPayloadByType(uint16_t type, uint8_t index = 0) const;
|
||||
std::string getName() const;
|
||||
int8_t getRSSI() const;
|
||||
NimBLEScan* getScan() const;
|
||||
uint8_t getServiceDataCount() const;
|
||||
std::string getServiceData(uint8_t index = 0) const;
|
||||
std::string getServiceData(const NimBLEUUID& uuid) const;
|
||||
NimBLEUUID getServiceDataUUID(uint8_t index = 0) const;
|
||||
NimBLEUUID getServiceUUID(uint8_t index = 0) const;
|
||||
uint8_t getServiceUUIDCount() const;
|
||||
NimBLEAddress getTargetAddress(uint8_t index = 0) const;
|
||||
uint8_t getTargetAddressCount() const;
|
||||
int8_t getTXPower() const;
|
||||
uint8_t getAdvLength() const;
|
||||
uint8_t getAddressType() const;
|
||||
bool isAdvertisingService(const NimBLEUUID& uuid) const;
|
||||
bool haveAppearance() const;
|
||||
bool haveManufacturerData() const;
|
||||
bool haveName() const;
|
||||
bool haveServiceData() const;
|
||||
bool haveServiceUUID() const;
|
||||
bool haveTXPower() const;
|
||||
bool haveConnParams() const;
|
||||
bool haveAdvInterval() const;
|
||||
bool haveTargetAddress() const;
|
||||
bool haveURI() const;
|
||||
bool haveType(uint16_t type) const;
|
||||
std::string toString() const;
|
||||
bool isConnectable() const;
|
||||
bool isScannable() const;
|
||||
bool isLegacyAdvertisement() const;
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
uint8_t getSetId() const;
|
||||
uint8_t getPrimaryPhy() const;
|
||||
uint8_t getSecondaryPhy() const;
|
||||
uint16_t getPeriodicInterval() const;
|
||||
# endif
|
||||
|
||||
const std::vector<uint8_t>& getPayload() const;
|
||||
const std::vector<uint8_t>::const_iterator begin() const;
|
||||
const std::vector<uint8_t>::const_iterator end() const;
|
||||
NimBLEAddress getAddress();
|
||||
uint8_t getAdvType();
|
||||
uint16_t getAppearance();
|
||||
uint16_t getAdvInterval();
|
||||
uint16_t getMinInterval();
|
||||
uint16_t getMaxInterval();
|
||||
std::string getManufacturerData();
|
||||
std::string getURI();
|
||||
|
||||
/**
|
||||
* @brief A template to convert the service data to <type\>.
|
||||
@ -107,13 +59,20 @@ class NimBLEAdvertisedDevice {
|
||||
* @details <b>Use:</b> <tt>getManufacturerData<type>(skipSizeCheck);</tt>
|
||||
*/
|
||||
template<typename T>
|
||||
T getManufacturerData(bool skipSizeCheck = false) const {
|
||||
T getManufacturerData(bool skipSizeCheck = false) {
|
||||
std::string data = getManufacturerData();
|
||||
if(!skipSizeCheck && data.size() < sizeof(T)) return T();
|
||||
const char *pData = data.data();
|
||||
return *((T *)pData);
|
||||
}
|
||||
|
||||
std::string getName();
|
||||
int getRSSI();
|
||||
NimBLEScan* getScan();
|
||||
size_t getServiceDataCount();
|
||||
std::string getServiceData(uint8_t index = 0);
|
||||
std::string getServiceData(const NimBLEUUID &uuid);
|
||||
|
||||
/**
|
||||
* @brief A template to convert the service data to <tt><type\></tt>.
|
||||
* @tparam T The type to convert the data to.
|
||||
@ -124,7 +83,7 @@ class NimBLEAdvertisedDevice {
|
||||
* @details <b>Use:</b> <tt>getServiceData<type>(skipSizeCheck);</tt>
|
||||
*/
|
||||
template<typename T>
|
||||
T getServiceData(uint8_t index = 0, bool skipSizeCheck = false) const {
|
||||
T getServiceData(uint8_t index = 0, bool skipSizeCheck = false) {
|
||||
std::string data = getServiceData(index);
|
||||
if(!skipSizeCheck && data.size() < sizeof(T)) return T();
|
||||
const char *pData = data.data();
|
||||
@ -141,37 +100,77 @@ class NimBLEAdvertisedDevice {
|
||||
* @details <b>Use:</b> <tt>getServiceData<type>(skipSizeCheck);</tt>
|
||||
*/
|
||||
template<typename T>
|
||||
T getServiceData(const NimBLEUUID& uuid, bool skipSizeCheck = false) const {
|
||||
T getServiceData(const NimBLEUUID &uuid, bool skipSizeCheck = false) {
|
||||
std::string data = getServiceData(uuid);
|
||||
if(!skipSizeCheck && data.size() < sizeof(T)) return T();
|
||||
const char *pData = data.data();
|
||||
return *((T *)pData);
|
||||
}
|
||||
|
||||
NimBLEUUID getServiceDataUUID(uint8_t index = 0);
|
||||
NimBLEUUID getServiceUUID(uint8_t index = 0);
|
||||
size_t getServiceUUIDCount();
|
||||
NimBLEAddress getTargetAddress(uint8_t index = 0);
|
||||
size_t getTargetAddressCount();
|
||||
int8_t getTXPower();
|
||||
uint8_t* getPayload();
|
||||
uint8_t getAdvLength();
|
||||
size_t getPayloadLength();
|
||||
uint8_t getAddressType();
|
||||
time_t getTimestamp();
|
||||
bool isAdvertisingService(const NimBLEUUID &uuid);
|
||||
bool haveAppearance();
|
||||
bool haveManufacturerData();
|
||||
bool haveName();
|
||||
bool haveRSSI();
|
||||
bool haveServiceData();
|
||||
bool haveServiceUUID();
|
||||
bool haveTXPower();
|
||||
bool haveConnParams();
|
||||
bool haveAdvInterval();
|
||||
bool haveTargetAddress();
|
||||
bool haveURI();
|
||||
std::string toString();
|
||||
|
||||
private:
|
||||
friend class NimBLEScan;
|
||||
|
||||
NimBLEAdvertisedDevice(const ble_gap_event* event, uint8_t eventType);
|
||||
void update(const ble_gap_event* event, uint8_t eventType);
|
||||
uint8_t findAdvField(uint8_t type, uint8_t index = 0, size_t* data_loc = nullptr) const;
|
||||
size_t findServiceData(uint8_t index, uint8_t* bytes) const;
|
||||
void setAddress(NimBLEAddress address);
|
||||
void setAdvType(uint8_t advType);
|
||||
void setPayload(const uint8_t *payload, uint8_t length, bool append);
|
||||
void setRSSI(int rssi);
|
||||
uint8_t findAdvField(uint8_t type, uint8_t index = 0, uint8_t *data_loc = nullptr);
|
||||
uint8_t findServiceData(uint8_t index, uint8_t* bytes);
|
||||
|
||||
NimBLEAddress m_address{};
|
||||
uint8_t m_advType{};
|
||||
int8_t m_rssi{};
|
||||
uint8_t m_callbackSent{};
|
||||
uint8_t m_advLength{};
|
||||
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
bool m_isLegacyAdv{};
|
||||
uint8_t m_sid{};
|
||||
uint8_t m_primPhy{};
|
||||
uint8_t m_secPhy{};
|
||||
uint16_t m_periodicItvl{};
|
||||
# endif
|
||||
NimBLEAddress m_address = NimBLEAddress("");
|
||||
uint8_t m_advType;
|
||||
int m_rssi;
|
||||
time_t m_timestamp;
|
||||
bool m_callbackSent;
|
||||
uint8_t m_advLength;
|
||||
|
||||
std::vector<uint8_t> m_payload;
|
||||
};
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_OBSERVER */
|
||||
#endif /* NIMBLE_CPP_ADVERTISED_DEVICE_H_ */
|
||||
/**
|
||||
* @brief A callback handler for callbacks associated device scanning.
|
||||
*
|
||||
* When we are performing a scan as a %BLE client, we may wish to know when a new device that is advertising
|
||||
* has been found. This class can be sub-classed and registered such that when a scan is performed and
|
||||
* a new advertised device has been found, we will be called back to be notified.
|
||||
*/
|
||||
class NimBLEAdvertisedDeviceCallbacks {
|
||||
public:
|
||||
virtual ~NimBLEAdvertisedDeviceCallbacks() {}
|
||||
/**
|
||||
* @brief Called when a new scan result is detected.
|
||||
*
|
||||
* As we are scanning, we will find new devices. When found, this call back is invoked with a reference to the
|
||||
* device that was found. During any individual scan, a device will only be detected one time.
|
||||
*/
|
||||
virtual void onResult(NimBLEAdvertisedDevice* advertisedDevice) = 0;
|
||||
};
|
||||
|
||||
#endif // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
#endif /* COMPONENTS_NIMBLEADVERTISEDDEVICE_H_ */
|
||||
|
@ -1,583 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020-2024 Ryan Powell <ryan@nable-embedded.io> and
|
||||
* esp-nimble-cpp, NimBLE-Arduino contributors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if (defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER) && !CONFIG_BT_NIMBLE_EXT_ADV) || \
|
||||
defined(_DOXYGEN_)
|
||||
|
||||
# include "NimBLEAdvertisementData.h"
|
||||
# include "NimBLEDevice.h"
|
||||
# include "NimBLEUtils.h"
|
||||
# include "NimBLEUUID.h"
|
||||
# include "NimBLELog.h"
|
||||
|
||||
# if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
# include "host/ble_hs_adv.h"
|
||||
# else
|
||||
# include "nimble/nimble/host/include/host/ble_hs_adv.h"
|
||||
# endif
|
||||
|
||||
static const char* LOG_TAG = "NimBLEAdvertisementData";
|
||||
|
||||
/**
|
||||
* @brief Add data to the payload to be advertised.
|
||||
* @param [in] data The data to be added to the payload.
|
||||
* @param [in] length The size of data to be added to the payload.
|
||||
*/
|
||||
bool NimBLEAdvertisementData::addData(const uint8_t* data, size_t length) {
|
||||
if ((m_payload.size() + length) > BLE_HS_ADV_MAX_SZ) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Data length exceeded");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_payload.insert(m_payload.end(), data, data + length);
|
||||
return true;
|
||||
} // addData
|
||||
|
||||
/**
|
||||
* @brief Add data to the payload to be advertised.
|
||||
* @param [in] data The data to be added to the payload.
|
||||
*/
|
||||
bool NimBLEAdvertisementData::addData(const std::vector<uint8_t>& data) {
|
||||
return addData(&data[0], data.size());
|
||||
} // addData
|
||||
|
||||
/**
|
||||
* @brief Set the appearance.
|
||||
* @param [in] appearance The appearance code value.
|
||||
* @return True if successful.
|
||||
* @details If the appearance value is 0 then it will be removed from the advertisement if set previously.
|
||||
*/
|
||||
bool NimBLEAdvertisementData::setAppearance(uint16_t appearance) {
|
||||
if (appearance == 0) {
|
||||
return removeData(BLE_HS_ADV_TYPE_APPEARANCE);
|
||||
}
|
||||
|
||||
uint8_t data[4];
|
||||
data[0] = 3;
|
||||
data[1] = BLE_HS_ADV_TYPE_APPEARANCE;
|
||||
data[2] = appearance;
|
||||
data[3] = (appearance >> 8) & 0xFF;
|
||||
return addData(data, 4);
|
||||
} // setAppearance
|
||||
|
||||
/**
|
||||
* @brief Set the advertisement flags.
|
||||
* @param [in] flag The flags to be set in the advertisement.
|
||||
* * BLE_HS_ADV_F_DISC_LTD
|
||||
* * BLE_HS_ADV_F_DISC_GEN
|
||||
* * BLE_HS_ADV_F_BREDR_UNSUP - must always use with NimBLE
|
||||
* A flag value of 0 will remove the flags from the advertisement.
|
||||
*/
|
||||
bool NimBLEAdvertisementData::setFlags(uint8_t flag) {
|
||||
int dataLoc = getDataLocation(BLE_HS_ADV_TYPE_FLAGS);
|
||||
if (dataLoc != -1) {
|
||||
if (flag) {
|
||||
m_payload[dataLoc + 2] = flag | BLE_HS_ADV_F_BREDR_UNSUP;
|
||||
return true;
|
||||
} else {
|
||||
return removeData(BLE_HS_ADV_TYPE_FLAGS);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t data[3];
|
||||
data[0] = 2;
|
||||
data[1] = BLE_HS_ADV_TYPE_FLAGS;
|
||||
data[2] = flag | BLE_HS_ADV_F_BREDR_UNSUP;
|
||||
return addData(data, 3);
|
||||
} // setFlags
|
||||
|
||||
/**
|
||||
* @brief Adds Tx power level to the advertisement data.
|
||||
* @return True if successful.
|
||||
*/
|
||||
bool NimBLEAdvertisementData::addTxPower() {
|
||||
uint8_t data[3];
|
||||
data[0] = BLE_HS_ADV_TX_PWR_LVL_LEN + 1;
|
||||
data[1] = BLE_HS_ADV_TYPE_TX_PWR_LVL;
|
||||
# ifndef CONFIG_IDF_TARGET_ESP32P4
|
||||
data[2] = NimBLEDevice::getPower();
|
||||
# else
|
||||
data[2] = 0;
|
||||
# endif
|
||||
return addData(data, 3);
|
||||
} // addTxPower
|
||||
|
||||
/**
|
||||
* @brief Set the preferred min and max connection intervals to advertise.
|
||||
* @param [in] minInterval The minimum preferred connection interval.
|
||||
* @param [in] maxInterval The Maximum preferred connection interval.
|
||||
* @details Range = 0x0006(7.5ms) to 0x0C80(4000ms), values not within the range will be limited to this range.
|
||||
* @return True if successful.
|
||||
*/
|
||||
bool NimBLEAdvertisementData::setPreferredParams(uint16_t minInterval, uint16_t maxInterval) {
|
||||
minInterval = std::max<uint16_t>(minInterval, 0x6);
|
||||
minInterval = std::min<uint16_t>(minInterval, 0xC80);
|
||||
maxInterval = std::max<uint16_t>(maxInterval, 0x6);
|
||||
maxInterval = std::min<uint16_t>(maxInterval, 0xC80);
|
||||
maxInterval = std::max<uint16_t>(maxInterval, minInterval); // Max must be greater than or equal to min.
|
||||
|
||||
uint8_t data[6];
|
||||
data[0] = BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN + 1;
|
||||
data[1] = BLE_HS_ADV_TYPE_SLAVE_ITVL_RANGE;
|
||||
data[2] = minInterval;
|
||||
data[3] = minInterval >> 8;
|
||||
data[4] = maxInterval;
|
||||
data[5] = maxInterval >> 8;
|
||||
return addData(data, 6);
|
||||
} // setPreferredParams
|
||||
|
||||
/**
|
||||
* @brief Add a service uuid to exposed list of services.
|
||||
* @param [in] serviceUUID The UUID of the service to expose.
|
||||
*/
|
||||
bool NimBLEAdvertisementData::addServiceUUID(const NimBLEUUID& serviceUUID) {
|
||||
uint8_t bytes = serviceUUID.bitSize() / 8;
|
||||
int type;
|
||||
switch (bytes) {
|
||||
case 2:
|
||||
type = BLE_HS_ADV_TYPE_COMP_UUIDS16;
|
||||
break;
|
||||
case 4:
|
||||
type = BLE_HS_ADV_TYPE_COMP_UUIDS32;
|
||||
break;
|
||||
case 16:
|
||||
type = BLE_HS_ADV_TYPE_COMP_UUIDS128;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
int dataLoc = getDataLocation(type);
|
||||
uint8_t length = bytes;
|
||||
if (dataLoc == -1) {
|
||||
length += 2;
|
||||
}
|
||||
|
||||
if (length + getPayload().size() > BLE_HS_ADV_MAX_SZ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t data[31];
|
||||
const uint8_t* uuid = serviceUUID.getValue();
|
||||
if (dataLoc == -1) {
|
||||
data[0] = 1 + bytes;
|
||||
data[1] = type;
|
||||
memcpy(&data[2], uuid, bytes);
|
||||
return addData(data, length);
|
||||
}
|
||||
|
||||
m_payload.insert(m_payload.begin() + dataLoc + m_payload[dataLoc] + 1, uuid, uuid + bytes);
|
||||
m_payload[dataLoc] += bytes;
|
||||
return true;
|
||||
} // addServiceUUID
|
||||
|
||||
/**
|
||||
* @brief Add a service uuid to exposed list of services.
|
||||
* @param [in] serviceUUID The string representation of the service to expose.
|
||||
* @return True if successful.
|
||||
*/
|
||||
bool NimBLEAdvertisementData::addServiceUUID(const char* serviceUUID) {
|
||||
return addServiceUUID(NimBLEUUID(serviceUUID));
|
||||
} // addServiceUUID
|
||||
|
||||
/**
|
||||
* @brief Remove a service UUID from the advertisement.
|
||||
* @param [in] serviceUUID The UUID of the service to remove.
|
||||
* @return True if successful or uuid not found, false if uuid error or data could not be reset.
|
||||
*/
|
||||
bool NimBLEAdvertisementData::removeServiceUUID(const NimBLEUUID& serviceUUID) {
|
||||
uint8_t bytes = serviceUUID.bitSize() / 8;
|
||||
int type;
|
||||
switch (bytes) {
|
||||
case 2:
|
||||
type = BLE_HS_ADV_TYPE_COMP_UUIDS16;
|
||||
break;
|
||||
case 4:
|
||||
type = BLE_HS_ADV_TYPE_COMP_UUIDS32;
|
||||
break;
|
||||
case 16:
|
||||
type = BLE_HS_ADV_TYPE_COMP_UUIDS128;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
int dataLoc = getDataLocation(type);
|
||||
if (dataLoc == -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int uuidLoc = -1;
|
||||
for (size_t i = dataLoc + 2; i < m_payload.size(); i += bytes) {
|
||||
if (memcmp(&m_payload[i], serviceUUID.getValue(), bytes) == 0) {
|
||||
uuidLoc = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (uuidLoc == -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_payload[dataLoc] - bytes == 1) {
|
||||
return removeData(type);
|
||||
}
|
||||
|
||||
m_payload.erase(m_payload.begin() + uuidLoc, m_payload.begin() + uuidLoc + bytes);
|
||||
m_payload[dataLoc] -= bytes;
|
||||
return true;
|
||||
} // removeServiceUUID
|
||||
|
||||
/**
|
||||
* @brief Remove a service UUID from the advertisement.
|
||||
* @param [in] serviceUUID The UUID of the service to remove.
|
||||
* @return True if successful or uuid not found, false if uuid error or data could not be reset.
|
||||
*/
|
||||
bool NimBLEAdvertisementData::removeServiceUUID(const char* serviceUUID) {
|
||||
return removeServiceUUID(NimBLEUUID(serviceUUID));
|
||||
} // removeServiceUUID
|
||||
|
||||
/**
|
||||
* @brief Remove all service UUIDs from the advertisement.
|
||||
*/
|
||||
bool NimBLEAdvertisementData::removeServices() {
|
||||
return true;
|
||||
} // removeServices
|
||||
|
||||
/**
|
||||
* @brief Set manufacturer specific data.
|
||||
* @param [in] data The manufacturer data to advertise.
|
||||
* @param [in] length The length of the data.
|
||||
* @return True if successful.
|
||||
*/
|
||||
bool NimBLEAdvertisementData::setManufacturerData(const uint8_t* data, size_t length) {
|
||||
if (length > 29) {
|
||||
NIMBLE_LOGE(LOG_TAG, "MFG data too long");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t mdata[31];
|
||||
mdata[0] = length + 1;
|
||||
mdata[1] = BLE_HS_ADV_TYPE_MFG_DATA;
|
||||
memcpy(&mdata[2], data, length);
|
||||
return addData(mdata, length + 2);
|
||||
} // setManufacturerData
|
||||
|
||||
/**
|
||||
* @brief Set manufacturer specific data.
|
||||
* @param [in] data The manufacturer data to advertise.
|
||||
* @return True if successful.
|
||||
*/
|
||||
bool NimBLEAdvertisementData::setManufacturerData(const std::string& data) {
|
||||
return setManufacturerData(reinterpret_cast<const uint8_t*>(data.data()), data.length());
|
||||
} // setManufacturerData
|
||||
|
||||
/**
|
||||
* @brief Set manufacturer specific data.
|
||||
* @param [in] data The manufacturer data to advertise.
|
||||
* @return True if successful.
|
||||
*/
|
||||
bool NimBLEAdvertisementData::setManufacturerData(const std::vector<uint8_t>& data) {
|
||||
return setManufacturerData(&data[0], data.size());
|
||||
} // setManufacturerData
|
||||
|
||||
/**
|
||||
* @brief Set the URI to advertise.
|
||||
* @param [in] uri The uri to advertise.
|
||||
* @return True if successful.
|
||||
*/
|
||||
bool NimBLEAdvertisementData::setURI(const std::string& uri) {
|
||||
if (uri.length() > 29) {
|
||||
NIMBLE_LOGE(LOG_TAG, "URI too long");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t data[31];
|
||||
uint8_t length = 2 + uri.length();
|
||||
data[0] = length - 1;
|
||||
data[1] = BLE_HS_ADV_TYPE_URI;
|
||||
memcpy(&data[2], uri.c_str(), uri.length());
|
||||
return addData(data, length);
|
||||
} // setURI
|
||||
|
||||
/**
|
||||
* @brief Set the complete name of this device.
|
||||
* @param [in] name The name to advertise.
|
||||
* @param [in] isComplete If true the name is complete, which will set the data type accordingly.
|
||||
* @details If the name is longer than 29 characters it will be truncated.
|
||||
* and the data type will be set to incomplete name.
|
||||
* @return True if successful.
|
||||
*/
|
||||
bool NimBLEAdvertisementData::setName(const std::string& name, bool isComplete) {
|
||||
if (name.length() > 29) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Name too long - truncating");
|
||||
isComplete = false;
|
||||
}
|
||||
|
||||
uint8_t data[31];
|
||||
uint8_t length = 2 + std::min<uint8_t>(name.length(), 29);
|
||||
data[0] = length - 1;
|
||||
data[1] = isComplete ? BLE_HS_ADV_TYPE_COMP_NAME : BLE_HS_ADV_TYPE_INCOMP_NAME;
|
||||
memcpy(&data[2], name.c_str(), std::min<uint8_t>(name.length(), 29));
|
||||
return addData(data, length);
|
||||
} // setName
|
||||
|
||||
/**
|
||||
* @brief Set the short name.
|
||||
* @param [in] name The short name of the device.
|
||||
* @return True if successful.
|
||||
*/
|
||||
bool NimBLEAdvertisementData::setShortName(const std::string& name) {
|
||||
return setName(name, false);
|
||||
} // setShortName
|
||||
|
||||
/**
|
||||
* @brief Set a single service to advertise as a complete list of services.
|
||||
* @param [in] uuid The service to advertise.
|
||||
* @return True if successful.
|
||||
*/
|
||||
bool NimBLEAdvertisementData::setCompleteServices(const NimBLEUUID& uuid) {
|
||||
return setServices(true, uuid.bitSize(), {uuid});
|
||||
} // setCompleteServices
|
||||
|
||||
/**
|
||||
* @brief Set the complete list of 16 bit services to advertise.
|
||||
* @param [in] uuids A vector of 16 bit UUID's to advertise.
|
||||
* @return True if successful.
|
||||
*/
|
||||
bool NimBLEAdvertisementData::setCompleteServices16(const std::vector<NimBLEUUID>& uuids) {
|
||||
return setServices(true, 16, uuids);
|
||||
} // setCompleteServices16
|
||||
|
||||
/**
|
||||
* @brief Set the complete list of 32 bit services to advertise.
|
||||
* @param [in] uuids A vector of 32 bit UUID's to advertise.
|
||||
* @return True if successful.
|
||||
*/
|
||||
bool NimBLEAdvertisementData::setCompleteServices32(const std::vector<NimBLEUUID>& uuids) {
|
||||
return setServices(true, 32, uuids);
|
||||
} // setCompleteServices32
|
||||
|
||||
/**
|
||||
* @brief Set a single service to advertise as a partial list of services.
|
||||
* @param [in] uuid The service to advertise.
|
||||
* @return True if successful.
|
||||
*/
|
||||
bool NimBLEAdvertisementData::setPartialServices(const NimBLEUUID& uuid) {
|
||||
return setServices(false, uuid.bitSize(), {uuid});
|
||||
} // setPartialServices
|
||||
|
||||
/**
|
||||
* @brief Set the partial list of services to advertise.
|
||||
* @param [in] uuids A vector of 16 bit UUID's to advertise.
|
||||
* @return True if successful.
|
||||
*/
|
||||
bool NimBLEAdvertisementData::setPartialServices16(const std::vector<NimBLEUUID>& uuids) {
|
||||
return setServices(false, 16, uuids);
|
||||
} // setPartialServices16
|
||||
|
||||
/**
|
||||
* @brief Set the partial list of services to advertise.
|
||||
* @param [in] uuids A vector of 32 bit UUID's to advertise.
|
||||
* @return True if successful.
|
||||
*/
|
||||
bool NimBLEAdvertisementData::setPartialServices32(const std::vector<NimBLEUUID>& uuids) {
|
||||
return setServices(false, 32, uuids);
|
||||
} // setPartialServices32
|
||||
|
||||
/**
|
||||
* @brief Utility function to create the list of service UUID's from a vector.
|
||||
* @param [in] complete If true the vector is the complete set of services.
|
||||
* @param [in] size The bit size of the UUID's in the vector. (16, 32, or 128).
|
||||
* @param [in] uuids The vector of service UUID's to advertise.
|
||||
* @return True if successful.
|
||||
* @details The number of services will be truncated if the total length exceeds 31 bytes.
|
||||
*/
|
||||
bool NimBLEAdvertisementData::setServices(bool complete, uint8_t size, const std::vector<NimBLEUUID>& uuids) {
|
||||
uint8_t bytes = size / 8;
|
||||
uint8_t length = 2; // start with 2 for length + type bytes
|
||||
uint8_t data[31];
|
||||
|
||||
for (const auto& uuid : uuids) {
|
||||
if (uuid.bitSize() != size) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Service UUID(%d) invalid", size);
|
||||
continue;
|
||||
} else {
|
||||
if (length + bytes >= 31) {
|
||||
NIMBLE_LOGW(LOG_TAG, "Too many services - truncating");
|
||||
complete = false;
|
||||
break;
|
||||
}
|
||||
memcpy(&data[length], uuid.getValue(), bytes);
|
||||
length += bytes;
|
||||
}
|
||||
}
|
||||
|
||||
data[0] = length - 1; // don't count the length byte as part of the AD length
|
||||
|
||||
switch (size) {
|
||||
case 16:
|
||||
data[1] = (complete ? BLE_HS_ADV_TYPE_COMP_UUIDS16 : BLE_HS_ADV_TYPE_INCOMP_UUIDS16);
|
||||
break;
|
||||
case 32:
|
||||
data[1] = (complete ? BLE_HS_ADV_TYPE_COMP_UUIDS32 : BLE_HS_ADV_TYPE_INCOMP_UUIDS32);
|
||||
break;
|
||||
case 128:
|
||||
data[1] = (complete ? BLE_HS_ADV_TYPE_COMP_UUIDS128 : BLE_HS_ADV_TYPE_INCOMP_UUIDS128);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return addData(data, length);
|
||||
} // setServices
|
||||
|
||||
/**
|
||||
* @brief Set the service data advertised for the UUID.
|
||||
* @param [in] uuid The UUID the service data belongs to.
|
||||
* @param [in] data The data to advertise.
|
||||
* @param [in] length The length of the data.
|
||||
* @note If data length is 0 the service data will not be advertised.
|
||||
* @return True if successful, false if data length is too long or could not be set.
|
||||
*/
|
||||
bool NimBLEAdvertisementData::setServiceData(const NimBLEUUID& uuid, const uint8_t* data, size_t length) {
|
||||
uint8_t uuidBytes = uuid.bitSize() / 8;
|
||||
uint8_t sDataLen = 2 + uuidBytes + length;
|
||||
if (sDataLen > 31) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Service Data too long");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t type;
|
||||
switch (uuidBytes) {
|
||||
case 2:
|
||||
type = BLE_HS_ADV_TYPE_SVC_DATA_UUID16;
|
||||
break;
|
||||
case 4:
|
||||
type = BLE_HS_ADV_TYPE_SVC_DATA_UUID32;
|
||||
break;
|
||||
case 16:
|
||||
type = BLE_HS_ADV_TYPE_SVC_DATA_UUID128;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (length == 0) {
|
||||
removeData(type);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t sData[31];
|
||||
sData[0] = uuidBytes + length + 1;
|
||||
sData[1] = type;
|
||||
memcpy(&sData[2], uuid.getValue(), uuidBytes);
|
||||
memcpy(&sData[2 + uuidBytes], data, length);
|
||||
return addData(sData, sDataLen);
|
||||
} // setServiceData
|
||||
|
||||
/**
|
||||
* @brief Set the service data (UUID + data)
|
||||
* @param [in] uuid The UUID to set with the service data.
|
||||
* @param [in] data The data to be associated with the service data advertised.
|
||||
* @return True if the service data was set successfully.
|
||||
* @note If data length is 0 the service data will not be advertised.
|
||||
*/
|
||||
bool NimBLEAdvertisementData::setServiceData(const NimBLEUUID& uuid, const std::string& data) {
|
||||
return setServiceData(uuid, reinterpret_cast<const uint8_t*>(data.data()), data.length());
|
||||
} // setServiceData
|
||||
|
||||
/**
|
||||
* @brief Set the service data advertised for the UUID.
|
||||
* @param [in] uuid The UUID the service data belongs to.
|
||||
* @param [in] data The data to advertise.
|
||||
* @return True if the service data was set successfully.
|
||||
* @note If data length is 0 the service data will not be advertised.
|
||||
*/
|
||||
bool NimBLEAdvertisementData::setServiceData(const NimBLEUUID& uuid, const std::vector<uint8_t>& data) {
|
||||
return setServiceData(uuid, &data[0], data.size());
|
||||
} // setServiceData
|
||||
|
||||
/**
|
||||
* @brief Get the location of the data in the payload.
|
||||
* @param [in] type The type of data to search for.
|
||||
* @return -1 if the data is not found, otherwise the index of the data in the payload.
|
||||
*/
|
||||
int NimBLEAdvertisementData::getDataLocation(uint8_t type) const {
|
||||
size_t index = 0;
|
||||
while (index < m_payload.size()) {
|
||||
if (m_payload[index + 1] == type) {
|
||||
return index;
|
||||
}
|
||||
index += m_payload[index] + 1;
|
||||
}
|
||||
return -1;
|
||||
} // getDataLocation
|
||||
|
||||
/**
|
||||
* @brief Remove data from the advertisement data.
|
||||
* @param [in] type The type of data to remove.
|
||||
* @return True if successful, false if the data was not found.
|
||||
*/
|
||||
bool NimBLEAdvertisementData::removeData(uint8_t type) {
|
||||
int dataLoc = getDataLocation(type);
|
||||
if (dataLoc != -1) {
|
||||
std::vector<uint8_t> swap(m_payload.begin(), m_payload.begin() + dataLoc);
|
||||
int nextData = dataLoc + m_payload[dataLoc] + 1;
|
||||
swap.insert(swap.end(), m_payload.begin() + nextData, m_payload.end());
|
||||
swap.swap(m_payload);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
} // removeData
|
||||
|
||||
/**
|
||||
* @brief Retrieve the payload that is to be advertised.
|
||||
* @return The payload of the advertisement data.
|
||||
*/
|
||||
std::vector<uint8_t> NimBLEAdvertisementData::getPayload() const {
|
||||
return m_payload;
|
||||
} // getPayload
|
||||
|
||||
/**
|
||||
* @brief Clear the advertisement data for reuse.
|
||||
*/
|
||||
void NimBLEAdvertisementData::clearData() {
|
||||
std::vector<uint8_t>().swap(m_payload);
|
||||
} // clearData
|
||||
|
||||
/**
|
||||
* @brief Get the string representation of the advertisement data.
|
||||
* @return The string representation of the advertisement data.
|
||||
*/
|
||||
std::string NimBLEAdvertisementData::toString() const {
|
||||
std::string hexStr = NimBLEUtils::dataToHexString(&m_payload[0], m_payload.size());
|
||||
std::string str;
|
||||
for (size_t i = 0; i < hexStr.length(); i += 2) {
|
||||
str += hexStr[i];
|
||||
str += hexStr[i + 1];
|
||||
if (i + 2 < hexStr.length()) {
|
||||
str += " ";
|
||||
}
|
||||
}
|
||||
|
||||
return str;
|
||||
} // toString
|
||||
|
||||
#endif // CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER && !CONFIG_BT_NIMBLE_EXT_ADV
|
@ -1,79 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020-2024 Ryan Powell <ryan@nable-embedded.io> and
|
||||
* esp-nimble-cpp, NimBLE-Arduino contributors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef NIMBLE_CPP_ADVERTISEMENT_DATA_H_
|
||||
#define NIMBLE_CPP_ADVERTISEMENT_DATA_H_
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if (defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER) && !CONFIG_BT_NIMBLE_EXT_ADV) || \
|
||||
defined(_DOXYGEN_)
|
||||
|
||||
# include <cstdint>
|
||||
# include <string>
|
||||
# include <vector>
|
||||
|
||||
class NimBLEUUID;
|
||||
/**
|
||||
* @brief Advertisement data set by the programmer to be published by the BLE server.
|
||||
*/
|
||||
class NimBLEAdvertisementData {
|
||||
// Only a subset of the possible BLE architected advertisement fields are currently exposed. Others will
|
||||
// be exposed on demand/request or as time permits.
|
||||
//
|
||||
public:
|
||||
bool addData(const uint8_t* data, size_t length);
|
||||
bool addData(const std::vector<uint8_t>& data);
|
||||
bool setAppearance(uint16_t appearance);
|
||||
bool setFlags(uint8_t);
|
||||
bool addTxPower();
|
||||
bool setPreferredParams(uint16_t minInterval, uint16_t maxInterval);
|
||||
bool addServiceUUID(const NimBLEUUID& serviceUUID);
|
||||
bool addServiceUUID(const char* serviceUUID);
|
||||
bool removeServiceUUID(const NimBLEUUID& serviceUUID);
|
||||
bool removeServiceUUID(const char* serviceUUID);
|
||||
bool removeServices();
|
||||
bool setManufacturerData(const uint8_t* data, size_t length);
|
||||
bool setManufacturerData(const std::string& data);
|
||||
bool setManufacturerData(const std::vector<uint8_t>& data);
|
||||
bool setURI(const std::string& uri);
|
||||
bool setName(const std::string& name, bool isComplete = true);
|
||||
bool setShortName(const std::string& name);
|
||||
bool setCompleteServices(const NimBLEUUID& uuid);
|
||||
bool setCompleteServices16(const std::vector<NimBLEUUID>& uuids);
|
||||
bool setCompleteServices32(const std::vector<NimBLEUUID>& uuids);
|
||||
bool setPartialServices(const NimBLEUUID& uuid);
|
||||
bool setPartialServices16(const std::vector<NimBLEUUID>& uuids);
|
||||
bool setPartialServices32(const std::vector<NimBLEUUID>& uuids);
|
||||
bool setServiceData(const NimBLEUUID& uuid, const uint8_t* data, size_t length);
|
||||
bool setServiceData(const NimBLEUUID& uuid, const std::string& data);
|
||||
bool setServiceData(const NimBLEUUID& uuid, const std::vector<uint8_t>& data);
|
||||
bool removeData(uint8_t type);
|
||||
void clearData();
|
||||
int getDataLocation(uint8_t type) const;
|
||||
|
||||
std::string toString() const;
|
||||
std::vector<uint8_t> getPayload() const;
|
||||
|
||||
private:
|
||||
friend class NimBLEAdvertising;
|
||||
|
||||
bool setServices(bool complete, uint8_t size, const std::vector<NimBLEUUID>& v_uuid);
|
||||
std::vector<uint8_t> m_payload{};
|
||||
}; // NimBLEAdvertisementData
|
||||
|
||||
#endif // CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER && !CONFIG_BT_NIMBLE_EXT_ADV
|
||||
#endif // NIMBLE_CPP_ADVERTISEMENT_DATA_H_
|
File diff suppressed because it is too large
Load Diff
@ -1,110 +1,137 @@
|
||||
/*
|
||||
* Copyright 2020-2024 Ryan Powell <ryan@nable-embedded.io> and
|
||||
* esp-nimble-cpp, NimBLE-Arduino contributors.
|
||||
* NimBLEAdvertising.h
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* Created: on March 3, 2020
|
||||
* Author H2zero
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Originally:
|
||||
*
|
||||
* 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.
|
||||
* BLEAdvertising.h
|
||||
*
|
||||
* Created on: Jun 21, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef NIMBLE_CPP_ADVERTISING_H_
|
||||
#define NIMBLE_CPP_ADVERTISING_H_
|
||||
#ifndef MAIN_BLEADVERTISING_H_
|
||||
#define MAIN_BLEADVERTISING_H_
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if (defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER) && !CONFIG_BT_NIMBLE_EXT_ADV) || \
|
||||
defined(_DOXYGEN_)
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||
|
||||
# if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
#include "host/ble_gap.h"
|
||||
# else
|
||||
# include "nimble/nimble/host/include/host/ble_gap.h"
|
||||
# endif
|
||||
|
||||
/**** FIX COMPILATION ****/
|
||||
#undef min
|
||||
#undef max
|
||||
/**************************/
|
||||
|
||||
#include "NimBLEUUID.h"
|
||||
# include "NimBLEAddress.h"
|
||||
# include "NimBLEAdvertisementData.h"
|
||||
|
||||
# include <functional>
|
||||
# include <string>
|
||||
#include <vector>
|
||||
|
||||
class NimBLEAdvertising;
|
||||
typedef std::function<void(NimBLEAdvertising*)> advCompleteCB_t;
|
||||
/* COMPATIBILITY - DO NOT USE */
|
||||
#define ESP_BLE_ADV_FLAG_LIMIT_DISC (0x01 << 0)
|
||||
#define ESP_BLE_ADV_FLAG_GEN_DISC (0x01 << 1)
|
||||
#define ESP_BLE_ADV_FLAG_BREDR_NOT_SPT (0x01 << 2)
|
||||
#define ESP_BLE_ADV_FLAG_DMT_CONTROLLER_SPT (0x01 << 3)
|
||||
#define ESP_BLE_ADV_FLAG_DMT_HOST_SPT (0x01 << 4)
|
||||
#define ESP_BLE_ADV_FLAG_NON_LIMIT_DISC (0x00 )
|
||||
/* ************************* */
|
||||
|
||||
|
||||
/**
|
||||
* @brief Perform and manage BLE advertising.
|
||||
* @brief Advertisement data set by the programmer to be published by the %BLE server.
|
||||
*/
|
||||
class NimBLEAdvertisementData {
|
||||
// Only a subset of the possible BLE architected advertisement fields are currently exposed. Others will
|
||||
// be exposed on demand/request or as time permits.
|
||||
//
|
||||
public:
|
||||
void setAppearance(uint16_t appearance);
|
||||
void setCompleteServices(const NimBLEUUID &uuid);
|
||||
void setCompleteServices16(const std::vector<NimBLEUUID> &v_uuid);
|
||||
void setCompleteServices32(const std::vector<NimBLEUUID> &v_uuid);
|
||||
void setFlags(uint8_t);
|
||||
void setManufacturerData(const std::string &data);
|
||||
void setURI(const std::string &uri);
|
||||
void setName(const std::string &name);
|
||||
void setPartialServices(const NimBLEUUID &uuid);
|
||||
void setPartialServices16(const std::vector<NimBLEUUID> &v_uuid);
|
||||
void setPartialServices32(const std::vector<NimBLEUUID> &v_uuid);
|
||||
void setServiceData(const NimBLEUUID &uuid, const std::string &data);
|
||||
void setShortName(const std::string &name);
|
||||
void addData(const std::string &data); // Add data to the payload.
|
||||
void addData(char * data, size_t length);
|
||||
void addTxPower();
|
||||
void setPreferredParams(uint16_t min, uint16_t max);
|
||||
std::string getPayload(); // Retrieve the current advert payload.
|
||||
|
||||
private:
|
||||
friend class NimBLEAdvertising;
|
||||
void setServices(const bool complete, const uint8_t size,
|
||||
const std::vector<NimBLEUUID> &v_uuid);
|
||||
std::string m_payload; // The payload of the advertisement.
|
||||
}; // NimBLEAdvertisementData
|
||||
|
||||
|
||||
/**
|
||||
* @brief Perform and manage %BLE advertising.
|
||||
*
|
||||
* A BLE server will want to perform advertising in order to make itself known to BLE clients.
|
||||
* A %BLE server will want to perform advertising in order to make itself known to %BLE clients.
|
||||
*/
|
||||
class NimBLEAdvertising {
|
||||
public:
|
||||
NimBLEAdvertising();
|
||||
bool start(uint32_t duration = 0, const NimBLEAddress* dirAddr = nullptr);
|
||||
void setAdvertisingCompleteCallback(advCompleteCB_t callback);
|
||||
bool stop();
|
||||
bool setConnectableMode(uint8_t mode);
|
||||
bool setDiscoverableMode(uint8_t mode);
|
||||
bool reset();
|
||||
bool isAdvertising();
|
||||
void addServiceUUID(const NimBLEUUID &serviceUUID);
|
||||
void addServiceUUID(const char* serviceUUID);
|
||||
void removeServiceUUID(const NimBLEUUID &serviceUUID);
|
||||
bool start(uint32_t duration = 0, void (*advCompleteCB)(NimBLEAdvertising *pAdv) = nullptr);
|
||||
void stop();
|
||||
void setAppearance(uint16_t appearance);
|
||||
void setName(const std::string &name);
|
||||
void setManufacturerData(const std::string &data);
|
||||
void setURI(const std::string &uri);
|
||||
void setServiceData(const NimBLEUUID &uuid, const std::string &data);
|
||||
void setAdvertisementType(uint8_t adv_type);
|
||||
void setMaxInterval(uint16_t maxinterval);
|
||||
void setMinInterval(uint16_t mininterval);
|
||||
void setAdvertisementData(NimBLEAdvertisementData& advertisementData);
|
||||
void setScanFilter(bool scanRequestWhitelistOnly, bool connectWhitelistOnly);
|
||||
void enableScanResponse(bool enable);
|
||||
void setAdvertisingInterval(uint16_t interval);
|
||||
void setMaxInterval(uint16_t maxInterval);
|
||||
void setMinInterval(uint16_t minInterval);
|
||||
|
||||
bool setAdvertisementData(const NimBLEAdvertisementData& advertisementData);
|
||||
bool setScanResponseData(const NimBLEAdvertisementData& advertisementData);
|
||||
const NimBLEAdvertisementData& getAdvertisementData();
|
||||
const NimBLEAdvertisementData& getScanData();
|
||||
void clearData();
|
||||
bool refreshAdvertisingData();
|
||||
|
||||
bool addServiceUUID(const NimBLEUUID& serviceUUID);
|
||||
bool addServiceUUID(const char* serviceUUID);
|
||||
bool removeServiceUUID(const NimBLEUUID& serviceUUID);
|
||||
bool removeServiceUUID(const char* serviceUUID);
|
||||
bool removeServices();
|
||||
bool setAppearance(uint16_t appearance);
|
||||
bool setPreferredParams(uint16_t minInterval, uint16_t maxInterval);
|
||||
bool addTxPower();
|
||||
bool setName(const std::string& name);
|
||||
bool setManufacturerData(const uint8_t* data, size_t length);
|
||||
bool setManufacturerData(const std::string& data);
|
||||
bool setManufacturerData(const std::vector<uint8_t>& data);
|
||||
bool setURI(const std::string& uri);
|
||||
bool setServiceData(const NimBLEUUID& uuid, const uint8_t* data, size_t length);
|
||||
bool setServiceData(const NimBLEUUID& uuid, const std::string& data);
|
||||
bool setServiceData(const NimBLEUUID& uuid, const std::vector<uint8_t>& data);
|
||||
void setScanResponseData(NimBLEAdvertisementData& advertisementData);
|
||||
void setScanResponse(bool);
|
||||
void setMinPreferred(uint16_t);
|
||||
void setMaxPreferred(uint16_t);
|
||||
void addTxPower();
|
||||
void reset();
|
||||
void advCompleteCB();
|
||||
bool isAdvertising();
|
||||
|
||||
private:
|
||||
friend class NimBLEDevice;
|
||||
friend class NimBLEServer;
|
||||
|
||||
void onHostSync();
|
||||
static int handleGapEvent(ble_gap_event* event, void* arg);
|
||||
static int handleGapEvent(struct ble_gap_event *event, void *arg);
|
||||
|
||||
NimBLEAdvertisementData m_advData;
|
||||
NimBLEAdvertisementData m_scanData;
|
||||
ble_hs_adv_fields m_advData;
|
||||
ble_hs_adv_fields m_scanData;
|
||||
ble_gap_adv_params m_advParams;
|
||||
advCompleteCB_t m_advCompCb;
|
||||
std::vector<NimBLEUUID> m_serviceUUIDs;
|
||||
bool m_customAdvData;
|
||||
bool m_customScanResponseData;
|
||||
bool m_scanResp;
|
||||
bool m_advDataSet;
|
||||
void (*m_advCompCB)(NimBLEAdvertising *pAdv);
|
||||
uint8_t m_slaveItvl[4];
|
||||
uint32_t m_duration;
|
||||
bool m_scanResp : 1;
|
||||
bool m_advDataSet : 1;
|
||||
std::vector<uint8_t> m_svcData16;
|
||||
std::vector<uint8_t> m_svcData32;
|
||||
std::vector<uint8_t> m_svcData128;
|
||||
std::vector<uint8_t> m_name;
|
||||
std::vector<uint8_t> m_mfgData;
|
||||
std::vector<uint8_t> m_uri;
|
||||
};
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER && !CONFIG_BT_NIMBLE_EXT_ADV */
|
||||
#endif /* NIMBLE_CPP_ADVERTISING_H_ */
|
||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
#endif /* MAIN_BLEADVERTISING_H_ */
|
||||
|
@ -1,138 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020-2024 Ryan Powell <ryan@nable-embedded.io> and
|
||||
* esp-nimble-cpp, NimBLE-Arduino contributors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
# if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
# include "nimble/nimble_npl.h"
|
||||
# else
|
||||
# include "nimble/nimble/include/nimble/nimble_npl.h"
|
||||
# endif
|
||||
|
||||
# include "NimBLEAttValue.h"
|
||||
|
||||
// Default constructor implementation.
|
||||
NimBLEAttValue::NimBLEAttValue(uint16_t init_len, uint16_t max_len)
|
||||
: m_attr_value{static_cast<uint8_t*>(calloc(init_len + 1, 1))},
|
||||
m_attr_max_len{std::min<uint16_t>(BLE_ATT_ATTR_MAX_LEN, max_len)},
|
||||
m_attr_len{},
|
||||
m_capacity{init_len}
|
||||
# if CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
|
||||
,
|
||||
m_timestamp{}
|
||||
# endif
|
||||
{
|
||||
NIMBLE_CPP_DEBUG_ASSERT(m_attr_value);
|
||||
}
|
||||
|
||||
// Value constructor implementation.
|
||||
NimBLEAttValue::NimBLEAttValue(const uint8_t* value, uint16_t len, uint16_t max_len) : NimBLEAttValue(len, max_len) {
|
||||
memcpy(m_attr_value, value, len);
|
||||
m_attr_value[len] = '\0';
|
||||
m_attr_len = len;
|
||||
}
|
||||
|
||||
// Destructor implementation.
|
||||
NimBLEAttValue::~NimBLEAttValue() {
|
||||
if (m_attr_value != nullptr) {
|
||||
free(m_attr_value);
|
||||
}
|
||||
}
|
||||
|
||||
// Move assignment operator implementation.
|
||||
NimBLEAttValue& NimBLEAttValue::operator=(NimBLEAttValue&& source) {
|
||||
if (this != &source) {
|
||||
free(m_attr_value);
|
||||
m_attr_value = source.m_attr_value;
|
||||
m_attr_max_len = source.m_attr_max_len;
|
||||
m_attr_len = source.m_attr_len;
|
||||
m_capacity = source.m_capacity;
|
||||
setTimeStamp(source.getTimeStamp());
|
||||
source.m_attr_value = nullptr;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Copy assignment implementation.
|
||||
NimBLEAttValue& NimBLEAttValue::operator=(const NimBLEAttValue& source) {
|
||||
if (this != &source) {
|
||||
deepCopy(source);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Copy all the data from the source object to this object, including allocated space.
|
||||
void NimBLEAttValue::deepCopy(const NimBLEAttValue& source) {
|
||||
uint8_t* res = static_cast<uint8_t*>(realloc(m_attr_value, source.m_capacity + 1));
|
||||
NIMBLE_CPP_DEBUG_ASSERT(res);
|
||||
|
||||
ble_npl_hw_enter_critical();
|
||||
m_attr_value = res;
|
||||
m_attr_max_len = source.m_attr_max_len;
|
||||
m_attr_len = source.m_attr_len;
|
||||
m_capacity = source.m_capacity;
|
||||
setTimeStamp(source.getTimeStamp());
|
||||
memcpy(m_attr_value, source.m_attr_value, m_attr_len + 1);
|
||||
ble_npl_hw_exit_critical(0);
|
||||
}
|
||||
|
||||
// Set the value of the attribute.
|
||||
bool NimBLEAttValue::setValue(const uint8_t* value, uint16_t len) {
|
||||
m_attr_len = 0; // Just set the value length to 0 and append instead of repeating code.
|
||||
append(value, len);
|
||||
return memcmp(m_attr_value, value, len) == 0 && m_attr_len == len;
|
||||
}
|
||||
|
||||
// Append the new data, allocate as necessary.
|
||||
NimBLEAttValue& NimBLEAttValue::append(const uint8_t* value, uint16_t len) {
|
||||
if (len == 0) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
if ((m_attr_len + len) > m_attr_max_len) {
|
||||
NIMBLE_LOGE("NimBLEAttValue", "val > max, len=%u, max=%u", len, m_attr_max_len);
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint8_t* res = m_attr_value;
|
||||
uint16_t new_len = m_attr_len + len;
|
||||
if (new_len > m_capacity) {
|
||||
res = static_cast<uint8_t*>(realloc(m_attr_value, (new_len + 1)));
|
||||
m_capacity = new_len;
|
||||
}
|
||||
NIMBLE_CPP_DEBUG_ASSERT(res);
|
||||
|
||||
# if CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
|
||||
time_t t = time(nullptr);
|
||||
# else
|
||||
time_t t = 0;
|
||||
# endif
|
||||
|
||||
ble_npl_hw_enter_critical();
|
||||
memcpy(res + m_attr_len, value, len);
|
||||
m_attr_value = res;
|
||||
m_attr_len = new_len;
|
||||
m_attr_value[m_attr_len] = '\0';
|
||||
setTimeStamp(t);
|
||||
ble_npl_hw_exit_critical(0);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
#endif // CONFIG_BT_ENABLED
|
@ -1,370 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020-2024 Ryan Powell <ryan@nable-embedded.io> and
|
||||
* esp-nimble-cpp, NimBLE-Arduino contributors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef NIMBLE_CPP_ATTVALUE_H
|
||||
#define NIMBLE_CPP_ATTVALUE_H
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
# ifdef NIMBLE_CPP_ARDUINO_STRING_AVAILABLE
|
||||
# include <Arduino.h>
|
||||
# endif
|
||||
|
||||
# include "NimBLELog.h"
|
||||
# include <string>
|
||||
# include <vector>
|
||||
# include <ctime>
|
||||
# include <cstring>
|
||||
# include <cstdint>
|
||||
|
||||
# ifndef CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
|
||||
# define CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED 0
|
||||
# endif
|
||||
|
||||
# ifndef BLE_ATT_ATTR_MAX_LEN
|
||||
# define BLE_ATT_ATTR_MAX_LEN 512
|
||||
# endif
|
||||
|
||||
# if !defined(CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH)
|
||||
# define CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH 20
|
||||
# elif CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH > BLE_ATT_ATTR_MAX_LEN
|
||||
# error CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH cannot be larger than 512 (BLE_ATT_ATTR_MAX_LEN)
|
||||
# elif CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH < 1
|
||||
# error CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH cannot be less than 1; Range = 1 : 512
|
||||
# endif
|
||||
|
||||
/* Used to determine if the type passed to a template has a data() and size() method. */
|
||||
template <typename T, typename = void, typename = void>
|
||||
struct Has_data_size : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct Has_data_size<T, decltype(void(std::declval<T&>().data())), decltype(void(std::declval<T&>().size()))>
|
||||
: std::true_type {};
|
||||
|
||||
/* Used to determine if the type passed to a template has a c_str() and length() method. */
|
||||
template <typename T, typename = void, typename = void>
|
||||
struct Has_c_str_length : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct Has_c_str_length<T, decltype(void(std::declval<T&>().c_str())), decltype(void(std::declval<T&>().length()))>
|
||||
: std::true_type {};
|
||||
|
||||
/**
|
||||
* @brief A specialized container class to hold BLE attribute values.
|
||||
* @details This class is designed to be more memory efficient than using\n
|
||||
* standard container types for value storage, while being convertible to\n
|
||||
* many different container classes.
|
||||
*/
|
||||
class NimBLEAttValue {
|
||||
uint8_t* m_attr_value{};
|
||||
uint16_t m_attr_max_len{};
|
||||
uint16_t m_attr_len{};
|
||||
uint16_t m_capacity{};
|
||||
# if CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
|
||||
time_t m_timestamp{};
|
||||
# endif
|
||||
void deepCopy(const NimBLEAttValue& source);
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor.
|
||||
* @param[in] init_len The initial size in bytes.
|
||||
* @param[in] max_len The max size in bytes that the value can be.
|
||||
*/
|
||||
NimBLEAttValue(uint16_t init_len = CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH, uint16_t max_len = BLE_ATT_ATTR_MAX_LEN);
|
||||
|
||||
/**
|
||||
* @brief Construct with an initial value from a buffer.
|
||||
* @param value A pointer to the initial value to set.
|
||||
* @param[in] len The size in bytes of the value to set.
|
||||
* @param[in] max_len The max size in bytes that the value can be.
|
||||
*/
|
||||
NimBLEAttValue(const uint8_t* value, uint16_t len, uint16_t max_len = BLE_ATT_ATTR_MAX_LEN);
|
||||
|
||||
/**
|
||||
* @brief Construct with an initial value from a const char string.
|
||||
* @param value A pointer to the initial value to set.
|
||||
* @param[in] max_len The max size in bytes that the value can be.
|
||||
*/
|
||||
NimBLEAttValue(const char* value, uint16_t max_len = BLE_ATT_ATTR_MAX_LEN)
|
||||
: NimBLEAttValue((uint8_t*)value, (uint16_t)strlen(value), max_len) {}
|
||||
|
||||
/**
|
||||
* @brief Construct with an initializer list.
|
||||
* @param list An initializer list containing the initial value to set.
|
||||
* @param[in] max_len The max size in bytes that the value can be.
|
||||
*/
|
||||
NimBLEAttValue(std::initializer_list<uint8_t> list, uint16_t max_len = BLE_ATT_ATTR_MAX_LEN)
|
||||
: NimBLEAttValue(list.begin(), list.size(), max_len) {}
|
||||
|
||||
/**
|
||||
* @brief Construct with an initial value from a std::string.
|
||||
* @param str A std::string containing to the initial value to set.
|
||||
* @param[in] max_len The max size in bytes that the value can be.
|
||||
*/
|
||||
NimBLEAttValue(const std::string str, uint16_t max_len = BLE_ATT_ATTR_MAX_LEN)
|
||||
: NimBLEAttValue(reinterpret_cast<const uint8_t*>(&str[0]), str.length(), max_len) {}
|
||||
|
||||
/**
|
||||
* @brief Construct with an initial value from a std::vector<uint8_t>.
|
||||
* @param vec A std::vector<uint8_t> containing to the initial value to set.
|
||||
* @param[in] max_len The max size in bytes that the value can be.
|
||||
*/
|
||||
NimBLEAttValue(const std::vector<uint8_t> vec, uint16_t max_len = BLE_ATT_ATTR_MAX_LEN)
|
||||
: NimBLEAttValue(&vec[0], vec.size(), max_len) {}
|
||||
|
||||
# ifdef NIMBLE_CPP_ARDUINO_STRING_AVAILABLE
|
||||
/**
|
||||
* @brief Construct with an initial value from an Arduino String.
|
||||
* @param str An Arduino String containing to the initial value to set.
|
||||
* @param[in] max_len The max size in bytes that the value can be.
|
||||
*/
|
||||
NimBLEAttValue(const String str, uint16_t max_len = BLE_ATT_ATTR_MAX_LEN)
|
||||
: NimBLEAttValue(reinterpret_cast<const uint8_t*>(str.c_str()), str.length(), max_len) {}
|
||||
# endif
|
||||
|
||||
/** @brief Copy constructor */
|
||||
NimBLEAttValue(const NimBLEAttValue& source) { deepCopy(source); }
|
||||
|
||||
/** @brief Move constructor */
|
||||
NimBLEAttValue(NimBLEAttValue&& source) { *this = std::move(source); }
|
||||
|
||||
/** @brief Destructor */
|
||||
~NimBLEAttValue();
|
||||
|
||||
/** @brief Returns the max size in bytes */
|
||||
uint16_t max_size() const { return m_attr_max_len; }
|
||||
|
||||
/** @brief Returns the currently allocated capacity in bytes */
|
||||
uint16_t capacity() const { return m_capacity; }
|
||||
|
||||
/** @brief Returns the current length of the value in bytes */
|
||||
uint16_t length() const { return m_attr_len; }
|
||||
|
||||
/** @brief Returns the current size of the value in bytes */
|
||||
uint16_t size() const { return m_attr_len; }
|
||||
|
||||
/** @brief Returns a pointer to the internal buffer of the value */
|
||||
const uint8_t* data() const { return m_attr_value; }
|
||||
|
||||
/** @brief Returns a pointer to the internal buffer of the value as a const char* */
|
||||
const char* c_str() const { return reinterpret_cast<const char*>(m_attr_value); }
|
||||
|
||||
/** @brief Iterator begin */
|
||||
const uint8_t* begin() const { return m_attr_value; }
|
||||
|
||||
/** @brief Iterator end */
|
||||
const uint8_t* end() const { return m_attr_value + m_attr_len; }
|
||||
|
||||
# if CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
|
||||
/** @brief Returns a timestamp of when the value was last updated */
|
||||
time_t getTimeStamp() const { return m_timestamp; }
|
||||
|
||||
/** @brief Set the timestamp to the current time */
|
||||
void setTimeStamp() { m_timestamp = time(nullptr); }
|
||||
|
||||
/**
|
||||
* @brief Set the timestamp to the specified time
|
||||
* @param[in] t The timestamp value to set
|
||||
*/
|
||||
void setTimeStamp(time_t t) { m_timestamp = t; }
|
||||
# else
|
||||
time_t getTimeStamp() const { return 0; }
|
||||
void setTimeStamp() {}
|
||||
void setTimeStamp(time_t t) {}
|
||||
# endif
|
||||
|
||||
/**
|
||||
* @brief Set the value from a buffer
|
||||
* @param[in] value A pointer to a buffer containing the value.
|
||||
* @param[in] len The length of the value in bytes.
|
||||
* @returns True if successful.
|
||||
*/
|
||||
bool setValue(const uint8_t* value, uint16_t len);
|
||||
|
||||
/**
|
||||
* @brief Set value to the value of const char*.
|
||||
* @param [in] s A pointer to a const char value to set.
|
||||
* @param [in] len The length of the value in bytes, defaults to strlen(s).
|
||||
*/
|
||||
bool setValue(const char* s, uint16_t len = 0) {
|
||||
if (len == 0) {
|
||||
len = strlen(s);
|
||||
}
|
||||
return setValue(reinterpret_cast<const uint8_t*>(s), len);
|
||||
}
|
||||
|
||||
const NimBLEAttValue& getValue(time_t* timestamp = nullptr) const {
|
||||
if (timestamp != nullptr) {
|
||||
# if CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
|
||||
*timestamp = m_timestamp;
|
||||
# else
|
||||
*timestamp = 0;
|
||||
# endif
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Append data to the value.
|
||||
* @param[in] value A ponter to a data buffer with the value to append.
|
||||
* @param[in] len The length of the value to append in bytes.
|
||||
* @returns A reference to the appended NimBLEAttValue.
|
||||
*/
|
||||
NimBLEAttValue& append(const uint8_t* value, uint16_t len);
|
||||
|
||||
/*********************** Template Functions ************************/
|
||||
|
||||
# if __cplusplus < 201703L
|
||||
/**
|
||||
* @brief Template to set value to the value of <type\>val.
|
||||
* @param [in] v The <type\>value to set.
|
||||
* @details Only used for types without a `c_str()` and `length()` or `data()` and `size()` method.
|
||||
* <type\> size must be evaluatable by `sizeof()`.
|
||||
*/
|
||||
template <typename T>
|
||||
# ifdef _DOXYGEN_
|
||||
bool
|
||||
# else
|
||||
typename std::enable_if<!std::is_pointer<T>::value && !Has_c_str_length<T>::value && !Has_data_size<T>::value, bool>::type
|
||||
# endif
|
||||
setValue(const T& v) {
|
||||
return setValue(reinterpret_cast<const uint8_t*>(&v), sizeof(T));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Template to set value to the value of <type\>val.
|
||||
* @param [in] s The <type\>value to set.
|
||||
* @details Only used if the <type\> has a `c_str()` method.
|
||||
*/
|
||||
template <typename T>
|
||||
# ifdef _DOXYGEN_
|
||||
bool
|
||||
# else
|
||||
typename std::enable_if<Has_c_str_length<T>::value && !Has_data_size<T>::value, bool>::type
|
||||
# endif
|
||||
setValue(const T& s) {
|
||||
return setValue(reinterpret_cast<const uint8_t*>(s.c_str()), s.length());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Template to set value to the value of <type\>val.
|
||||
* @param [in] v The <type\>value to set.
|
||||
* @details Only used if the <type\> has a `data()` and `size()` method.
|
||||
*/
|
||||
template <typename T>
|
||||
# ifdef _DOXYGEN_
|
||||
bool
|
||||
# else
|
||||
typename std::enable_if<Has_data_size<T>::value, bool>::type
|
||||
# endif
|
||||
setValue(const T& v) {
|
||||
return setValue(reinterpret_cast<const uint8_t*>(v.data()), v.size());
|
||||
}
|
||||
|
||||
# else
|
||||
/**
|
||||
* @brief Template to set value to the value of <type\>val.
|
||||
* @param [in] s The <type\>value to set.
|
||||
* @note This function is only available if the type T is not a pointer.
|
||||
*/
|
||||
template <typename T>
|
||||
typename std::enable_if<!std::is_pointer<T>::value, bool>::type setValue(const T& s) {
|
||||
if constexpr (Has_data_size<T>::value) {
|
||||
return setValue(reinterpret_cast<const uint8_t*>(s.data()), s.size());
|
||||
} else if constexpr (Has_c_str_length<T>::value) {
|
||||
return setValue(reinterpret_cast<const uint8_t*>(s.c_str()), s.length());
|
||||
} else {
|
||||
return setValue(reinterpret_cast<const uint8_t*>(&s), sizeof(s));
|
||||
}
|
||||
}
|
||||
# endif
|
||||
|
||||
/**
|
||||
* @brief Template to return the value as a <type\>.
|
||||
* @tparam T The type to convert the data to.
|
||||
* @param [in] timestamp A pointer to a time_t struct to store the time the value was read.
|
||||
* @param [in] skipSizeCheck If true it will skip checking if the data size is less than\n
|
||||
* <tt>sizeof(<type\>)</tt>.
|
||||
* @return The data converted to <type\> or NULL if skipSizeCheck is false and the data is\n
|
||||
* less than <tt>sizeof(<type\>)</tt>.
|
||||
* @details <b>Use:</b> <tt>getValue<type>(×tamp, skipSizeCheck);</tt>
|
||||
*/
|
||||
template <typename T>
|
||||
T getValue(time_t* timestamp = nullptr, bool skipSizeCheck = false) const {
|
||||
if (!skipSizeCheck && size() < sizeof(T)) {
|
||||
return T();
|
||||
}
|
||||
if (timestamp != nullptr) {
|
||||
# if CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
|
||||
*timestamp = m_timestamp;
|
||||
# else
|
||||
*timestamp = 0;
|
||||
# endif
|
||||
}
|
||||
|
||||
return *(reinterpret_cast<const T*>(m_attr_value));
|
||||
}
|
||||
|
||||
/*********************** Operators ************************/
|
||||
|
||||
/** @brief Subscript operator */
|
||||
uint8_t operator[](int pos) const {
|
||||
NIMBLE_CPP_DEBUG_ASSERT(pos < m_attr_len);
|
||||
return m_attr_value[pos];
|
||||
}
|
||||
|
||||
/** @brief Operator; Get the value as a std::vector<uint8_t>. */
|
||||
operator std::vector<uint8_t>() const { return std::vector<uint8_t>(m_attr_value, m_attr_value + m_attr_len); }
|
||||
|
||||
/** @brief Operator; Get the value as a std::string. */
|
||||
operator std::string() const { return std::string(reinterpret_cast<char*>(m_attr_value), m_attr_len); }
|
||||
|
||||
/** @brief Operator; Get the value as a const uint8_t*. */
|
||||
operator const uint8_t*() const { return m_attr_value; }
|
||||
|
||||
/** @brief Operator; Append another NimBLEAttValue. */
|
||||
NimBLEAttValue& operator+=(const NimBLEAttValue& source) { return append(source.data(), source.size()); }
|
||||
|
||||
/** @brief Operator; Set the value from a std::string source. */
|
||||
NimBLEAttValue& operator=(const std::string& source) {
|
||||
setValue(reinterpret_cast<const uint8_t*>(&source[0]), source.size());
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @brief Move assignment operator */
|
||||
NimBLEAttValue& operator=(NimBLEAttValue&& source);
|
||||
|
||||
/** @brief Copy assignment operator */
|
||||
NimBLEAttValue& operator=(const NimBLEAttValue& source);
|
||||
|
||||
/** @brief Equality operator */
|
||||
bool operator==(const NimBLEAttValue& source) const {
|
||||
return (m_attr_len == source.size()) ? memcmp(m_attr_value, source.data(), m_attr_len) == 0 : false;
|
||||
}
|
||||
|
||||
/** @brief Inequality operator */
|
||||
bool operator!=(const NimBLEAttValue& source) const { return !(*this == source); }
|
||||
|
||||
# ifdef NIMBLE_CPP_ARDUINO_STRING_AVAILABLE
|
||||
/** @brief Operator; Get the value as an Arduino String value. */
|
||||
operator String() const { return String(reinterpret_cast<char*>(m_attr_value)); }
|
||||
# endif
|
||||
};
|
||||
|
||||
#endif /*(CONFIG_BT_ENABLED) */
|
||||
#endif /* NIMBLE_CPP_ATTVALUE_H_ */
|
@ -1,60 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020-2024 Ryan Powell <ryan@nable-embedded.io> and
|
||||
* esp-nimble-cpp, NimBLE-Arduino contributors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef NIMBLE_CPP_ATTRIBUTE_H_
|
||||
#define NIMBLE_CPP_ATTRIBUTE_H_
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && (defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) || defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL))
|
||||
|
||||
# include "NimBLEUUID.h"
|
||||
|
||||
/**
|
||||
* @brief A base class for BLE attributes.
|
||||
*/
|
||||
class NimBLEAttribute {
|
||||
public:
|
||||
/**
|
||||
* @brief Get the UUID of the attribute.
|
||||
* @return The UUID.
|
||||
*/
|
||||
const NimBLEUUID& getUUID() const { return m_uuid; }
|
||||
|
||||
/**
|
||||
* @brief Get the handle of the attribute.
|
||||
*/
|
||||
uint16_t getHandle() const { return m_handle; };
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Construct a new NimBLEAttribute object.
|
||||
* @param [in] handle The handle of the attribute.
|
||||
* @param [in] uuid The UUID of the attribute.
|
||||
*/
|
||||
NimBLEAttribute(const NimBLEUUID& uuid, uint16_t handle) : m_uuid{uuid}, m_handle{handle} {}
|
||||
|
||||
/**
|
||||
* @brief Destroy the NimBLEAttribute object.
|
||||
*/
|
||||
~NimBLEAttribute() = default;
|
||||
|
||||
const NimBLEUUID m_uuid{};
|
||||
uint16_t m_handle{0};
|
||||
};
|
||||
|
||||
#endif // CONFIG_BT_ENABLED && (CONFIG_BT_NIMBLE_ROLE_PERIPHERAL || CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
#endif // NIMBLE_CPP_ATTRIBUTE_H_
|
@ -1,46 +1,60 @@
|
||||
/*
|
||||
* Copyright 2020-2024 Ryan Powell <ryan@nable-embedded.io> and
|
||||
* esp-nimble-cpp, NimBLE-Arduino contributors.
|
||||
* NimBLEBeacon2.cpp
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* Created: on March 15 2020
|
||||
* Author H2zero
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Originally:
|
||||
*
|
||||
* 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.
|
||||
* BLEBeacon.cpp
|
||||
*
|
||||
* Created on: Jan 4, 2018
|
||||
* Author: kolban
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_NIMBLE_ENABLED)
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||
|
||||
#include <string.h>
|
||||
#include <algorithm>
|
||||
#include "NimBLEBeacon.h"
|
||||
# include "NimBLEUUID.h"
|
||||
#include "NimBLELog.h"
|
||||
|
||||
#define ENDIAN_CHANGE_U16(x) ((((x)&0xFF00)>>8) + (((x)&0xFF)<<8))
|
||||
|
||||
static const char* LOG_TAG = "NimBLEBeacon";
|
||||
|
||||
|
||||
/**
|
||||
* @brief Construct a default beacon object.
|
||||
*/
|
||||
NimBLEBeacon::NimBLEBeacon() {
|
||||
m_beaconData.manufacturerId = 0x4c00;
|
||||
m_beaconData.subType = 0x02;
|
||||
m_beaconData.subTypeLength = 0x15;
|
||||
m_beaconData.major = 0;
|
||||
m_beaconData.minor = 0;
|
||||
m_beaconData.signalPower = 0;
|
||||
memset(m_beaconData.proximityUUID, 0, sizeof(m_beaconData.proximityUUID));
|
||||
} // NimBLEBeacon
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieve the data that is being advertised.
|
||||
* @return The advertised data.
|
||||
*/
|
||||
const NimBLEBeacon::BeaconData& NimBLEBeacon::getData() {
|
||||
return m_beaconData;
|
||||
std::string NimBLEBeacon::getData() {
|
||||
return std::string((char*) &m_beaconData, sizeof(m_beaconData));
|
||||
} // getData
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the major value being advertised.
|
||||
* @return The major value advertised.
|
||||
*/
|
||||
uint16_t NimBLEBeacon::getMajor() {
|
||||
return m_beaconData.major;
|
||||
} // getMajor
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the manufacturer ID being advertised.
|
||||
@ -48,7 +62,8 @@ uint16_t NimBLEBeacon::getMajor() {
|
||||
*/
|
||||
uint16_t NimBLEBeacon::getManufacturerId() {
|
||||
return m_beaconData.manufacturerId;
|
||||
} // getManufacturerId
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the minor value being advertised.
|
||||
@ -56,15 +71,17 @@ uint16_t NimBLEBeacon::getManufacturerId() {
|
||||
*/
|
||||
uint16_t NimBLEBeacon::getMinor() {
|
||||
return m_beaconData.minor;
|
||||
} // getMinor
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the proximity UUID being advertised.
|
||||
* @return The UUID advertised.
|
||||
*/
|
||||
NimBLEUUID NimBLEBeacon::getProximityUUID() {
|
||||
return NimBLEUUID(m_beaconData.proximityUUID, 16).reverseByteOrder();
|
||||
} // getProximityUUID
|
||||
return NimBLEUUID(m_beaconData.proximityUUID, 16, true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the signal power being advertised.
|
||||
@ -72,28 +89,22 @@ NimBLEUUID NimBLEBeacon::getProximityUUID() {
|
||||
*/
|
||||
int8_t NimBLEBeacon::getSignalPower() {
|
||||
return m_beaconData.signalPower;
|
||||
} // getSignalPower
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the beacon data.
|
||||
* @param [in] data A pointer to the raw data that the beacon should advertise.
|
||||
* @param [in] length The length of the data.
|
||||
* @brief Set the raw data for the beacon record.
|
||||
* @param [in] data The raw beacon data.
|
||||
*/
|
||||
void NimBLEBeacon::setData(const uint8_t* data, uint8_t length) {
|
||||
if (length != sizeof(BeaconData)) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Data length must be %d bytes, sent: %d", sizeof(BeaconData), length);
|
||||
void NimBLEBeacon::setData(const std::string &data) {
|
||||
if (data.length() != sizeof(m_beaconData)) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Unable to set the data ... length passed in was %d and expected %d",
|
||||
data.length(), sizeof(m_beaconData));
|
||||
return;
|
||||
}
|
||||
memcpy(&m_beaconData, data, length);
|
||||
memcpy(&m_beaconData, data.data(), sizeof(m_beaconData));
|
||||
} // setData
|
||||
|
||||
/**
|
||||
* @brief Set the beacon data.
|
||||
* @param [in] data The data that the beacon should advertise.
|
||||
*/
|
||||
void NimBLEBeacon::setData(const NimBLEBeacon::BeaconData& data) {
|
||||
m_beaconData = data;
|
||||
} // setData
|
||||
|
||||
/**
|
||||
* @brief Set the major value.
|
||||
@ -103,6 +114,7 @@ void NimBLEBeacon::setMajor(uint16_t major) {
|
||||
m_beaconData.major = ENDIAN_CHANGE_U16(major);
|
||||
} // setMajor
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the manufacturer ID.
|
||||
* @param [in] manufacturerId The manufacturer ID value.
|
||||
@ -111,13 +123,15 @@ void NimBLEBeacon::setManufacturerId(uint16_t manufacturerId) {
|
||||
m_beaconData.manufacturerId = ENDIAN_CHANGE_U16(manufacturerId);
|
||||
} // setManufacturerId
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the minor value.
|
||||
* @param [in] minor The minor value.
|
||||
*/
|
||||
void NimBLEBeacon::setMinor(uint16_t minor) {
|
||||
m_beaconData.minor = ENDIAN_CHANGE_U16(minor);
|
||||
} // setMinor
|
||||
} // setMinior
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the proximity UUID.
|
||||
@ -126,10 +140,12 @@ void NimBLEBeacon::setMinor(uint16_t minor) {
|
||||
void NimBLEBeacon::setProximityUUID(const NimBLEUUID &uuid) {
|
||||
NimBLEUUID temp_uuid = uuid;
|
||||
temp_uuid.to128();
|
||||
temp_uuid.reverseByteOrder();
|
||||
memcpy(m_beaconData.proximityUUID, temp_uuid.getValue(), 16);
|
||||
std::reverse_copy(temp_uuid.getNative()->u128.value,
|
||||
temp_uuid.getNative()->u128.value + 16,
|
||||
m_beaconData.proximityUUID);
|
||||
} // setProximityUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the signal power.
|
||||
* @param [in] signalPower The signal power value.
|
||||
@ -138,4 +154,4 @@ void NimBLEBeacon::setSignalPower(int8_t signalPower) {
|
||||
m_beaconData.signalPower = signalPower;
|
||||
} // setSignalPower
|
||||
|
||||
#endif // CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER
|
||||
#endif
|
||||
|
@ -1,64 +1,53 @@
|
||||
/*
|
||||
* Copyright 2020-2024 Ryan Powell <ryan@nable-embedded.io> and
|
||||
* esp-nimble-cpp, NimBLE-Arduino contributors.
|
||||
* NimBLEBeacon2.h
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* Created: on March 15 2020
|
||||
* Author H2zero
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Originally:
|
||||
*
|
||||
* 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.
|
||||
* BLEBeacon2.h
|
||||
*
|
||||
* Created on: Jan 4, 2018
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef NIMBLE_CPP_BEACON_H_
|
||||
#define NIMBLE_CPP_BEACON_H_
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||
|
||||
class NimBLEUUID;
|
||||
|
||||
# include <cstdint>
|
||||
#ifndef MAIN_NIMBLEBEACON_H_
|
||||
#define MAIN_NIMBLEBEACON_H_
|
||||
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_NIMBLE_ENABLED)
|
||||
#include "NimBLEUUID.h"
|
||||
/**
|
||||
* @brief Representation of a beacon.
|
||||
* See:
|
||||
* * https://en.wikipedia.org/wiki/IBeacon
|
||||
*/
|
||||
class NimBLEBeacon {
|
||||
private:
|
||||
struct {
|
||||
uint16_t manufacturerId;
|
||||
uint8_t subType;
|
||||
uint8_t subTypeLength;
|
||||
uint8_t proximityUUID[16];
|
||||
uint16_t major;
|
||||
uint16_t minor;
|
||||
int8_t signalPower;
|
||||
} __attribute__((packed)) m_beaconData;
|
||||
public:
|
||||
struct BeaconData {
|
||||
uint16_t manufacturerId{0x4c00};
|
||||
uint8_t subType{0x02};
|
||||
uint8_t subTypeLength{0x15};
|
||||
uint8_t proximityUUID[16]{};
|
||||
uint16_t major{};
|
||||
uint16_t minor{};
|
||||
int8_t signalPower{};
|
||||
} __attribute__((packed));
|
||||
|
||||
const BeaconData& getData();
|
||||
NimBLEBeacon();
|
||||
std::string getData();
|
||||
uint16_t getMajor();
|
||||
uint16_t getMinor();
|
||||
uint16_t getManufacturerId();
|
||||
NimBLEUUID getProximityUUID();
|
||||
int8_t getSignalPower();
|
||||
void setData(const uint8_t* data, uint8_t length);
|
||||
void setData(const BeaconData& data);
|
||||
void setData(const std::string &data);
|
||||
void setMajor(uint16_t major);
|
||||
void setMinor(uint16_t minor);
|
||||
void setManufacturerId(uint16_t manufacturerId);
|
||||
void setProximityUUID(const NimBLEUUID &uuid);
|
||||
void setSignalPower(int8_t signalPower);
|
||||
|
||||
private:
|
||||
BeaconData m_beaconData;
|
||||
}; // NimBLEBeacon
|
||||
|
||||
#endif // NIMBLE_CPP_BEACON_H_
|
||||
#endif // CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL
|
||||
#endif
|
||||
#endif /* MAIN_NIMBLEBEACON_H_ */
|
||||
|
@ -1,179 +1,134 @@
|
||||
/*
|
||||
* Copyright 2020-2024 Ryan Powell <ryan@nable-embedded.io> and
|
||||
* esp-nimble-cpp, NimBLE-Arduino contributors.
|
||||
* NimBLECharacteristic.cpp
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* Created: on March 3, 2020
|
||||
* Author H2zero
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* BLECharacteristic.cpp
|
||||
*
|
||||
* 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.
|
||||
* Created on: Jun 22, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
|
||||
#include "NimBLECharacteristic.h"
|
||||
#include "NimBLE2904.h"
|
||||
#include "NimBLEDevice.h"
|
||||
#include "NimBLELog.h"
|
||||
|
||||
#define NULL_HANDLE (0xffff)
|
||||
#define NIMBLE_SUB_NOTIFY 0x0001
|
||||
#define NIMBLE_SUB_INDICATE 0x0002
|
||||
|
||||
static NimBLECharacteristicCallbacks defaultCallback;
|
||||
static const char* LOG_TAG = "NimBLECharacteristic";
|
||||
|
||||
|
||||
/**
|
||||
* @brief Construct a characteristic
|
||||
* @param [in] uuid - UUID (const char*) for the characteristic.
|
||||
* @param [in] properties - Properties for the characteristic.
|
||||
* @param [in] maxLen - The maximum length in bytes that the characteristic value can hold. (Default: 512 bytes for esp32, 20 for all others).
|
||||
* @param [in] pService - pointer to the service instance this characteristic belongs to.
|
||||
*/
|
||||
NimBLECharacteristic::NimBLECharacteristic(const char* uuid, uint16_t properties, uint16_t maxLen, NimBLEService* pService)
|
||||
: NimBLECharacteristic(NimBLEUUID(uuid), properties, maxLen, pService) {}
|
||||
NimBLECharacteristic::NimBLECharacteristic(const char* uuid, uint16_t properties, NimBLEService* pService)
|
||||
: NimBLECharacteristic(NimBLEUUID(uuid), properties, pService) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a characteristic
|
||||
* @param [in] uuid - UUID for the characteristic.
|
||||
* @param [in] properties - Properties for the characteristic.
|
||||
* @param [in] maxLen - The maximum length in bytes that the characteristic value can hold. (Default: 512 bytes for esp32, 20 for all others).
|
||||
* @param [in] pService - pointer to the service instance this characteristic belongs to.
|
||||
*/
|
||||
NimBLECharacteristic::NimBLECharacteristic(const NimBLEUUID& uuid, uint16_t properties, uint16_t maxLen, NimBLEService* pService)
|
||||
: NimBLELocalValueAttribute{uuid, 0, maxLen}, m_pCallbacks{&defaultCallback}, m_pService{pService} {
|
||||
setProperties(properties);
|
||||
NimBLECharacteristic::NimBLECharacteristic(const NimBLEUUID &uuid, uint16_t properties, NimBLEService* pService) {
|
||||
m_uuid = uuid;
|
||||
m_handle = NULL_HANDLE;
|
||||
m_properties = properties;
|
||||
m_pCallbacks = &defaultCallback;
|
||||
m_pService = pService;
|
||||
m_value = "";
|
||||
m_valMux = portMUX_INITIALIZER_UNLOCKED;
|
||||
m_timestamp = 0;
|
||||
} // NimBLECharacteristic
|
||||
|
||||
/**
|
||||
* @brief Destructor.
|
||||
*/
|
||||
NimBLECharacteristic::~NimBLECharacteristic() {
|
||||
for (const auto& dsc : m_vDescriptors) {
|
||||
delete dsc;
|
||||
for(auto &it : m_dscVec) {
|
||||
delete it;
|
||||
}
|
||||
} // ~NimBLECharacteristic
|
||||
|
||||
/**
|
||||
* @brief Create a new BLE Descriptor associated with this characteristic.
|
||||
* @param [in] uuid - The UUID of the descriptor.
|
||||
* @param [in] properties - The properties of the descriptor.
|
||||
* @param [in] maxLen - The max length in bytes of the descriptor value.
|
||||
* @return The new BLE descriptor.
|
||||
*/
|
||||
NimBLEDescriptor* NimBLECharacteristic::createDescriptor(const char* uuid, uint32_t properties, uint16_t maxLen) {
|
||||
return createDescriptor(NimBLEUUID(uuid), properties, maxLen);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a new BLE Descriptor associated with this characteristic.
|
||||
* @param [in] uuid - The UUID of the descriptor.
|
||||
* @param [in] properties - The properties of the descriptor.
|
||||
* @param [in] maxLen - The max length in bytes of the descriptor value.
|
||||
* @param [in] max_len - The max length in bytes of the descriptor value.
|
||||
* @return The new BLE descriptor.
|
||||
*/
|
||||
NimBLEDescriptor* NimBLECharacteristic::createDescriptor(const NimBLEUUID& uuid, uint32_t properties, uint16_t maxLen) {
|
||||
NimBLEDescriptor* NimBLECharacteristic::createDescriptor(const char* uuid, uint32_t properties, uint16_t max_len) {
|
||||
return createDescriptor(NimBLEUUID(uuid), properties, max_len);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a new BLE Descriptor associated with this characteristic.
|
||||
* @param [in] uuid - The UUID of the descriptor.
|
||||
* @param [in] properties - The properties of the descriptor.
|
||||
* @param [in] max_len - The max length in bytes of the descriptor value.
|
||||
* @return The new BLE descriptor.
|
||||
*/
|
||||
NimBLEDescriptor* NimBLECharacteristic::createDescriptor(const NimBLEUUID &uuid, uint32_t properties, uint16_t max_len) {
|
||||
NimBLEDescriptor* pDescriptor = nullptr;
|
||||
if (uuid == NimBLEUUID(static_cast<uint16_t>(0x2904))) {
|
||||
NIMBLE_LOGW(LOG_TAG, "0x2904 descriptor should be created with create2904()");
|
||||
pDescriptor = create2904();
|
||||
if(uuid == NimBLEUUID(uint16_t(0x2902))) {
|
||||
assert(0 && "0x2902 descriptors cannot be manually created");
|
||||
} else if (uuid == NimBLEUUID(uint16_t(0x2904))) {
|
||||
pDescriptor = new NimBLE2904(this);
|
||||
} else {
|
||||
pDescriptor = new NimBLEDescriptor(uuid, properties, maxLen, this);
|
||||
pDescriptor = new NimBLEDescriptor(uuid, properties, max_len, this);
|
||||
}
|
||||
|
||||
addDescriptor(pDescriptor);
|
||||
|
||||
return pDescriptor;
|
||||
} // createDescriptor
|
||||
|
||||
/**
|
||||
* @brief Create a Characteristic Presentation Format Descriptor for this characteristic.
|
||||
* @return A pointer to a NimBLE2904 descriptor.
|
||||
*/
|
||||
NimBLE2904* NimBLECharacteristic::create2904() {
|
||||
NimBLE2904* pDescriptor = new NimBLE2904(this);
|
||||
addDescriptor(pDescriptor);
|
||||
return pDescriptor;
|
||||
} // create2904
|
||||
|
||||
/**
|
||||
* @brief Add a descriptor to the characteristic.
|
||||
* @param [in] pDescriptor A pointer to the descriptor to add.
|
||||
* @param [in] A pointer to the descriptor to add.
|
||||
*/
|
||||
void NimBLECharacteristic::addDescriptor(NimBLEDescriptor *pDescriptor) {
|
||||
bool foundRemoved = false;
|
||||
if (pDescriptor->getRemoved() > 0) {
|
||||
for (const auto& dsc : m_vDescriptors) {
|
||||
if (dsc == pDescriptor) {
|
||||
foundRemoved = true;
|
||||
pDescriptor->setRemoved(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the descriptor is already in the vector and if so, return.
|
||||
for (const auto& dsc : m_vDescriptors) {
|
||||
if (dsc == pDescriptor) {
|
||||
pDescriptor->setCharacteristic(this); // Update the characteristic pointer in the descriptor.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundRemoved) {
|
||||
m_vDescriptors.push_back(pDescriptor);
|
||||
}
|
||||
|
||||
pDescriptor->setCharacteristic(this);
|
||||
NimBLEDevice::getServer()->serviceChanged();
|
||||
m_dscVec.push_back(pDescriptor);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Remove a descriptor from the characteristic.
|
||||
* @param[in] pDescriptor A pointer to the descriptor instance to remove from the characteristic.
|
||||
* @param[in] deleteDsc If true it will delete the descriptor instance and free it's resources.
|
||||
*/
|
||||
void NimBLECharacteristic::removeDescriptor(NimBLEDescriptor* pDescriptor, bool deleteDsc) {
|
||||
// Check if the descriptor was already removed and if so, check if this
|
||||
// is being called to delete the object and do so if requested.
|
||||
// Otherwise, ignore the call and return.
|
||||
if (pDescriptor->getRemoved() > 0) {
|
||||
if (deleteDsc) {
|
||||
for (auto it = m_vDescriptors.begin(); it != m_vDescriptors.end(); ++it) {
|
||||
if ((*it) == pDescriptor) {
|
||||
delete (*it);
|
||||
m_vDescriptors.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
pDescriptor->setRemoved(deleteDsc ? NIMBLE_ATT_REMOVE_DELETE : NIMBLE_ATT_REMOVE_HIDE);
|
||||
NimBLEDevice::getServer()->serviceChanged();
|
||||
} // removeDescriptor
|
||||
|
||||
/**
|
||||
* @brief Return the BLE Descriptor for the given UUID.
|
||||
* @param [in] uuid The UUID of the descriptor.
|
||||
* @return A pointer to the descriptor object or nullptr if not found.
|
||||
*/
|
||||
NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const char* uuid) const {
|
||||
NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const char* uuid) {
|
||||
return getDescriptorByUUID(NimBLEUUID(uuid));
|
||||
} // getDescriptorByUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return the BLE Descriptor for the given UUID.
|
||||
* @param [in] uuid The UUID of the descriptor.
|
||||
* @return A pointer to the descriptor object or nullptr if not found.
|
||||
*/
|
||||
NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const NimBLEUUID& uuid) const {
|
||||
for (const auto& dsc : m_vDescriptors) {
|
||||
if (dsc->getUUID() == uuid) {
|
||||
return dsc;
|
||||
NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const NimBLEUUID &uuid) {
|
||||
for (auto &it : m_dscVec) {
|
||||
if (it->getUUID() == uuid) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
@ -184,136 +139,312 @@ NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const NimBLEUUID& uu
|
||||
* @param [in] handle The handle of the descriptor.
|
||||
* @return A pointer to the descriptor object or nullptr if not found.
|
||||
*/
|
||||
NimBLEDescriptor* NimBLECharacteristic::getDescriptorByHandle(uint16_t handle) const {
|
||||
for (const auto& dsc : m_vDescriptors) {
|
||||
if (dsc->getHandle() == handle) {
|
||||
return dsc;
|
||||
NimBLEDescriptor *NimBLECharacteristic::getDescriptorByHandle(uint16_t handle) {
|
||||
for (auto &it : m_dscVec) {
|
||||
if (it->getHandle() == handle) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
} // getDescriptorByHandle
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the handle of the characteristic.
|
||||
* @return The handle of the characteristic.
|
||||
*/
|
||||
uint16_t NimBLECharacteristic::getHandle() {
|
||||
return m_handle;
|
||||
} // getHandle
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the properties of the characteristic.
|
||||
* @return The properties of the characteristic.
|
||||
*/
|
||||
uint16_t NimBLECharacteristic::getProperties() const {
|
||||
uint16_t NimBLECharacteristic::getProperties() {
|
||||
return m_properties;
|
||||
} // getProperties
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the service that owns this characteristic.
|
||||
* @brief Get the service associated with this characteristic.
|
||||
*/
|
||||
NimBLEService* NimBLECharacteristic::getService() const {
|
||||
NimBLEService* NimBLECharacteristic::getService() {
|
||||
return m_pService;
|
||||
} // getService
|
||||
|
||||
|
||||
void NimBLECharacteristic::setService(NimBLEService *pService) {
|
||||
m_pService = pService;
|
||||
} // setService
|
||||
|
||||
/**
|
||||
* @brief Send an indication.
|
||||
* @param[in] connHandle Connection handle to send an individual indication, or BLE_HS_CONN_HANDLE_NONE to send
|
||||
* the indication to all subscribed clients.
|
||||
* @return True if the indication was sent successfully, false otherwise.
|
||||
*/
|
||||
bool NimBLECharacteristic::indicate(uint16_t connHandle) const {
|
||||
return sendValue(nullptr, 0, false, connHandle);
|
||||
} // indicate
|
||||
|
||||
/**
|
||||
* @brief Send an indication.
|
||||
* @param[in] value A pointer to the data to send.
|
||||
* @param[in] length The length of the data to send.
|
||||
* @param[in] connHandle Connection handle to send an individual indication, or BLE_HS_CONN_HANDLE_NONE to send
|
||||
* the indication to all subscribed clients.
|
||||
* @return True if the indication was sent successfully, false otherwise.
|
||||
*/
|
||||
bool NimBLECharacteristic::indicate(const uint8_t* value, size_t length, uint16_t connHandle) const {
|
||||
return sendValue(value, length, false, connHandle);
|
||||
} // indicate
|
||||
|
||||
/**
|
||||
* @brief Send a notification.
|
||||
* @param[in] connHandle Connection handle to send an individual notification, or BLE_HS_CONN_HANDLE_NONE to send
|
||||
* the notification to all subscribed clients.
|
||||
* @return True if the notification was sent successfully, false otherwise.
|
||||
*/
|
||||
bool NimBLECharacteristic::notify(uint16_t connHandle) const {
|
||||
return sendValue(nullptr, 0, true, connHandle);
|
||||
} // notify
|
||||
|
||||
/**
|
||||
* @brief Send a notification.
|
||||
* @param[in] value A pointer to the data to send.
|
||||
* @param[in] length The length of the data to send.
|
||||
* @param[in] connHandle Connection handle to send an individual notification, or BLE_HS_CONN_HANDLE_NONE to send
|
||||
* the notification to all subscribed clients.
|
||||
* @return True if the notification was sent successfully, false otherwise.
|
||||
*/
|
||||
bool NimBLECharacteristic::notify(const uint8_t* value, size_t length, uint16_t connHandle) const {
|
||||
return sendValue(value, length, true, connHandle);
|
||||
} // indicate
|
||||
|
||||
/**
|
||||
* @brief Sends a notification or indication.
|
||||
* @param[in] value A pointer to the data to send.
|
||||
* @param[in] length The length of the data to send.
|
||||
* @param[in] isNotification if true sends a notification, false sends an indication.
|
||||
* @param[in] connHandle Connection handle to send to a specific peer.
|
||||
* @return True if the value was sent successfully, false otherwise.
|
||||
*/
|
||||
bool NimBLECharacteristic::sendValue(const uint8_t* value, size_t length, bool isNotification, uint16_t connHandle) const {
|
||||
int rc = 0;
|
||||
|
||||
if (value != nullptr && length > 0) { // custom notification value
|
||||
// Notify all connected peers unless a specific handle is provided
|
||||
for (const auto& ch : NimBLEDevice::getServer()->getPeerDevices()) {
|
||||
if (connHandle != BLE_HS_CONN_HANDLE_NONE && ch != connHandle) {
|
||||
continue; // only send to the specific handle, minor inefficiency but saves code.
|
||||
}
|
||||
|
||||
// Must re-create the data buffer on each iteration because it is freed by the calls bellow.
|
||||
os_mbuf* om = ble_hs_mbuf_from_flat(value, length);
|
||||
if (!om) {
|
||||
NIMBLE_LOGE(LOG_TAG, "<< sendValue: failed to allocate mbuf");
|
||||
return false;
|
||||
|
||||
/**
|
||||
* @brief Get the UUID of the characteristic.
|
||||
* @return The UUID of the characteristic.
|
||||
*/
|
||||
NimBLEUUID NimBLECharacteristic::getUUID() {
|
||||
return m_uuid;
|
||||
} // getUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieve the current value of the characteristic.
|
||||
* @return A std::string containing the current characteristic value.
|
||||
*/
|
||||
std::string NimBLECharacteristic::getValue(time_t *timestamp) {
|
||||
portENTER_CRITICAL(&m_valMux);
|
||||
std::string retVal = m_value;
|
||||
if(timestamp != nullptr) {
|
||||
*timestamp = m_timestamp;
|
||||
}
|
||||
portEXIT_CRITICAL(&m_valMux);
|
||||
|
||||
return retVal;
|
||||
} // getValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieve the the current data length of the characteristic.
|
||||
* @return The length of the current characteristic data.
|
||||
*/
|
||||
size_t NimBLECharacteristic::getDataLength() {
|
||||
portENTER_CRITICAL(&m_valMux);
|
||||
size_t len = m_value.length();
|
||||
portEXIT_CRITICAL(&m_valMux);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
if (isNotification) {
|
||||
rc = ble_gattc_notify_custom(ch, m_handle, om);
|
||||
} else {
|
||||
rc = ble_gattc_indicate_custom(ch, m_handle, om);
|
||||
|
||||
/**
|
||||
* @brief STATIC callback to handle events from the NimBLE stack.
|
||||
*/
|
||||
int NimBLECharacteristic::handleGapEvent(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt,
|
||||
void *arg)
|
||||
{
|
||||
const ble_uuid_t *uuid;
|
||||
int rc;
|
||||
struct ble_gap_conn_desc desc;
|
||||
NimBLECharacteristic* pCharacteristic = (NimBLECharacteristic*)arg;
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "Characteristic %s %s event", pCharacteristic->getUUID().toString().c_str(),
|
||||
ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR ? "Read" : "Write");
|
||||
|
||||
uuid = ctxt->chr->uuid;
|
||||
if(ble_uuid_cmp(uuid, &pCharacteristic->getUUID().getNative()->u) == 0){
|
||||
switch(ctxt->op) {
|
||||
case BLE_GATT_ACCESS_OP_READ_CHR: {
|
||||
// If the packet header is only 8 bytes this is a follow up of a long read
|
||||
// so we don't want to call the onRead() callback again.
|
||||
if(ctxt->om->om_pkthdr_len > 8) {
|
||||
rc = ble_gap_conn_find(conn_handle, &desc);
|
||||
assert(rc == 0);
|
||||
pCharacteristic->m_pCallbacks->onRead(pCharacteristic);
|
||||
pCharacteristic->m_pCallbacks->onRead(pCharacteristic, &desc);
|
||||
}
|
||||
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "<< sendValue: failed to send value, rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
|
||||
portENTER_CRITICAL(&pCharacteristic->m_valMux);
|
||||
rc = os_mbuf_append(ctxt->om, (uint8_t*)pCharacteristic->m_value.data(),
|
||||
pCharacteristic->m_value.length());
|
||||
portEXIT_CRITICAL(&pCharacteristic->m_valMux);
|
||||
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
|
||||
case BLE_GATT_ACCESS_OP_WRITE_CHR: {
|
||||
if (ctxt->om->om_len > BLE_ATT_ATTR_MAX_LEN) {
|
||||
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||
}
|
||||
|
||||
uint8_t buf[BLE_ATT_ATTR_MAX_LEN];
|
||||
size_t len = ctxt->om->om_len;
|
||||
memcpy(buf, ctxt->om->om_data,len);
|
||||
|
||||
os_mbuf *next;
|
||||
next = SLIST_NEXT(ctxt->om, om_next);
|
||||
while(next != NULL){
|
||||
if((len + next->om_len) > BLE_ATT_ATTR_MAX_LEN) {
|
||||
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||
}
|
||||
memcpy(&buf[len], next->om_data, next->om_len);
|
||||
len += next->om_len;
|
||||
next = SLIST_NEXT(next, om_next);
|
||||
}
|
||||
rc = ble_gap_conn_find(conn_handle, &desc);
|
||||
assert(rc == 0);
|
||||
pCharacteristic->setValue(buf, len);
|
||||
pCharacteristic->m_pCallbacks->onWrite(pCharacteristic);
|
||||
pCharacteristic->m_pCallbacks->onWrite(pCharacteristic, &desc);
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (connHandle != BLE_HS_CONN_HANDLE_NONE) { // only sending to specific peer
|
||||
// Null buffer will read the value from the characteristic
|
||||
if (isNotification) {
|
||||
rc = ble_gattc_notify_custom(connHandle, m_handle, NULL);
|
||||
|
||||
return BLE_ATT_ERR_UNLIKELY;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the number of clients subscribed to the characteristic.
|
||||
* @returns Number of clients subscribed to notifications / indications.
|
||||
*/
|
||||
size_t NimBLECharacteristic::getSubscribedCount() {
|
||||
return m_subscribedVec.size();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the subscribe status for this characteristic.\n
|
||||
* This will maintain a vector of subscribed clients and their indicate/notify status.
|
||||
*/
|
||||
void NimBLECharacteristic::setSubscribe(struct ble_gap_event *event) {
|
||||
ble_gap_conn_desc desc;
|
||||
if(ble_gap_conn_find(event->subscribe.conn_handle, &desc) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t subVal = 0;
|
||||
if(event->subscribe.cur_notify > 0 && (m_properties & NIMBLE_PROPERTY::NOTIFY)) {
|
||||
subVal |= NIMBLE_SUB_NOTIFY;
|
||||
}
|
||||
if(event->subscribe.cur_indicate && (m_properties & NIMBLE_PROPERTY::INDICATE)) {
|
||||
subVal |= NIMBLE_SUB_INDICATE;
|
||||
}
|
||||
|
||||
NIMBLE_LOGI(LOG_TAG, "New subscribe value for conn: %d val: %d",
|
||||
event->subscribe.conn_handle, subVal);
|
||||
|
||||
if(!event->subscribe.cur_indicate && event->subscribe.prev_indicate) {
|
||||
NimBLEDevice::getServer()->clearIndicateWait(event->subscribe.conn_handle);
|
||||
}
|
||||
|
||||
|
||||
auto it = m_subscribedVec.begin();
|
||||
for(;it != m_subscribedVec.end(); ++it) {
|
||||
if((*it).first == event->subscribe.conn_handle) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(subVal > 0) {
|
||||
if(it == m_subscribedVec.end()) {
|
||||
m_subscribedVec.push_back({event->subscribe.conn_handle, subVal});
|
||||
} else {
|
||||
rc = ble_gattc_indicate_custom(connHandle, m_handle, NULL);
|
||||
(*it).second = subVal;
|
||||
}
|
||||
} else { // Notify or indicate to all connected peers the characteristic value
|
||||
ble_gatts_chr_updated(m_handle);
|
||||
} else if(it != m_subscribedVec.end()) {
|
||||
m_subscribedVec.erase(it);
|
||||
}
|
||||
|
||||
return rc == 0;
|
||||
} // sendValue
|
||||
m_pCallbacks->onSubscribe(this, &desc, subVal);
|
||||
}
|
||||
|
||||
void NimBLECharacteristic::readEvent(NimBLEConnInfo& connInfo) {
|
||||
m_pCallbacks->onRead(this, connInfo);
|
||||
} // readEvent
|
||||
|
||||
void NimBLECharacteristic::writeEvent(const uint8_t* val, uint16_t len, NimBLEConnInfo& connInfo) {
|
||||
setValue(val, len);
|
||||
m_pCallbacks->onWrite(this, connInfo);
|
||||
} // writeEvent
|
||||
/**
|
||||
* @brief Send an indication.\n
|
||||
* An indication is a transmission of up to the first 20 bytes of the characteristic value.\n
|
||||
* An indication will block waiting for a positive confirmation from the client.
|
||||
*/
|
||||
void NimBLECharacteristic::indicate() {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> indicate: length: %d", getDataLength());
|
||||
notify(false);
|
||||
NIMBLE_LOGD(LOG_TAG, "<< indicate");
|
||||
} // indicate
|
||||
|
||||
/**
|
||||
* @brief Send a notification.\n
|
||||
* A notification is a transmission of up to the first 20 bytes of the characteristic value.\n
|
||||
* A notification will not block; it is a fire and forget.
|
||||
* @param[in] is_notification if true sends a notification, false sends an indication.
|
||||
*/
|
||||
void NimBLECharacteristic::notify(bool is_notification) {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> notify: length: %d", getDataLength());
|
||||
|
||||
|
||||
if(!(m_properties & NIMBLE_PROPERTY::NOTIFY) &&
|
||||
!(m_properties & NIMBLE_PROPERTY::INDICATE))
|
||||
{
|
||||
NIMBLE_LOGE(LOG_TAG,
|
||||
"<< notify-Error; Notify/indicate not enabled for characterisitc: %s",
|
||||
std::string(getUUID()).c_str());
|
||||
}
|
||||
|
||||
if (m_subscribedVec.size() == 0) {
|
||||
NIMBLE_LOGD(LOG_TAG, "<< notify: No clients subscribed.");
|
||||
return;
|
||||
}
|
||||
|
||||
m_pCallbacks->onNotify(this);
|
||||
|
||||
std::string value = getValue();
|
||||
size_t length = value.length();
|
||||
bool reqSec = (m_properties & BLE_GATT_CHR_F_READ_AUTHEN) ||
|
||||
(m_properties & BLE_GATT_CHR_F_READ_AUTHOR) ||
|
||||
(m_properties & BLE_GATT_CHR_F_READ_ENC);
|
||||
int rc = 0;
|
||||
|
||||
for (auto &it : m_subscribedVec) {
|
||||
uint16_t _mtu = getService()->getServer()->getPeerMTU(it.first);
|
||||
|
||||
// check if connected and subscribed
|
||||
if(_mtu == 0 || it.second == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// check if security requirements are satisfied
|
||||
if(reqSec) {
|
||||
struct ble_gap_conn_desc desc;
|
||||
rc = ble_gap_conn_find(it.first, &desc);
|
||||
if(rc != 0 || !desc.sec_state.encrypted) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (length > _mtu - 3) {
|
||||
NIMBLE_LOGW(LOG_TAG, "- Truncating to %d bytes (maximum notify size)", _mtu - 3);
|
||||
}
|
||||
|
||||
if(is_notification && (!(it.second & NIMBLE_SUB_NOTIFY))) {
|
||||
NIMBLE_LOGW(LOG_TAG,
|
||||
"Sending notification to client subscribed to indications, sending indication instead");
|
||||
is_notification = false;
|
||||
}
|
||||
|
||||
if(!is_notification && (!(it.second & NIMBLE_SUB_INDICATE))) {
|
||||
NIMBLE_LOGW(LOG_TAG,
|
||||
"Sending indication to client subscribed to notification, sending notification instead");
|
||||
is_notification = true;
|
||||
}
|
||||
|
||||
// don't create the m_buf until we are sure to send the data or else
|
||||
// we could be allocating a buffer that doesn't get released.
|
||||
// We also must create it in each loop iteration because it is consumed with each host call.
|
||||
os_mbuf *om = ble_hs_mbuf_from_flat((uint8_t*)value.data(), length);
|
||||
|
||||
if(!is_notification && (m_properties & NIMBLE_PROPERTY::INDICATE)) {
|
||||
if(!NimBLEDevice::getServer()->setIndicateWait(it.first)) {
|
||||
NIMBLE_LOGE(LOG_TAG, "prior Indication in progress");
|
||||
os_mbuf_free_chain(om);
|
||||
return;
|
||||
}
|
||||
|
||||
rc = ble_gattc_indicate_custom(it.first, m_handle, om);
|
||||
if(rc != 0){
|
||||
NimBLEDevice::getServer()->clearIndicateWait(it.first);
|
||||
}
|
||||
} else {
|
||||
ble_gattc_notify_custom(it.first, m_handle, om);
|
||||
}
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< notify");
|
||||
} // Notify
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the callback handlers for this characteristic.
|
||||
@ -331,18 +462,56 @@ void NimBLECharacteristic::setCallbacks(NimBLECharacteristicCallbacks* pCallback
|
||||
/**
|
||||
* @brief Get the callback handlers for this characteristic.
|
||||
*/
|
||||
NimBLECharacteristicCallbacks* NimBLECharacteristic::getCallbacks() const {
|
||||
NimBLECharacteristicCallbacks* NimBLECharacteristic::getCallbacks() {
|
||||
return m_pCallbacks;
|
||||
} //getCallbacks
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the value of the characteristic.
|
||||
* @param [in] data The data to set for the characteristic.
|
||||
* @param [in] length The length of the data in bytes.
|
||||
*/
|
||||
void NimBLECharacteristic::setValue(const uint8_t* data, size_t length) {
|
||||
#if CONFIG_LOG_DEFAULT_LEVEL > 3 || (ARDUINO_ARCH_ESP32 && !defined(DONT_USE_ARDUINO_BULLSHIT) && CORE_DEBUG_LEVEL >= 4)
|
||||
char* pHex = NimBLEUtils::buildHexData(nullptr, data, length);
|
||||
NIMBLE_LOGD(LOG_TAG, ">> setValue: length=%d, data=%s, characteristic UUID=%s", length, pHex, getUUID().toString().c_str());
|
||||
free(pHex);
|
||||
#endif
|
||||
|
||||
if (length > BLE_ATT_ATTR_MAX_LEN) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Size %d too large, must be no bigger than %d", length, BLE_ATT_ATTR_MAX_LEN);
|
||||
return;
|
||||
}
|
||||
|
||||
time_t t = time(nullptr);
|
||||
portENTER_CRITICAL(&m_valMux);
|
||||
m_value = std::string((char*)data, length);
|
||||
m_timestamp = t;
|
||||
portEXIT_CRITICAL(&m_valMux);
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< setValue");
|
||||
} // setValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the value of the characteristic from string data.\n
|
||||
* We set the value of the characteristic from the bytes contained in the string.
|
||||
* @param [in] value the std::string value of the characteristic.
|
||||
*/
|
||||
void NimBLECharacteristic::setValue(const std::string &value) {
|
||||
setValue((uint8_t*)(value.data()), value.length());
|
||||
} // setValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return a string representation of the characteristic.
|
||||
* @return A string representation of the characteristic.
|
||||
*/
|
||||
std::string NimBLECharacteristic::toString() const {
|
||||
std::string NimBLECharacteristic::toString() {
|
||||
std::string res = "UUID: " + m_uuid.toString() + ", handle : 0x";
|
||||
char hex[5];
|
||||
snprintf(hex, sizeof(hex), "%04x", getHandle());
|
||||
snprintf(hex, sizeof(hex), "%04x", m_handle);
|
||||
res += hex;
|
||||
res += " ";
|
||||
if (m_properties & BLE_GATT_CHR_PROP_READ ) res += "Read ";
|
||||
@ -354,39 +523,68 @@ std::string NimBLECharacteristic::toString() const {
|
||||
return res;
|
||||
} // toString
|
||||
|
||||
|
||||
NimBLECharacteristicCallbacks::~NimBLECharacteristicCallbacks() {}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Callback function to support a read request.
|
||||
* @param [in] pCharacteristic The characteristic that is the source of the event.
|
||||
* @param [in] connInfo A reference to a NimBLEConnInfo instance containing the peer info.
|
||||
*/
|
||||
void NimBLECharacteristicCallbacks::onRead(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo) {
|
||||
void NimBLECharacteristicCallbacks::onRead(NimBLECharacteristic* pCharacteristic) {
|
||||
NIMBLE_LOGD("NimBLECharacteristicCallbacks", "onRead: default");
|
||||
} // onRead
|
||||
|
||||
/**
|
||||
* @brief Callback function to support a read request.
|
||||
* @param [in] pCharacteristic The characteristic that is the source of the event.
|
||||
* @param [in] desc The connection description struct that is associated with the peer that performed the read.
|
||||
*/
|
||||
void NimBLECharacteristicCallbacks::onRead(NimBLECharacteristic* pCharacteristic, ble_gap_conn_desc* desc) {
|
||||
NIMBLE_LOGD("NimBLECharacteristicCallbacks", "onRead: default");
|
||||
} // onRead
|
||||
|
||||
/**
|
||||
* @brief Callback function to support a write request.
|
||||
* @param [in] pCharacteristic The characteristic that is the source of the event.
|
||||
* @param [in] connInfo A reference to a NimBLEConnInfo instance containing the peer info.
|
||||
*/
|
||||
void NimBLECharacteristicCallbacks::onWrite(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo) {
|
||||
void NimBLECharacteristicCallbacks::onWrite(NimBLECharacteristic* pCharacteristic) {
|
||||
NIMBLE_LOGD("NimBLECharacteristicCallbacks", "onWrite: default");
|
||||
} // onWrite
|
||||
|
||||
/**
|
||||
* @brief Callback function to support a write request.
|
||||
* @param [in] pCharacteristic The characteristic that is the source of the event.
|
||||
* @param [in] desc The connection description struct that is associated with the peer that performed the write.
|
||||
*/
|
||||
void NimBLECharacteristicCallbacks::onWrite(NimBLECharacteristic* pCharacteristic, ble_gap_conn_desc* desc) {
|
||||
NIMBLE_LOGD("NimBLECharacteristicCallbacks", "onWrite: default");
|
||||
} // onWrite
|
||||
|
||||
/**
|
||||
* @brief Callback function to support a Notify request.
|
||||
* @param [in] pCharacteristic The characteristic that is the source of the event.
|
||||
*/
|
||||
void NimBLECharacteristicCallbacks::onNotify(NimBLECharacteristic* pCharacteristic) {
|
||||
NIMBLE_LOGD("NimBLECharacteristicCallbacks", "onNotify: default");
|
||||
} // onNotify
|
||||
|
||||
|
||||
/**
|
||||
* @brief Callback function to support a Notify/Indicate Status report.
|
||||
* @param [in] pCharacteristic The characteristic that is the source of the event.
|
||||
* @param [in] code Status return code from the NimBLE stack.
|
||||
* @details The status code for success is 0 for notifications and BLE_HS_EDONE for indications,
|
||||
* any other value is an error.
|
||||
* @param [in] s Status of the notification/indication.
|
||||
* @param [in] code Additional return code from the NimBLE stack.
|
||||
*/
|
||||
void NimBLECharacteristicCallbacks::onStatus(NimBLECharacteristic* pCharacteristic, int code) {
|
||||
void NimBLECharacteristicCallbacks::onStatus(NimBLECharacteristic* pCharacteristic, Status s, int code) {
|
||||
NIMBLE_LOGD("NimBLECharacteristicCallbacks", "onStatus: default");
|
||||
} // onStatus
|
||||
|
||||
|
||||
/**
|
||||
* @brief Callback function called when a client changes subscription status.
|
||||
* @param [in] pCharacteristic The characteristic that is the source of the event.
|
||||
* @param [in] connInfo A reference to a NimBLEConnInfo instance containing the peer info.
|
||||
* @param [in] desc The connection description struct that is associated with the client.
|
||||
* @param [in] subValue The subscription status:
|
||||
* * 0 = Un-Subscribed
|
||||
* * 1 = Notifications
|
||||
@ -394,9 +592,12 @@ void NimBLECharacteristicCallbacks::onStatus(NimBLECharacteristic* pCharacterist
|
||||
* * 3 = Notifications and Indications
|
||||
*/
|
||||
void NimBLECharacteristicCallbacks::onSubscribe(NimBLECharacteristic* pCharacteristic,
|
||||
NimBLEConnInfo& connInfo,
|
||||
uint16_t subValue) {
|
||||
ble_gap_conn_desc* desc,
|
||||
uint16_t subValue)
|
||||
{
|
||||
NIMBLE_LOGD("NimBLECharacteristicCallbacks", "onSubscribe: default");
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||
|
||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
|
@ -1,238 +1,162 @@
|
||||
/*
|
||||
* Copyright 2020-2024 Ryan Powell <ryan@nable-embedded.io> and
|
||||
* esp-nimble-cpp, NimBLE-Arduino contributors.
|
||||
* NimBLECharacteristic.h
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* Created: on March 3, 2020
|
||||
* Author H2zero
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Originally:
|
||||
* BLECharacteristic.h
|
||||
*
|
||||
* 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.
|
||||
* Created on: Jun 22, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef NIMBLE_CPP_CHARACTERISTIC_H_
|
||||
#define NIMBLE_CPP_CHARACTERISTIC_H_
|
||||
#ifndef MAIN_NIMBLECHARACTERISTIC_H_
|
||||
#define MAIN_NIMBLECHARACTERISTIC_H_
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
|
||||
class NimBLECharacteristicCallbacks;
|
||||
class NimBLEService;
|
||||
class NimBLECharacteristic;
|
||||
class NimBLEDescriptor;
|
||||
class NimBLE2904;
|
||||
#include "host/ble_hs.h"
|
||||
/**** FIX COMPILATION ****/
|
||||
#undef min
|
||||
#undef max
|
||||
/**************************/
|
||||
|
||||
# include "NimBLELocalValueAttribute.h"
|
||||
typedef enum {
|
||||
READ = BLE_GATT_CHR_F_READ,
|
||||
READ_ENC = BLE_GATT_CHR_F_READ_ENC,
|
||||
READ_AUTHEN = BLE_GATT_CHR_F_READ_AUTHEN,
|
||||
READ_AUTHOR = BLE_GATT_CHR_F_READ_AUTHOR,
|
||||
WRITE = BLE_GATT_CHR_F_WRITE,
|
||||
WRITE_NR = BLE_GATT_CHR_F_WRITE_NO_RSP,
|
||||
WRITE_ENC = BLE_GATT_CHR_F_WRITE_ENC,
|
||||
WRITE_AUTHEN = BLE_GATT_CHR_F_WRITE_AUTHEN,
|
||||
WRITE_AUTHOR = BLE_GATT_CHR_F_WRITE_AUTHOR,
|
||||
BROADCAST = BLE_GATT_CHR_F_BROADCAST,
|
||||
NOTIFY = BLE_GATT_CHR_F_NOTIFY,
|
||||
INDICATE = BLE_GATT_CHR_F_INDICATE
|
||||
} NIMBLE_PROPERTY;
|
||||
|
||||
#include "NimBLEService.h"
|
||||
#include "NimBLEDescriptor.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class NimBLEService;
|
||||
class NimBLEDescriptor;
|
||||
class NimBLECharacteristicCallbacks;
|
||||
|
||||
|
||||
/**
|
||||
* @brief The model of a BLE Characteristic.
|
||||
* @brief The model of a %BLE Characteristic.
|
||||
*
|
||||
* A BLE Characteristic is an identified value container that manages a value. It is exposed by a BLE service and
|
||||
* can be read and written to by a BLE client.
|
||||
* A BLE Characteristic is an identified value container that manages a value. It is exposed by a BLE server and
|
||||
* can be read and written to by a %BLE client.
|
||||
*/
|
||||
class NimBLECharacteristic : public NimBLELocalValueAttribute {
|
||||
class NimBLECharacteristic {
|
||||
public:
|
||||
NimBLECharacteristic(const char* uuid,
|
||||
uint16_t properties = NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE,
|
||||
uint16_t maxLen = BLE_ATT_ATTR_MAX_LEN,
|
||||
uint16_t properties =
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE,
|
||||
NimBLEService* pService = nullptr);
|
||||
NimBLECharacteristic(const NimBLEUUID &uuid,
|
||||
uint16_t properties = NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE,
|
||||
uint16_t maxLen = BLE_ATT_ATTR_MAX_LEN,
|
||||
uint16_t properties =
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE,
|
||||
NimBLEService* pService = nullptr);
|
||||
|
||||
~NimBLECharacteristic();
|
||||
|
||||
std::string toString() const;
|
||||
void addDescriptor(NimBLEDescriptor* pDescriptor);
|
||||
void removeDescriptor(NimBLEDescriptor* pDescriptor, bool deleteDsc = false);
|
||||
uint16_t getProperties() const;
|
||||
uint16_t getHandle();
|
||||
NimBLEUUID getUUID();
|
||||
std::string toString();
|
||||
|
||||
void setCallbacks(NimBLECharacteristicCallbacks* pCallbacks);
|
||||
bool indicate(uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const;
|
||||
bool indicate(const uint8_t* value, size_t length, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const;
|
||||
bool notify(uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const;
|
||||
bool notify(const uint8_t* value, size_t length, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const;
|
||||
NimBLECharacteristicCallbacks*
|
||||
getCallbacks();
|
||||
|
||||
void indicate();
|
||||
void notify(bool is_notification = true);
|
||||
size_t getSubscribedCount();
|
||||
|
||||
NimBLEDescriptor* createDescriptor(const char* uuid,
|
||||
uint32_t properties = NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE,
|
||||
uint16_t maxLen = BLE_ATT_ATTR_MAX_LEN);
|
||||
uint32_t properties =
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE,
|
||||
uint16_t max_len = 100);
|
||||
NimBLEDescriptor* createDescriptor(const NimBLEUUID &uuid,
|
||||
uint32_t properties = NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE,
|
||||
uint16_t maxLen = BLE_ATT_ATTR_MAX_LEN);
|
||||
NimBLE2904* create2904();
|
||||
NimBLEDescriptor* getDescriptorByUUID(const char* uuid) const;
|
||||
NimBLEDescriptor* getDescriptorByUUID(const NimBLEUUID& uuid) const;
|
||||
NimBLEDescriptor* getDescriptorByHandle(uint16_t handle) const;
|
||||
NimBLEService* getService() const;
|
||||
uint32_t properties =
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE,
|
||||
uint16_t max_len = 100);
|
||||
|
||||
NimBLECharacteristicCallbacks* getCallbacks() const;
|
||||
void addDescriptor(NimBLEDescriptor *pDescriptor);
|
||||
NimBLEDescriptor* getDescriptorByUUID(const char* uuid);
|
||||
NimBLEDescriptor* getDescriptorByUUID(const NimBLEUUID &uuid);
|
||||
NimBLEDescriptor* getDescriptorByHandle(uint16_t handle);
|
||||
|
||||
/*********************** Template Functions ************************/
|
||||
|
||||
# if __cplusplus < 201703L
|
||||
std::string getValue(time_t *timestamp = nullptr);
|
||||
size_t getDataLength();
|
||||
/**
|
||||
* @brief Template to send a notification with a value from a struct or array.
|
||||
* @param [in] v The value to send.
|
||||
* @param [in] connHandle Optional, a connection handle to send the notification to.
|
||||
* @details <type\> size must be evaluatable by `sizeof()`.
|
||||
* @brief A template to convert the characteristic data to <type\>.
|
||||
* @tparam T The type to convert the data to.
|
||||
* @param [in] timestamp A pointer to a time_t struct to store the time the value was read.
|
||||
* @param [in] skipSizeCheck If true it will skip checking if the data size is less than <tt>sizeof(<type\>)</tt>.
|
||||
* @return The data converted to <type\> or NULL if skipSizeCheck is false and the data is
|
||||
* less than <tt>sizeof(<type\>)</tt>.
|
||||
* @details <b>Use:</b> <tt>getValue<type>(×tamp, skipSizeCheck);</tt>
|
||||
*/
|
||||
template<typename T>
|
||||
# ifdef _DOXYGEN_
|
||||
bool
|
||||
# else
|
||||
typename std::enable_if<!std::is_pointer<T>::value && !Has_c_str_length<T>::value && !Has_data_size<T>::value, bool>::type
|
||||
# endif
|
||||
notify(const T& v, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const {
|
||||
return notify(reinterpret_cast<const uint8_t*>(&v), sizeof(T), connHandle);
|
||||
T getValue(time_t *timestamp = nullptr, bool skipSizeCheck = false) {
|
||||
std::string value = getValue();
|
||||
if(!skipSizeCheck && value.size() < sizeof(T)) return T();
|
||||
const char *pData = value.data();
|
||||
return *((T *)pData);
|
||||
}
|
||||
|
||||
void setValue(const uint8_t* data, size_t size);
|
||||
void setValue(const std::string &value);
|
||||
/**
|
||||
* @brief Template to send a notification with a value from a class that has a c_str() and length() method.
|
||||
* @param [in] s The value to send.
|
||||
* @param [in] connHandle Optional, a connection handle to send the notification to.
|
||||
* @brief Convenience template to set the characteristic value to <type\>val.
|
||||
* @param [in] s The value to set.
|
||||
*/
|
||||
template<typename T>
|
||||
# ifdef _DOXYGEN_
|
||||
bool
|
||||
# else
|
||||
typename std::enable_if<Has_c_str_length<T>::value && !Has_data_size<T>::value, bool>::type
|
||||
# endif
|
||||
notify(const T& s, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const {
|
||||
return notify(reinterpret_cast<const uint8_t*>(s.c_str()), s.length(), connHandle);
|
||||
void setValue(const T &s) {
|
||||
setValue((uint8_t*)&s, sizeof(T));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Template to send a notification with a value from a class that has a data() and size() method.
|
||||
* @param [in] v The value to send.
|
||||
* @param [in] connHandle Optional, a connection handle to send the notification to.
|
||||
*/
|
||||
template <typename T>
|
||||
# ifdef _DOXYGEN_
|
||||
bool
|
||||
# else
|
||||
typename std::enable_if<Has_data_size<T>::value, bool>::type
|
||||
# endif
|
||||
notify(const T& v, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const {
|
||||
return notify(reinterpret_cast<const uint8_t*>(v.data()), v.size(), connHandle);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Template to send an indication with a value from a struct or array.
|
||||
* @param [in] v The value to send.
|
||||
* @param [in] connHandle Optional, a connection handle to send the notification to.
|
||||
* @details <type\> size must be evaluatable by `sizeof()`.
|
||||
*/
|
||||
template <typename T>
|
||||
# ifdef _DOXYGEN_
|
||||
bool
|
||||
# else
|
||||
typename std::enable_if<!std::is_pointer<T>::value && !Has_c_str_length<T>::value && !Has_data_size<T>::value, bool>::type
|
||||
# endif
|
||||
indicate(const T& v, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const {
|
||||
return indicate(reinterpret_cast<const uint8_t*>(&v), sizeof(T), connHandle);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Template to send a indication with a value from a class that has a c_str() and length() method.
|
||||
* @param [in] s The value to send.
|
||||
* @param [in] connHandle Optional, a connection handle to send the notification to.
|
||||
*/
|
||||
template <typename T>
|
||||
# ifdef _DOXYGEN_
|
||||
bool
|
||||
# else
|
||||
typename std::enable_if<Has_c_str_length<T>::value && !Has_data_size<T>::value, bool>::type
|
||||
# endif
|
||||
indicate(const T& s, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const {
|
||||
return indicate(reinterpret_cast<const uint8_t*>(s.c_str()), s.length(), connHandle);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Template to send a indication with a value from a class that has a data() and size() method.
|
||||
* @param [in] v The value to send.
|
||||
* @param [in] connHandle Optional, a connection handle to send the notification to.
|
||||
*/
|
||||
template <typename T>
|
||||
# ifdef _DOXYGEN_
|
||||
bool
|
||||
# else
|
||||
typename std::enable_if<Has_data_size<T>::value, bool>::type
|
||||
# endif
|
||||
indicate(const T& v, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const {
|
||||
return indicate(reinterpret_cast<const uint8_t*>(v.data()), v.size(), connHandle);
|
||||
}
|
||||
|
||||
# else
|
||||
|
||||
/**
|
||||
* @brief Template to send a notification for classes which may have
|
||||
* data()/size() or c_str()/length() methods. Falls back to sending
|
||||
* the data by casting the first element of the array to a uint8_t
|
||||
* pointer and getting the length of the array using sizeof.
|
||||
* @tparam T The a reference to a class containing the data to send.
|
||||
* @param[in] value The <type\>value to set.
|
||||
* @param[in] connHandle The connection handle to send the notification to.
|
||||
* @note This function is only available if the type T is not a pointer.
|
||||
*/
|
||||
template <typename T>
|
||||
typename std::enable_if<!std::is_pointer<T>::value, bool>::type notify(const T& value,
|
||||
uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const {
|
||||
if constexpr (Has_data_size<T>::value) {
|
||||
return notify(reinterpret_cast<const uint8_t*>(value.data()), value.size(), connHandle);
|
||||
} else if constexpr (Has_c_str_length<T>::value) {
|
||||
return notify(reinterpret_cast<const uint8_t*>(value.c_str()), value.length(), connHandle);
|
||||
} else {
|
||||
return notify(reinterpret_cast<const uint8_t*>(&value), sizeof(value), connHandle);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Template to send an indication for classes which may have
|
||||
* data()/size() or c_str()/length() methods. Falls back to sending
|
||||
* the data by casting the first element of the array to a uint8_t
|
||||
* pointer and getting the length of the array using sizeof.
|
||||
* @tparam T The a reference to a class containing the data to send.
|
||||
* @param[in] value The <type\>value to set.
|
||||
* @param[in] connHandle The connection handle to send the indication to.
|
||||
* @note This function is only available if the type T is not a pointer.
|
||||
*/
|
||||
template <typename T>
|
||||
typename std::enable_if<!std::is_pointer<T>::value, bool>::type indicate(
|
||||
const T& value, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const {
|
||||
if constexpr (Has_data_size<T>::value) {
|
||||
return indicate(reinterpret_cast<const uint8_t*>(value.data()), value.size(), connHandle);
|
||||
} else if constexpr (Has_c_str_length<T>::value) {
|
||||
return indicate(reinterpret_cast<const uint8_t*>(value.c_str()), value.length(), connHandle);
|
||||
} else {
|
||||
return indicate(reinterpret_cast<const uint8_t*>(&value), sizeof(value), connHandle);
|
||||
}
|
||||
}
|
||||
# endif
|
||||
NimBLEService* getService();
|
||||
uint16_t getProperties();
|
||||
|
||||
private:
|
||||
|
||||
friend class NimBLEServer;
|
||||
friend class NimBLEService;
|
||||
|
||||
void setService(NimBLEService *pService);
|
||||
void readEvent(NimBLEConnInfo& connInfo) override;
|
||||
void writeEvent(const uint8_t* val, uint16_t len, NimBLEConnInfo& connInfo) override;
|
||||
bool sendValue(const uint8_t* value,
|
||||
size_t length,
|
||||
bool is_notification = true,
|
||||
uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const;
|
||||
void setSubscribe(struct ble_gap_event *event);
|
||||
static int handleGapEvent(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg);
|
||||
|
||||
NimBLECharacteristicCallbacks* m_pCallbacks{nullptr};
|
||||
NimBLEService* m_pService{nullptr};
|
||||
std::vector<NimBLEDescriptor*> m_vDescriptors{};
|
||||
NimBLEUUID m_uuid;
|
||||
uint16_t m_handle;
|
||||
uint16_t m_properties;
|
||||
NimBLECharacteristicCallbacks* m_pCallbacks;
|
||||
NimBLEService* m_pService;
|
||||
std::string m_value;
|
||||
std::vector<NimBLEDescriptor*> m_dscVec;
|
||||
portMUX_TYPE m_valMux;
|
||||
time_t m_timestamp;
|
||||
|
||||
std::vector<std::pair<uint16_t, uint16_t>> m_subscribedVec;
|
||||
}; // NimBLECharacteristic
|
||||
|
||||
|
||||
/**
|
||||
* @brief Callbacks that can be associated with a %BLE characteristic to inform of events.
|
||||
*
|
||||
@ -242,12 +166,33 @@ class NimBLECharacteristic : public NimBLELocalValueAttribute {
|
||||
*/
|
||||
class NimBLECharacteristicCallbacks {
|
||||
public:
|
||||
virtual ~NimBLECharacteristicCallbacks() {}
|
||||
virtual void onRead(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo);
|
||||
virtual void onWrite(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo);
|
||||
virtual void onStatus(NimBLECharacteristic* pCharacteristic, int code);
|
||||
virtual void onSubscribe(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo, uint16_t subValue);
|
||||
|
||||
/**
|
||||
* @brief An enum to provide the callback the status of the
|
||||
* notification/indication, implemented for backward compatibility.
|
||||
* @deprecated To be removed in the future as the NimBLE stack return code is also provided.
|
||||
*/
|
||||
typedef enum {
|
||||
SUCCESS_INDICATE,
|
||||
SUCCESS_NOTIFY,
|
||||
ERROR_INDICATE_DISABLED,
|
||||
ERROR_NOTIFY_DISABLED,
|
||||
ERROR_GATT,
|
||||
ERROR_NO_CLIENT,
|
||||
ERROR_INDICATE_TIMEOUT,
|
||||
ERROR_INDICATE_FAILURE
|
||||
}Status;
|
||||
|
||||
virtual ~NimBLECharacteristicCallbacks();
|
||||
virtual void onRead(NimBLECharacteristic* pCharacteristic);
|
||||
virtual void onRead(NimBLECharacteristic* pCharacteristic, ble_gap_conn_desc* desc);
|
||||
virtual void onWrite(NimBLECharacteristic* pCharacteristic);
|
||||
virtual void onWrite(NimBLECharacteristic* pCharacteristic, ble_gap_conn_desc* desc);
|
||||
virtual void onNotify(NimBLECharacteristic* pCharacteristic);
|
||||
virtual void onStatus(NimBLECharacteristic* pCharacteristic, Status s, int code);
|
||||
virtual void onSubscribe(NimBLECharacteristic* pCharacteristic, ble_gap_conn_desc* desc, uint16_t subValue);
|
||||
};
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||
#endif /*NIMBLE_CPP_CHARACTERISTIC_H_*/
|
||||
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
#endif /*MAIN_NIMBLECHARACTERISTIC_H_*/
|
||||
|
1297
src/NimBLEClient.cpp
1297
src/NimBLEClient.cpp
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user