mirror of
https://github.com/h2zero/esp-nimble-cpp.git
synced 2026-04-13 13:16:02 +02:00
Compare commits
18 Commits
2.4.0
...
release/2.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ec5600d40b | ||
|
|
bc3e342046 | ||
|
|
865ec9f760 | ||
|
|
e2de3f6268 | ||
|
|
bdb86274c9 | ||
|
|
8aa824ef32 | ||
|
|
cc7f97a37d | ||
|
|
8723121ff9 | ||
|
|
90b721ed55 | ||
|
|
d1ef98a4c8 | ||
|
|
70eee888eb | ||
|
|
80b61ffa3d | ||
|
|
ee895d386e | ||
|
|
5add3442e9 | ||
|
|
aea55ccda2 | ||
|
|
83e9919457 | ||
|
|
edeaf3977a | ||
|
|
4e80e1ee38 |
15
.github/workflows/build.yml
vendored
15
.github/workflows/build.yml
vendored
@@ -12,14 +12,13 @@ jobs:
|
||||
name: Build with ESP-IDF ${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
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-v5.4", "release-v5.5"]
|
||||
idf_target: ["esp32", "esp32s3", "esp32c2", "esp32c3", "esp32c5", "esp32c6", "esp32c61", "esp32h2", "esp32p4"]
|
||||
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
|
||||
@@ -32,14 +31,8 @@ jobs:
|
||||
example: Bluetooth_5/NimBLE_extended_server
|
||||
- idf_ver: release-v4.4
|
||||
idf_target: "esp32c2"
|
||||
- idf_ver: release-v4.4
|
||||
idf_target: "esp32c5"
|
||||
- idf_ver: release-v4.4
|
||||
idf_target: "esp32c6"
|
||||
- idf_ver: release-v4.4
|
||||
idf_target: "esp32c61"
|
||||
- idf_ver: release-v5.4
|
||||
idf_target: "esp32c61"
|
||||
- idf_ver: release-v4.4
|
||||
idf_target: "esp32h2"
|
||||
- idf_ver: release-v4.4
|
||||
@@ -50,7 +43,7 @@ jobs:
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: components/esp-nimble-cpp
|
||||
- name: Build examples
|
||||
@@ -65,7 +58,7 @@ jobs:
|
||||
build_docs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v4
|
||||
- name: Doxygen Action
|
||||
uses: mattnotmitt/doxygen-action@v1.9.8
|
||||
with:
|
||||
|
||||
27
.github/workflows/release.yml
vendored
27
.github/workflows/release.yml
vendored
@@ -8,7 +8,7 @@ jobs:
|
||||
build_docs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v4
|
||||
- name: Doxygen Action
|
||||
uses: mattnotmitt/doxygen-action@v1.9.8
|
||||
with:
|
||||
@@ -17,27 +17,4 @@ jobs:
|
||||
uses: peaceiris/actions-gh-pages@v4
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
publish_dir: ./docs/doxydocs/html
|
||||
|
||||
upload_to_component_registry:
|
||||
permissions:
|
||||
id-token: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
submodules: "recursive"
|
||||
- name: Upload component to the component registry
|
||||
uses: espressif/upload-components-ci-action@v2
|
||||
with:
|
||||
components: "esp-nimble-cpp: ."
|
||||
namespace: "h2zero"
|
||||
|
||||
upload_to_platformio_registry:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- name: Upload component to PlatformIO Registry
|
||||
uses: bojit/platformio-publish@main
|
||||
with:
|
||||
token: ${{ secrets.PLATFORMIO_AUTH_TOKEN }}
|
||||
publish_dir: ./docs/doxydocs/html
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,4 +1 @@
|
||||
docs/doxydocs
|
||||
dist
|
||||
.development
|
||||
_codeql_detected_source_root
|
||||
|
||||
95
CHANGELOG.md
95
CHANGELOG.md
@@ -1,101 +1,6 @@
|
||||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [2.4.0] 2026-03-20
|
||||
|
||||
## Fixed
|
||||
- GATT attribute handles are now assigned from the registration callback so duplicate UUID attributes are identified correctly.
|
||||
- Dynamic service changes now properly remove characteristics/descriptors and reset the GATT database when advertising starts.
|
||||
- Missing notification/indication payload data when the value spans multiple mbufs, such as values larger than 255 bytes with small ACL buffers.
|
||||
- `NimBLEDevice::createServer` will longer crash when called before the stack is initialized.
|
||||
- Re-pairing after deleting all bonds now works by unpairing each stored bond instead of only deleting NVS data.
|
||||
- Whitelist bounds checks.
|
||||
- `NimBLEDevice::getBondedAddress` index bounds validation.
|
||||
- Compiler warnings when bonds are disabled.
|
||||
- kconfig warnings, redefined macros.
|
||||
|
||||
## Added
|
||||
- `NimBLEStream`, `NimBLEStreamClient`, and `NimBLEStreamServer` classes and examples.
|
||||
- `NimBLECppVersion.h` with compile-time version macros.
|
||||
- `NimBLEDevice::getVersion` runtime version string helper.
|
||||
- Matching passkey callbacks for both roles: `NimBLEServerCallbacks::onPassKeyEntry` and `NimBLEClientCallbacks::onPassKeyDisplay`.
|
||||
- Bond migration helpers to convert bond storage between v1 and current formats while preserving existing bonds.
|
||||
- `NimBLEUUID` constructor overload for `ble_uuid_t*`.
|
||||
- Optional `index` parameter for `NimBLECharacteristic::getDescriptorByUUID` to access multiple descriptors with the same UUID.
|
||||
- `NimBLEConnInfo::toString` method to get a string representation of the connection info.
|
||||
|
||||
## Changed
|
||||
- `NimBLEService::start` is deprecated; services are now added when the server starts.
|
||||
- `NimBLEHIDDevice::startServices()` is deprecated; services are now added when the server starts.
|
||||
|
||||
## [2.3.4] 2025-12-27
|
||||
|
||||
## Fixed
|
||||
- Disconnect event not finding the client by address in some cases, use the connection handle instead.
|
||||
- Notification/Indications will now be sent to server created clients.
|
||||
- Attribute values will now consider type size when using a container.
|
||||
- Descriptor searching will now correctly stop at the end handle of the characteristic.
|
||||
|
||||
## Changed
|
||||
- Build conditionals now use `MYNEWT_VAL_` macros instead of `CONFIG_` macros where applicable.
|
||||
- Sending of indications/notifications has been refactored for greater efficiency and tracks client subscription state locally instead uof relying on the stack.
|
||||
|
||||
## Added
|
||||
- Support for esp32c61.
|
||||
- `NimBLECharacteristicCallbacks::onStatus` overload that takes a `NimBLEConnInfo&` parameter to indicate which client the status is for.
|
||||
- `NimBLEDevice::setCustomGapHandler` now takes a `void*` parameter to allow for passing user data to the custom handler.
|
||||
|
||||
## [2.3.3] 2025-09-05
|
||||
|
||||
## Fixed
|
||||
- NimBLEAdvertisedDevice::isConnectable returning incorrect result.
|
||||
- Extended advertisements not reporting full data.
|
||||
|
||||
## Added
|
||||
- Support up to 1650 bytes of advertisement with extended advertising
|
||||
|
||||
## [2.3.2] 2025-09-02
|
||||
|
||||
## Fixed
|
||||
- Build failures with esp-idf versions 4.x.
|
||||
- Workaround for upstream issue causing onConnectFail to not be called.
|
||||
- Build failures with idf v5.5+ and specific roles are not enabled.
|
||||
|
||||
## Changed
|
||||
- Allow peripheral and central roles to be used without broadcaster/observer roles.
|
||||
- Where applicable, `MYNEWT_VAL_` macros are used to control feature availability instead of `CONFIG_`
|
||||
|
||||
## [2.3.1] 2025-06-11
|
||||
|
||||
## Fixed
|
||||
- Build errors when disabling BLE roles.
|
||||
- `NimBLEClient::readValue` call not returning when the instance was created with a`NimBLEServer` and reading a secured characteristic.
|
||||
- `NimBLEScan` destructor potentially causing a crash.
|
||||
|
||||
## Added
|
||||
- `NimBLEBeacon::BeaconData` `std::vector<uint8_t>` operator to allow it to be used as a parameter to `NimBLEAdvertisementData::setManufacturerData`.
|
||||
|
||||
## [2.3.0] 2025-05-19
|
||||
|
||||
## Fixed
|
||||
- Incorrect `NimBLECharacteristic::onSubscribe` value when indications are set.
|
||||
- `NimBLECharacteristic::onRead` callback not called in some cases.
|
||||
- Clear attribute value when zero length value is written.
|
||||
- Notify/Indicate incorrectly returning success with custom value.
|
||||
- Corrected NimBLEClient array initialization.
|
||||
- Prevent potential exception when scan is restarted.
|
||||
- Attribute getValue failing with some data types
|
||||
- Incorrectly passing a pointer to a function taking const reference.
|
||||
|
||||
## Added
|
||||
- Support for esp32c5
|
||||
- L2CAP infrastructure.
|
||||
- Scan duplicate cache reset time.
|
||||
|
||||
## Changed
|
||||
- Cleaned up examples.
|
||||
- Allow PHY updates without enabling extended advertising.
|
||||
|
||||
## [2.2.1] 2025-02-28
|
||||
|
||||
## Fixed
|
||||
|
||||
@@ -35,9 +35,7 @@ idf_component_register(
|
||||
"esp32s3"
|
||||
"esp32c2"
|
||||
"esp32c3"
|
||||
"esp32c5"
|
||||
"esp32c6"
|
||||
"esp32c61"
|
||||
"esp32h2"
|
||||
"esp32p4"
|
||||
INCLUDE_DIRS
|
||||
@@ -57,8 +55,6 @@ idf_component_register(
|
||||
"src/NimBLEEddystoneTLM.cpp"
|
||||
"src/NimBLEExtAdvertising.cpp"
|
||||
"src/NimBLEHIDDevice.cpp"
|
||||
"src/NimBLEL2CAPChannel.cpp"
|
||||
"src/NimBLEL2CAPServer.cpp"
|
||||
"src/NimBLERemoteCharacteristic.cpp"
|
||||
"src/NimBLERemoteDescriptor.cpp"
|
||||
"src/NimBLERemoteService.cpp"
|
||||
@@ -66,7 +62,6 @@ idf_component_register(
|
||||
"src/NimBLEScan.cpp"
|
||||
"src/NimBLEServer.cpp"
|
||||
"src/NimBLEService.cpp"
|
||||
"src/NimBLEStream.cpp"
|
||||
"src/NimBLEUtils.cpp"
|
||||
"src/NimBLEUUID.cpp"
|
||||
REQUIRES
|
||||
|
||||
49
Kconfig
49
Kconfig
@@ -204,8 +204,51 @@ config NIMBLE_CPP_FREERTOS_TASK_BLOCK_BIT
|
||||
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.
|
||||
|
||||
config NIMBLE_CPP_IDF
|
||||
bool
|
||||
default BT_NIMBLE_ENABLED
|
||||
#
|
||||
# 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
|
||||
@@ -9,8 +9,6 @@
|
||||
|
||||
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).
|
||||
|
||||
The library is threadsafe, characteristics can be set from any thread.
|
||||
|
||||
**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
|
||||
|
||||
@@ -43,7 +43,6 @@ The changes listed here are only the required changes that must be made, and a s
|
||||
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`.
|
||||
- `NimBLEDevice::getClientByID(uint16_t conn_id);` has been changed to `NimBLEDevice::getClientByHandle(uint16_t connHandle)`
|
||||
<br/>
|
||||
|
||||
## BLE Addresses
|
||||
@@ -55,7 +54,7 @@ The default address type is public `0`, whereas many devices use a random `1` ad
|
||||
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.val` and type is in `ble_addr_t.type`.
|
||||
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
|
||||
@@ -134,7 +133,6 @@ Have been removed, instead the application should use `NimBLERemoteCharacteristi
|
||||
- - `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::setAdvertisedDeviceCallbacks(NimBLEAdvertisedDeviceCallbacks* callbacks, bool wantDuplicates)` has been changed to `NimBLEScan::setScanCallbacks(NimBLEScanCallbacks* callbacks, bool wantDuplicates);`
|
||||
<br/>
|
||||
|
||||
### Advertised Device
|
||||
|
||||
@@ -48,7 +48,8 @@ PROJECT_NAME = esp-nimble-cpp
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER = 2.4.0
|
||||
PROJECT_NUMBER = 2.2.1
|
||||
|
||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||
# for a project that appears at the top of each page and should give viewer a
|
||||
# quick idea about the purpose of the project. Keep the description short.
|
||||
@@ -2416,12 +2417,12 @@ INCLUDE_FILE_PATTERNS =
|
||||
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
|
||||
|
||||
PREDEFINED = _DOXYGEN_ \
|
||||
CONFIG_BT_NIMBLE_ENABLED=1 \
|
||||
MYNEWT_VAL_BLE_ROLE_CENTRAL=1 \
|
||||
MYNEWT_VAL_BLE_ROLE_OBSERVER=1 \
|
||||
MYNEWT_VAL_BLE_ROLE_PERIPHERAL=1 \
|
||||
MYNEWT_VAL_BLE_ROLE_BROADCASTER=1 \
|
||||
MYNEWT_VAL_BLE_EXT_ADV=1
|
||||
CONFIG_BT_ENABLED \
|
||||
CONFIG_BT_NIMBLE_ROLE_CENTRAL \
|
||||
CONFIG_BT_NIMBLE_ROLE_OBSERVER \
|
||||
CONFIG_BT_NIMBLE_ROLE_PERIPHERAL \
|
||||
CONFIG_BT_NIMBLE_ROLE_BROADCASTER \
|
||||
CONFIG_BT_NIMBLE_EXT_ADV
|
||||
|
||||
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
|
||||
# tag can be used to specify a list of macro names that should be expanded. The
|
||||
|
||||
@@ -234,7 +234,7 @@ This can be changed to use passkey authentication or numeric comparison. See [Se
|
||||
Advertising works the same as the original API except:
|
||||
|
||||
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 if calling `NimBLEAdvertising::setAdvertisementData`.
|
||||
`NimBLEAdvertising::setAppearance` or similar methods. You should set all the data you wish to advertise within the `NimBLEAdvertisementData` instead.
|
||||
<br/>
|
||||
|
||||
> BLEAdvertising::start (NimBLEAdvertising::start)
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
# Usage Tips
|
||||
|
||||
## Threadsafety
|
||||
## Put BLE functions in a task running on the NimBLE stack core
|
||||
|
||||
This library is threadsafe. Attribues can be manipulated freely.
|
||||
When commands are sent to the stack from a different core they can experience delays in execution.
|
||||
This library detects this and invokes the esp32 IPC to reroute these commands through the correct core but this also increases overhead.
|
||||
Therefore it is highly recommended to create tasks for BLE to run on the same core, the macro `CONFIG_BT_NIMBLE_PINNED_TO_CORE` can be used to set the core.
|
||||
<br/>
|
||||
|
||||
## Do not delete client instances unless necessary or unused
|
||||
|
||||
@@ -29,41 +32,6 @@ or nullptr such as when calling `NimBLEClient::getService`. The latter being a
|
||||
Most of the functions in this library return something that should be checked before proceeding.
|
||||
<br/>
|
||||
|
||||
## Persisted bonds can be lost due to low MAX_CCCDS
|
||||
|
||||
The symptom: CONFIG_BT_NIMBLE_MAX_BONDS is set to N, but a smaller number of bonds is preserved, perhaps even a single bond. The limitation of persisted bonds can be observed via NimBLEDevice::getNumBonds(). The number may not reach CONFIG_BT_NIMBLE_MAX_BONDS.
|
||||
|
||||
Cause: For each bond, NimBLE persists each of the CCCD (client characteristic configuration descriptor) values that have been subscribed
|
||||
to by the client. If CONFIG_BT_NIMBLE_MAX_CCCDS is too low, the older CCCD values are overwritten by the newer ones. The loss of the older
|
||||
CCCDs values results in those bonds being lost.
|
||||
|
||||
Fix: Increase CONFIG_BT_NIMBLE_MAX_CCCDS. These take approximately 40 bytes in NVS, 2 bytes for the CCCD value and the NVS metadata overhead. The value of
|
||||
CONFIG_BT_NIMBLE_MAX_CCCDS should conservatively be no less than (CONFIG_BT_NIMBLE_MAX_BONDS * {maximum number of characteristics that can be subscribed to}).
|
||||
|
||||
## Device 'Local Name'
|
||||
|
||||
'Local name' refers to how the device is seen and displayed.
|
||||
|
||||
A devices 'Local name' can be thought of as coming from two places, the <i>Advertising "Local name"</i> and the <i>the GATT Device Name</i>.
|
||||
|
||||
### Advertising "Local name"
|
||||
|
||||
Field found in the advertising data payload. Value is set via NimBLEAdvertising::setName().
|
||||
|
||||
### GATT Device Name
|
||||
|
||||
Characteristic UUID 0x2A00 in the Generic Access service. Set via NimBLEDevice::init() or NimBLEDevice::setDeviceName().
|
||||
|
||||
This characteristic is read <b>after</b> connecting to the device.
|
||||
|
||||
### Important considerations
|
||||
|
||||
* OSes cache the <i>'GATT Device Name'</i>.
|
||||
* OSes update the device name based on the <i>'GATT Device Name'</i> after connecting to a device. This means that if you set the <i>Advertising 'Local name'</i> to "ABCD" but the <i>'GATT Device Name'</i> to "12345", the device will be seen as "ABCD" until connecting to the device, at which time the devices name will change to "12345".
|
||||
* If no <i>'Advertising "Local name"'</i> is set, OSes, such as iOS, may display the devices name as 'Unnamed' until the device is connected to, at which time the <i>'GATT Device Name'</i> is read and used instead.
|
||||
|
||||
It is recommended that both <i>'Advertising "Local name"'</i> <b>and</b> <i>'GATT Device Name'</i> be set appropriately, after considering the above described behavior.
|
||||
|
||||
## There will be bugs - please report them
|
||||
|
||||
No code is bug free and unit testing will not find them all on it's own. If you encounter a bug, please report it along with any logs and decoded backtrace if applicable.
|
||||
|
||||
@@ -36,7 +36,7 @@ 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:\n%s", connInfo.toString().c_str());
|
||||
printf("Client connected:: %s\n", connInfo.getAddress().toString().c_str());
|
||||
}
|
||||
|
||||
void onDisconnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo, int reason) override {
|
||||
@@ -65,7 +65,8 @@ class AdvertisingCallbacks : public NimBLEExtAdvertisingCallbacks {
|
||||
}
|
||||
} advertisingCallbacks;
|
||||
|
||||
extern "C" void app_main(void) {
|
||||
extern "C"
|
||||
void app_main(void) {
|
||||
/** Initialize NimBLE and set the device name */
|
||||
NimBLEDevice::init("Extended advertiser");
|
||||
|
||||
@@ -80,6 +81,9 @@ extern "C" void app_main(void) {
|
||||
|
||||
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.
|
||||
@@ -101,6 +105,7 @@ extern "C" void app_main(void) {
|
||||
"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 */
|
||||
|
||||
@@ -36,7 +36,7 @@ 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:\n%s", connInfo.toString().c_str());
|
||||
printf("Client connected: %s\n", connInfo.getAddress().toString().c_str());
|
||||
}
|
||||
|
||||
void onDisconnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo, int reason) override {
|
||||
@@ -98,6 +98,9 @@ extern "C" void app_main(void) {
|
||||
|
||||
pCharacteristic->setValue("Hello World");
|
||||
|
||||
/** Start the service */
|
||||
pService->start();
|
||||
|
||||
/** Create our multi advertising instances */
|
||||
|
||||
/** extended scannable instance advertising on coded and 1m PHY's. */
|
||||
|
||||
5
examples/L2CAP/.gitignore
vendored
5
examples/L2CAP/.gitignore
vendored
@@ -1,5 +0,0 @@
|
||||
.vscode
|
||||
build
|
||||
sdkconfig
|
||||
sdkconfig.old
|
||||
dependencies.lock
|
||||
@@ -1,7 +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)
|
||||
set(SUPPORTED_TARGETS esp32 esp32s3 esp32c3 esp32c6)
|
||||
project(L2CAP_client)
|
||||
@@ -1,3 +0,0 @@
|
||||
PROJECT_NAME := L2CAP_client
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
@@ -1,4 +0,0 @@
|
||||
set(COMPONENT_SRCS "main.cpp")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||
|
||||
register_component()
|
||||
@@ -1,4 +0,0 @@
|
||||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
||||
@@ -1,3 +0,0 @@
|
||||
dependencies:
|
||||
local/esp-nimble-cpp:
|
||||
path: ../../../../../esp-nimble-cpp/
|
||||
@@ -1,165 +0,0 @@
|
||||
#include <NimBLEDevice.h>
|
||||
|
||||
// See the following for generating UUIDs:
|
||||
// https://www.uuidgenerator.net/
|
||||
|
||||
// The remote service we wish to connect to.
|
||||
static BLEUUID serviceUUID("dcbc7255-1e9e-49a0-a360-b0430b6c6905");
|
||||
// The characteristic of the remote service we are interested in.
|
||||
static BLEUUID charUUID("371a55c8-f251-4ad2-90b3-c7c195b049be");
|
||||
|
||||
#define L2CAP_CHANNEL 150
|
||||
#define L2CAP_MTU 5000
|
||||
|
||||
const BLEAdvertisedDevice* theDevice = NULL;
|
||||
BLEClient* theClient = NULL;
|
||||
BLEL2CAPChannel* theChannel = NULL;
|
||||
|
||||
size_t bytesSent = 0;
|
||||
size_t bytesReceived = 0;
|
||||
|
||||
class L2CAPChannelCallbacks: public BLEL2CAPChannelCallbacks {
|
||||
|
||||
public:
|
||||
void onConnect(NimBLEL2CAPChannel* channel) {
|
||||
printf("L2CAP connection established\n");
|
||||
}
|
||||
|
||||
void onMTUChange(NimBLEL2CAPChannel* channel, uint16_t mtu) {
|
||||
printf("L2CAP MTU changed to %d\n", mtu);
|
||||
}
|
||||
|
||||
void onRead(NimBLEL2CAPChannel* channel, std::vector<uint8_t>& data) {
|
||||
printf("L2CAP read %d bytes\n", data.size());
|
||||
}
|
||||
void onDisconnect(NimBLEL2CAPChannel* channel) {
|
||||
printf("L2CAP disconnected\n");
|
||||
}
|
||||
};
|
||||
|
||||
class MyClientCallbacks: public BLEClientCallbacks {
|
||||
|
||||
void onConnect(BLEClient* pClient) {
|
||||
printf("GAP connected\n");
|
||||
pClient->setDataLen(251);
|
||||
|
||||
theChannel = BLEL2CAPChannel::connect(pClient, L2CAP_CHANNEL, L2CAP_MTU, new L2CAPChannelCallbacks());
|
||||
}
|
||||
|
||||
void onDisconnect(BLEClient* pClient, int reason) {
|
||||
printf("GAP disconnected (reason: %d)\n", reason);
|
||||
theDevice = NULL;
|
||||
theChannel = NULL;
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
BLEDevice::getScan()->start(5 * 1000, true);
|
||||
}
|
||||
};
|
||||
|
||||
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
|
||||
|
||||
void onResult(const BLEAdvertisedDevice* advertisedDevice) {
|
||||
if (theDevice) { return; }
|
||||
printf("BLE Advertised Device found: %s\n", advertisedDevice->toString().c_str());
|
||||
|
||||
if (!advertisedDevice->haveServiceUUID()) { return; }
|
||||
if (!advertisedDevice->isAdvertisingService(serviceUUID)) { return; }
|
||||
|
||||
printf("Found the device we're interested in!\n");
|
||||
BLEDevice::getScan()->stop();
|
||||
|
||||
// Hand over the device to the other task
|
||||
theDevice = advertisedDevice;
|
||||
}
|
||||
};
|
||||
|
||||
void connectTask(void *pvParameters) {
|
||||
|
||||
uint8_t sequenceNumber = 0;
|
||||
|
||||
while (true) {
|
||||
|
||||
if (!theDevice) {
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!theClient) {
|
||||
theClient = BLEDevice::createClient();
|
||||
theClient->setConnectionParams(6, 6, 0, 42);
|
||||
|
||||
auto callbacks = new MyClientCallbacks();
|
||||
theClient->setClientCallbacks(callbacks);
|
||||
|
||||
auto success = theClient->connect(theDevice);
|
||||
if (!success) {
|
||||
printf("Error: Could not connect to device\n");
|
||||
break;
|
||||
}
|
||||
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!theChannel) {
|
||||
printf("l2cap channel not initialized\n");
|
||||
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!theChannel->isConnected()) {
|
||||
printf("l2cap channel not connected\n");
|
||||
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
||||
continue;
|
||||
}
|
||||
|
||||
while (theChannel->isConnected()) {
|
||||
|
||||
/*
|
||||
static auto initialDelay = true;
|
||||
if (initialDelay) {
|
||||
printf("Waiting gracefully 3 seconds before sending data\n");
|
||||
vTaskDelay(3000 / portTICK_PERIOD_MS);
|
||||
initialDelay = false;
|
||||
};
|
||||
*/
|
||||
std::vector<uint8_t> data(5000, sequenceNumber++);
|
||||
if (theChannel->write(data)) {
|
||||
bytesSent += data.size();
|
||||
} else {
|
||||
printf("failed to send!\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C"
|
||||
void app_main(void) {
|
||||
printf("Starting L2CAP client example\n");
|
||||
|
||||
xTaskCreate(connectTask, "connectTask", 5000, NULL, 1, NULL);
|
||||
|
||||
BLEDevice::init("L2CAP-Client");
|
||||
BLEDevice::setMTU(BLE_ATT_MTU_MAX);
|
||||
|
||||
auto scan = BLEDevice::getScan();
|
||||
auto callbacks = new MyAdvertisedDeviceCallbacks();
|
||||
scan->setScanCallbacks(callbacks);
|
||||
scan->setInterval(1349);
|
||||
scan->setWindow(449);
|
||||
scan->setActiveScan(true);
|
||||
scan->start(25 * 1000, false);
|
||||
|
||||
int numberOfSeconds = 0;
|
||||
|
||||
while (bytesSent == 0) {
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
while (true) {
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
int bytesSentPerSeconds = bytesSent / ++numberOfSeconds;
|
||||
printf("Bandwidth: %d b/sec = %d KB/sec\n", bytesSentPerSeconds, bytesSentPerSeconds / 1024);
|
||||
}
|
||||
}
|
||||
@@ -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_L2CAP_COC_MAX_NUM=1
|
||||
@@ -1,7 +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)
|
||||
set(SUPPORTED_TARGETS esp32 esp32s3 esp32c3 esp32c6)
|
||||
project(L2CAP_server)
|
||||
@@ -1,3 +0,0 @@
|
||||
PROJECT_NAME := L2CAP_server
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
@@ -1,4 +0,0 @@
|
||||
set(COMPONENT_SRCS "main.cpp")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||
|
||||
register_component()
|
||||
@@ -1,4 +0,0 @@
|
||||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
||||
@@ -1,3 +0,0 @@
|
||||
dependencies:
|
||||
local/esp-nimble-cpp:
|
||||
path: ../../../../../esp-nimble-cpp/
|
||||
@@ -1,90 +0,0 @@
|
||||
#include <NimBLEDevice.h>
|
||||
|
||||
// See the following for generating UUIDs:
|
||||
// https://www.uuidgenerator.net/
|
||||
|
||||
#define SERVICE_UUID "dcbc7255-1e9e-49a0-a360-b0430b6c6905"
|
||||
#define CHARACTERISTIC_UUID "371a55c8-f251-4ad2-90b3-c7c195b049be"
|
||||
#define L2CAP_CHANNEL 150
|
||||
#define L2CAP_MTU 5000
|
||||
|
||||
class GATTCallbacks: public BLEServerCallbacks {
|
||||
|
||||
public:
|
||||
void onConnect(BLEServer* pServer, BLEConnInfo& info) {
|
||||
/// Booster #1
|
||||
pServer->setDataLen(info.getConnHandle(), 251);
|
||||
/// Booster #2 (especially for Apple devices)
|
||||
BLEDevice::getServer()->updateConnParams(info.getConnHandle(), 12, 12, 0, 200);
|
||||
}
|
||||
};
|
||||
|
||||
class L2CAPChannelCallbacks: public BLEL2CAPChannelCallbacks {
|
||||
|
||||
public:
|
||||
bool connected = false;
|
||||
size_t numberOfReceivedBytes;
|
||||
uint8_t nextSequenceNumber;
|
||||
|
||||
public:
|
||||
void onConnect(NimBLEL2CAPChannel* channel) {
|
||||
printf("L2CAP connection established\n");
|
||||
connected = true;
|
||||
numberOfReceivedBytes = nextSequenceNumber = 0;
|
||||
}
|
||||
|
||||
void onRead(NimBLEL2CAPChannel* channel, std::vector<uint8_t>& data) {
|
||||
numberOfReceivedBytes += data.size();
|
||||
size_t sequenceNumber = data[0];
|
||||
printf("L2CAP read %d bytes w/ sequence number %d", data.size(), sequenceNumber);
|
||||
if (sequenceNumber != nextSequenceNumber) {
|
||||
printf("(wrong sequence number %d, expected %d)\n", sequenceNumber, nextSequenceNumber);
|
||||
} else {
|
||||
printf("\n");
|
||||
nextSequenceNumber++;
|
||||
}
|
||||
}
|
||||
void onDisconnect(NimBLEL2CAPChannel* channel) {
|
||||
printf("L2CAP disconnected\n");
|
||||
connected = false;
|
||||
}
|
||||
};
|
||||
|
||||
extern "C"
|
||||
void app_main(void) {
|
||||
printf("Starting L2CAP server example [%lu free] [%lu min]\n", esp_get_free_heap_size(), esp_get_minimum_free_heap_size());
|
||||
|
||||
BLEDevice::init("L2CAP-Server");
|
||||
BLEDevice::setMTU(BLE_ATT_MTU_MAX);
|
||||
|
||||
auto cocServer = BLEDevice::createL2CAPServer();
|
||||
auto l2capChannelCallbacks = new L2CAPChannelCallbacks();
|
||||
auto channel = cocServer->createService(L2CAP_CHANNEL, L2CAP_MTU, l2capChannelCallbacks);
|
||||
|
||||
auto server = BLEDevice::createServer();
|
||||
server->setCallbacks(new GATTCallbacks());
|
||||
auto service = server->createService(SERVICE_UUID);
|
||||
auto characteristic = service->createCharacteristic(CHARACTERISTIC_UUID, NIMBLE_PROPERTY::READ);
|
||||
characteristic->setValue(L2CAP_CHANNEL);
|
||||
service->start();
|
||||
auto advertising = BLEDevice::getAdvertising();
|
||||
advertising->addServiceUUID(SERVICE_UUID);
|
||||
advertising->enableScanResponse(true);
|
||||
|
||||
BLEDevice::startAdvertising();
|
||||
printf("Server waiting for connection requests [%lu free] [%lu min]\n", esp_get_free_heap_size(), esp_get_minimum_free_heap_size());
|
||||
|
||||
// Wait until transfer actually starts...
|
||||
while (!l2capChannelCallbacks->numberOfReceivedBytes) {
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
}
|
||||
printf("\n\n\n");
|
||||
int numberOfSeconds = 0;
|
||||
|
||||
while (true) {
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
if (!l2capChannelCallbacks->connected) { continue; }
|
||||
int bps = l2capChannelCallbacks->numberOfReceivedBytes / ++numberOfSeconds;
|
||||
printf("Bandwidth: %d b/sec = %d KB/sec [%lu free] [%lu min]\n", bps, bps / 1024, esp_get_free_heap_size(), esp_get_minimum_free_heap_size());
|
||||
}
|
||||
}
|
||||
@@ -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_L2CAP_COC_MAX_NUM=1
|
||||
@@ -112,7 +112,7 @@ bool connectToServer() {
|
||||
|
||||
/** No client to reuse? Create a new one. */
|
||||
if (!pClient) {
|
||||
if (NimBLEDevice::getCreatedClientCount() >= MYNEWT_VAL(BLE_MAX_CONNECTIONS)) {
|
||||
if (NimBLEDevice::getCreatedClientCount() >= NIMBLE_MAX_CONNECTIONS) {
|
||||
printf("Max clients reached - no more connections available\n");
|
||||
return false;
|
||||
}
|
||||
@@ -261,7 +261,8 @@ extern "C" void app_main(void) {
|
||||
* 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);
|
||||
|
||||
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 */
|
||||
|
||||
@@ -16,7 +16,7 @@ static NimBLEServer* pServer;
|
||||
** Remove as you see fit for your needs */
|
||||
class ServerCallbacks : public NimBLEServerCallbacks {
|
||||
void onConnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo) override {
|
||||
printf("Client connected:\n%s", connInfo.toString().c_str());
|
||||
printf("Client address: %s\n", connInfo.getAddress().toString().c_str());
|
||||
|
||||
/**
|
||||
* We can use the connection handle here to ask for different connection parameters.
|
||||
@@ -142,8 +142,8 @@ extern "C" void app_main(void) {
|
||||
* 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);
|
||||
|
||||
NimBLEDevice::setSecurityAuth(/*BLE_SM_PAIR_AUTHREQ_BOND | BLE_SM_PAIR_AUTHREQ_MITM |*/ BLE_SM_PAIR_AUTHREQ_SC);
|
||||
pServer = NimBLEDevice::createServer();
|
||||
pServer->setCallbacks(&serverCallbacks);
|
||||
|
||||
@@ -184,6 +184,10 @@ extern "C" void app_main(void) {
|
||||
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");
|
||||
|
||||
@@ -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_Stream_Client)
|
||||
@@ -1,53 +0,0 @@
|
||||
# NimBLE Stream Client Example
|
||||
|
||||
This example demonstrates how to use the `NimBLEStreamClient` class to connect to a BLE GATT server and communicate using the familiar Arduino Stream interface.
|
||||
|
||||
## Features
|
||||
|
||||
- Uses Arduino Stream interface (print, println, read, available, etc.)
|
||||
- Automatic server discovery and connection
|
||||
- Bidirectional communication
|
||||
- Buffered TX/RX using ring buffers
|
||||
- Automatic reconnection on disconnect
|
||||
- Similar usage to Serial communication
|
||||
|
||||
## How it Works
|
||||
|
||||
1. Scans for BLE devices advertising the target service UUID
|
||||
2. Connects to the server and discovers the stream characteristic
|
||||
3. Initializes `NimBLEStreamClient` with the remote characteristic
|
||||
4. Subscribes to notifications to receive data in the RX buffer
|
||||
5. Uses familiar Stream methods like `print()`, `println()`, `read()`, and `available()`
|
||||
|
||||
## Usage
|
||||
|
||||
1. Build and flash the NimBLE_Stream_Server example to one ESP32 using ESP-IDF (`idf.py build flash monitor`)
|
||||
2. Build and flash this client example to another ESP32 using ESP-IDF
|
||||
3. The client will automatically:
|
||||
- Scan for the server
|
||||
- Connect when found
|
||||
- Set up the stream interface
|
||||
- Begin bidirectional communication
|
||||
4. Open `idf.py monitor` on each board to observe stream traffic
|
||||
|
||||
## Service UUIDs
|
||||
|
||||
Must match the server:
|
||||
- Service: `6E400001-B5A3-F393-E0A9-E50E24DCCA9E`
|
||||
- Characteristic: `6E400002-B5A3-F393-E0A9-E50E24DCCA9E`
|
||||
|
||||
## Monitor Output
|
||||
|
||||
The example displays:
|
||||
- Server discovery progress
|
||||
- Connection status
|
||||
- All data received from the server
|
||||
- Confirmation of data sent to the server
|
||||
|
||||
## Testing
|
||||
|
||||
Run with NimBLE_Stream_Server to see bidirectional communication:
|
||||
- Server sends periodic status messages
|
||||
- Client sends periodic uptime messages
|
||||
- Both echo data received from each other
|
||||
- You can send data from either `idf.py monitor` session
|
||||
@@ -1,4 +0,0 @@
|
||||
set(COMPONENT_SRCS "main.cpp")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||
|
||||
register_component()
|
||||
@@ -1,217 +0,0 @@
|
||||
/**
|
||||
* NimBLE_Stream_Client Example:
|
||||
*
|
||||
* Demonstrates using NimBLEStreamClient to connect to a BLE GATT server
|
||||
* and communicate using the Stream-like interface.
|
||||
*
|
||||
* This example connects to the NimBLE_Stream_Server example.
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "esp_timer.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#include <NimBLEDevice.h>
|
||||
|
||||
// Service and Characteristic UUIDs (must match the server)
|
||||
#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
|
||||
#define CHARACTERISTIC_UUID "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
|
||||
|
||||
// Create the stream client instance
|
||||
NimBLEStreamClient bleStream;
|
||||
|
||||
struct RxOverflowStats {
|
||||
uint32_t droppedOld{0};
|
||||
uint32_t droppedNew{0};
|
||||
};
|
||||
|
||||
RxOverflowStats g_rxOverflowStats;
|
||||
uint32_t scanTime = 5000; // Scan duration in milliseconds
|
||||
|
||||
NimBLEStream::RxOverflowAction onRxOverflow(const uint8_t* data, size_t len, void* userArg) {
|
||||
auto* stats = static_cast<RxOverflowStats*>(userArg);
|
||||
if (stats) {
|
||||
stats->droppedOld++;
|
||||
}
|
||||
|
||||
// For status/telemetry streams, prioritize newest packets.
|
||||
(void)data;
|
||||
(void)len;
|
||||
return NimBLEStream::DROP_OLDER_DATA;
|
||||
}
|
||||
|
||||
static uint64_t millis() {
|
||||
return esp_timer_get_time() / 1000ULL;
|
||||
}
|
||||
|
||||
// Connection state variables
|
||||
static bool doConnect = false;
|
||||
static bool connected = false;
|
||||
static const NimBLEAdvertisedDevice* pServerDevice = nullptr;
|
||||
static NimBLEClient* pClient = nullptr;
|
||||
|
||||
/** Scan callbacks to find the server */
|
||||
class ScanCallbacks : public NimBLEScanCallbacks {
|
||||
void onResult(const NimBLEAdvertisedDevice* advertisedDevice) override {
|
||||
printf("Advertised Device: %s\n", advertisedDevice->toString().c_str());
|
||||
|
||||
// Check if this device advertises our service.
|
||||
if (advertisedDevice->isAdvertisingService(NimBLEUUID(SERVICE_UUID))) {
|
||||
printf("Found our stream server!\n");
|
||||
pServerDevice = advertisedDevice;
|
||||
NimBLEDevice::getScan()->stop();
|
||||
doConnect = true;
|
||||
}
|
||||
}
|
||||
|
||||
void onScanEnd(const NimBLEScanResults& results, int reason) override {
|
||||
(void)results;
|
||||
(void)reason;
|
||||
printf("Scan ended\n");
|
||||
if (!doConnect && !connected) {
|
||||
printf("Server not found, restarting scan...\n");
|
||||
NimBLEDevice::getScan()->start(scanTime, false, true);
|
||||
}
|
||||
}
|
||||
} scanCallbacks;
|
||||
|
||||
/** Client callbacks for connection/disconnection events */
|
||||
class ClientCallbacks : public NimBLEClientCallbacks {
|
||||
void onConnect(NimBLEClient* pClient) override {
|
||||
printf("Connected to server\n");
|
||||
// Update connection parameters for better throughput.
|
||||
pClient->updateConnParams(12, 24, 0, 200);
|
||||
}
|
||||
|
||||
void onDisconnect(NimBLEClient* pClient, int reason) override {
|
||||
(void)pClient;
|
||||
printf("Disconnected from server, reason: %d\n", reason);
|
||||
connected = false;
|
||||
bleStream.end();
|
||||
|
||||
// Restart scanning.
|
||||
printf("Restarting scan...\n");
|
||||
NimBLEDevice::getScan()->start(scanTime, false, true);
|
||||
}
|
||||
} clientCallbacks;
|
||||
|
||||
/** Connect to the BLE Server and set up the stream */
|
||||
bool connectToServer() {
|
||||
printf("Connecting to: %s\n", pServerDevice->getAddress().toString().c_str());
|
||||
|
||||
// Create or reuse a client.
|
||||
pClient = NimBLEDevice::getClientByPeerAddress(pServerDevice->getAddress());
|
||||
if (!pClient) {
|
||||
pClient = NimBLEDevice::createClient();
|
||||
if (!pClient) {
|
||||
printf("Failed to create client\n");
|
||||
return false;
|
||||
}
|
||||
pClient->setClientCallbacks(&clientCallbacks, false);
|
||||
pClient->setConnectionParams(12, 24, 0, 200);
|
||||
pClient->setConnectTimeout(5000);
|
||||
}
|
||||
|
||||
// Connect to the remote BLE Server.
|
||||
if (!pClient->connect(pServerDevice)) {
|
||||
printf("Failed to connect to server\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
printf("Connected! Discovering services...\n");
|
||||
|
||||
// Get the service and characteristic.
|
||||
NimBLERemoteService* pRemoteService = pClient->getService(SERVICE_UUID);
|
||||
if (!pRemoteService) {
|
||||
printf("Failed to find our service UUID\n");
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
printf("Found the stream service\n");
|
||||
|
||||
NimBLERemoteCharacteristic* pRemoteCharacteristic = pRemoteService->getCharacteristic(CHARACTERISTIC_UUID);
|
||||
if (!pRemoteCharacteristic) {
|
||||
printf("Failed to find our characteristic UUID\n");
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
printf("Found the stream characteristic\n");
|
||||
|
||||
// subscribeNotify=true means notifications are stored in the RX buffer.
|
||||
if (!bleStream.begin(pRemoteCharacteristic, true)) {
|
||||
printf("Failed to initialize BLE stream!\n");
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
|
||||
bleStream.setRxOverflowCallback(onRxOverflow, &g_rxOverflowStats);
|
||||
|
||||
printf("BLE Stream initialized successfully!\n");
|
||||
connected = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
extern "C" void app_main(void) {
|
||||
printf("Starting NimBLE Stream Client\n");
|
||||
|
||||
/** Initialize NimBLE */
|
||||
NimBLEDevice::init("NimBLE-StreamClient");
|
||||
|
||||
// Create the BLE scan instance and set callbacks.
|
||||
NimBLEScan* pScan = NimBLEDevice::getScan();
|
||||
pScan->setScanCallbacks(&scanCallbacks, false);
|
||||
pScan->setActiveScan(true);
|
||||
|
||||
// Start scanning for the server.
|
||||
printf("Scanning for BLE Stream Server...\n");
|
||||
pScan->start(scanTime, false, true);
|
||||
|
||||
uint32_t lastDroppedOld = 0;
|
||||
uint32_t lastDroppedNew = 0;
|
||||
uint64_t lastSend = 0;
|
||||
|
||||
for (;;) {
|
||||
if (g_rxOverflowStats.droppedOld != lastDroppedOld || g_rxOverflowStats.droppedNew != lastDroppedNew) {
|
||||
lastDroppedOld = g_rxOverflowStats.droppedOld;
|
||||
lastDroppedNew = g_rxOverflowStats.droppedNew;
|
||||
printf("RX overflow handled (drop-old=%" PRIu32 ", drop-new=%" PRIu32 ")\n", lastDroppedOld, lastDroppedNew);
|
||||
}
|
||||
|
||||
// If we found a server, try to connect.
|
||||
if (doConnect) {
|
||||
doConnect = false;
|
||||
if (connectToServer()) {
|
||||
printf("Stream ready for communication!\n");
|
||||
} else {
|
||||
printf("Failed to connect to server, restarting scan...\n");
|
||||
pServerDevice = nullptr;
|
||||
NimBLEDevice::getScan()->start(scanTime, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
// If connected, demonstrate stream communication.
|
||||
if (connected && bleStream) {
|
||||
if (bleStream.available()) {
|
||||
printf("Received from server: ");
|
||||
while (bleStream.available()) {
|
||||
char c = bleStream.read();
|
||||
putchar(c);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
uint64_t now = millis();
|
||||
if (now - lastSend > 5000) {
|
||||
lastSend = now;
|
||||
bleStream.printf("Hello from client! Uptime: %" PRIu64 " seconds\n", now / 1000);
|
||||
printf("Sent data to server via BLE stream\n");
|
||||
}
|
||||
}
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
}
|
||||
}
|
||||
@@ -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_Stream_Echo)
|
||||
@@ -1,39 +0,0 @@
|
||||
# NimBLE Stream Echo Example
|
||||
|
||||
This is the simplest example demonstrating `NimBLEStreamServer`. It echoes back any data received from BLE clients.
|
||||
|
||||
## Features
|
||||
|
||||
- Minimal code showing essential NimBLE Stream usage
|
||||
- Echoes all received data back to the client
|
||||
- Uses default service and characteristic UUIDs
|
||||
- Perfect starting point for learning the Stream interface
|
||||
|
||||
## How it Works
|
||||
|
||||
1. Initializes BLE with minimal configuration
|
||||
2. Creates a stream server with default UUIDs
|
||||
3. Waits for client connection and data
|
||||
4. Echoes received data back to the client
|
||||
5. Displays received data in the ESP-IDF monitor output
|
||||
|
||||
## Default UUIDs
|
||||
|
||||
- Service: `0xc0de`
|
||||
- Characteristic: `0xfeed`
|
||||
|
||||
## Usage
|
||||
|
||||
1. Build and flash this example to your ESP32 using ESP-IDF (`idf.py build flash monitor`)
|
||||
2. Connect with a BLE client app (nRF Connect, Serial Bluetooth Terminal, etc.)
|
||||
3. Find the service `0xc0de` and characteristic `0xfeed`
|
||||
4. Subscribe to notifications
|
||||
5. Write data to the characteristic
|
||||
6. The data will be echoed back and displayed in `idf.py monitor`
|
||||
|
||||
## Good For
|
||||
|
||||
- Learning the basic NimBLE Stream API
|
||||
- Testing BLE connectivity
|
||||
- Starting point for custom applications
|
||||
- Understanding Stream read/write operations
|
||||
@@ -1,4 +0,0 @@
|
||||
set(COMPONENT_SRCS "main.cpp")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||
|
||||
register_component()
|
||||
@@ -1,83 +0,0 @@
|
||||
/**
|
||||
* NimBLE_Stream_Echo Example:
|
||||
*
|
||||
* A minimal example demonstrating NimBLEStreamServer.
|
||||
* Echoes back any data received from BLE clients.
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#include <NimBLEDevice.h>
|
||||
|
||||
NimBLEStreamServer bleStream;
|
||||
|
||||
struct RxOverflowStats {
|
||||
uint32_t droppedOld{0};
|
||||
uint32_t droppedNew{0};
|
||||
};
|
||||
|
||||
RxOverflowStats g_rxOverflowStats;
|
||||
|
||||
NimBLEStream::RxOverflowAction onRxOverflow(const uint8_t* data, size_t len, void* userArg) {
|
||||
auto* stats = static_cast<RxOverflowStats*>(userArg);
|
||||
if (stats) {
|
||||
stats->droppedOld++;
|
||||
}
|
||||
|
||||
// Echo mode prefers the latest incoming bytes.
|
||||
(void)data;
|
||||
(void)len;
|
||||
return NimBLEStream::DROP_OLDER_DATA;
|
||||
}
|
||||
|
||||
extern "C" void app_main(void) {
|
||||
printf("NimBLE Stream Echo Server\n");
|
||||
|
||||
// Initialize BLE.
|
||||
NimBLEDevice::init("BLE-Echo");
|
||||
auto pServer = NimBLEDevice::createServer();
|
||||
pServer->advertiseOnDisconnect(true); // Keep advertising after disconnects.
|
||||
|
||||
if (!bleStream.begin(NimBLEUUID(uint16_t(0xc0de)),
|
||||
NimBLEUUID(uint16_t(0xfeed)),
|
||||
1024,
|
||||
1024,
|
||||
false)) {
|
||||
printf("Failed to initialize BLE stream\n");
|
||||
return;
|
||||
}
|
||||
|
||||
bleStream.setRxOverflowCallback(onRxOverflow, &g_rxOverflowStats);
|
||||
|
||||
// Start advertising.
|
||||
NimBLEDevice::getAdvertising()->start();
|
||||
printf("Ready! Connect with a BLE client and send data.\n");
|
||||
|
||||
uint32_t lastDroppedOld = 0;
|
||||
uint32_t lastDroppedNew = 0;
|
||||
|
||||
for (;;) {
|
||||
if (g_rxOverflowStats.droppedOld != lastDroppedOld || g_rxOverflowStats.droppedNew != lastDroppedNew) {
|
||||
lastDroppedOld = g_rxOverflowStats.droppedOld;
|
||||
lastDroppedNew = g_rxOverflowStats.droppedNew;
|
||||
printf("RX overflow handled (drop-old=%" PRIu32 ", drop-new=%" PRIu32 ")\n", lastDroppedOld, lastDroppedNew);
|
||||
}
|
||||
|
||||
// Echo any received data back to the client.
|
||||
if (bleStream.ready() && bleStream.available()) {
|
||||
printf("Echo: ");
|
||||
while (bleStream.available()) {
|
||||
char c = bleStream.read();
|
||||
putchar(c);
|
||||
bleStream.write(c);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
}
|
||||
}
|
||||
@@ -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_Stream_Server)
|
||||
@@ -1,42 +0,0 @@
|
||||
# NimBLE Stream Server Example
|
||||
|
||||
This example demonstrates how to use the `NimBLEStreamServer` class to create a BLE GATT server that behaves like a serial port using the familiar Arduino Stream interface.
|
||||
|
||||
## Features
|
||||
|
||||
- Uses Arduino Stream interface (print, println, read, available, etc.)
|
||||
- Automatic connection management
|
||||
- Bidirectional communication
|
||||
- Buffered TX/RX using ring buffers
|
||||
- Similar usage to Serial communication
|
||||
|
||||
## How it Works
|
||||
|
||||
1. Creates a BLE GATT server with a custom service and characteristic
|
||||
2. Initializes `NimBLEStreamServer` with the characteristic configured for notifications and writes
|
||||
3. Uses familiar Stream methods like `print()`, `println()`, `read()`, and `available()`
|
||||
4. Automatically handles connection state and MTU negotiation
|
||||
|
||||
## Usage
|
||||
|
||||
1. Build and flash this example to your ESP32 using ESP-IDF (`idf.py build flash monitor`)
|
||||
2. The device will advertise as "NimBLE-Stream"
|
||||
3. Connect with a BLE client (such as the NimBLE_Stream_Client example or a mobile app)
|
||||
4. Once connected, the server will:
|
||||
- Send periodic messages to the client
|
||||
- Echo back any data received from the client
|
||||
- Display all communication in `idf.py monitor`
|
||||
|
||||
## Service UUIDs
|
||||
|
||||
- Service: `6E400001-B5A3-F393-E0A9-E50E24DCCA9E`
|
||||
- Characteristic: `6E400002-B5A3-F393-E0A9-E50E24DCCA9E`
|
||||
|
||||
These are based on the Nordic UART Service (NUS) UUIDs for compatibility with many BLE terminal apps.
|
||||
|
||||
## Compatible With
|
||||
|
||||
- NimBLE_Stream_Client example
|
||||
- nRF Connect mobile app
|
||||
- Serial Bluetooth Terminal apps
|
||||
- Any BLE client that supports characteristic notifications and writes
|
||||
@@ -1,4 +0,0 @@
|
||||
set(COMPONENT_SRCS "main.cpp")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||
|
||||
register_component()
|
||||
@@ -1,146 +0,0 @@
|
||||
/**
|
||||
* NimBLE_Stream_Server Example:
|
||||
*
|
||||
* Demonstrates using NimBLEStreamServer to create a BLE GATT server
|
||||
* that behaves like a serial port using the Stream-like interface.
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_timer.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#include <NimBLEDevice.h>
|
||||
|
||||
// Create the stream server instance
|
||||
NimBLEStreamServer bleStream;
|
||||
|
||||
struct RxOverflowStats {
|
||||
uint32_t droppedOld{0};
|
||||
uint32_t droppedNew{0};
|
||||
};
|
||||
|
||||
RxOverflowStats g_rxOverflowStats;
|
||||
|
||||
NimBLEStream::RxOverflowAction onRxOverflow(const uint8_t* data, size_t len, void* userArg) {
|
||||
auto* stats = static_cast<RxOverflowStats*>(userArg);
|
||||
if (stats) {
|
||||
stats->droppedOld++;
|
||||
}
|
||||
|
||||
// Keep the newest bytes for command/stream style traffic.
|
||||
(void)data;
|
||||
(void)len;
|
||||
return NimBLEStream::DROP_OLDER_DATA;
|
||||
}
|
||||
|
||||
static uint64_t millis() {
|
||||
return esp_timer_get_time() / 1000ULL;
|
||||
}
|
||||
|
||||
// Service and Characteristic UUIDs for the stream.
|
||||
#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
|
||||
#define CHARACTERISTIC_UUID "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
|
||||
|
||||
/** Server callbacks to handle connection/disconnection events */
|
||||
class ServerCallbacks : public NimBLEServerCallbacks {
|
||||
void onConnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo) override {
|
||||
printf("Client connected: %s\n", connInfo.getAddress().toString().c_str());
|
||||
// Optionally update connection parameters for better throughput.
|
||||
pServer->updateConnParams(connInfo.getConnHandle(), 12, 24, 0, 200);
|
||||
}
|
||||
|
||||
void onDisconnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo, int reason) override {
|
||||
(void)pServer;
|
||||
(void)connInfo;
|
||||
printf("Client disconnected - reason: %d, restarting advertising\n", reason);
|
||||
NimBLEDevice::startAdvertising();
|
||||
}
|
||||
|
||||
void onMTUChange(uint16_t MTU, NimBLEConnInfo& connInfo) override {
|
||||
printf("MTU updated: %u for connection ID: %u\n", MTU, connInfo.getConnHandle());
|
||||
}
|
||||
} serverCallbacks;
|
||||
|
||||
extern "C" void app_main(void) {
|
||||
printf("Starting NimBLE Stream Server\n");
|
||||
|
||||
/** Initialize NimBLE and set the device name */
|
||||
NimBLEDevice::init("NimBLE-Stream");
|
||||
|
||||
/**
|
||||
* Create the BLE server and set callbacks.
|
||||
* Note: The stream will create its own service and characteristic.
|
||||
*/
|
||||
NimBLEServer* pServer = NimBLEDevice::createServer();
|
||||
pServer->setCallbacks(&serverCallbacks);
|
||||
|
||||
/**
|
||||
* Initialize the stream server with:
|
||||
* - Service UUID
|
||||
* - Characteristic UUID
|
||||
* - txBufSize: 1024 bytes for outgoing data (notifications)
|
||||
* - rxBufSize: 1024 bytes for incoming data (writes)
|
||||
* - secure: false (no encryption required - set true for secure connections)
|
||||
*/
|
||||
if (!bleStream.begin(NimBLEUUID(SERVICE_UUID),
|
||||
NimBLEUUID(CHARACTERISTIC_UUID),
|
||||
1024,
|
||||
1024,
|
||||
false)) {
|
||||
printf("Failed to initialize BLE stream!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
bleStream.setRxOverflowCallback(onRxOverflow, &g_rxOverflowStats);
|
||||
|
||||
// Make the stream service discoverable.
|
||||
NimBLEAdvertising* pAdvertising = NimBLEDevice::getAdvertising();
|
||||
pAdvertising->addServiceUUID(SERVICE_UUID);
|
||||
pAdvertising->setName("NimBLE-Stream");
|
||||
pAdvertising->enableScanResponse(true);
|
||||
pAdvertising->start();
|
||||
|
||||
printf("BLE Stream Server ready!\n");
|
||||
printf("Waiting for client connection...\n");
|
||||
|
||||
uint32_t lastDroppedOld = 0;
|
||||
uint32_t lastDroppedNew = 0;
|
||||
uint64_t lastSend = 0;
|
||||
|
||||
for (;;) {
|
||||
if (g_rxOverflowStats.droppedOld != lastDroppedOld || g_rxOverflowStats.droppedNew != lastDroppedNew) {
|
||||
lastDroppedOld = g_rxOverflowStats.droppedOld;
|
||||
lastDroppedNew = g_rxOverflowStats.droppedNew;
|
||||
printf("RX overflow handled (drop-old=%" PRIu32 ", drop-new=%" PRIu32 ")\n", lastDroppedOld, lastDroppedNew);
|
||||
}
|
||||
|
||||
if (bleStream.ready()) {
|
||||
uint64_t now = millis();
|
||||
if (now - lastSend > 2000) {
|
||||
lastSend = now;
|
||||
bleStream.printf("Hello from server! Uptime: %" PRIu64 " seconds\n", now / 1000);
|
||||
bleStream.printf("Free heap: %" PRIu32 " bytes\n", esp_get_free_heap_size());
|
||||
printf("Sent data to client via BLE stream\n");
|
||||
}
|
||||
|
||||
if (bleStream.available()) {
|
||||
printf("Received from client: ");
|
||||
while (bleStream.available()) {
|
||||
char c = bleStream.read();
|
||||
putchar(c);
|
||||
bleStream.write(c); // Echo back to BLE client.
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
} else {
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
}
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
}
|
||||
}
|
||||
@@ -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,5 +1,5 @@
|
||||
## IDF Component Manager Manifest File
|
||||
version: "2.4.0"
|
||||
version: "2.2.1"
|
||||
license: "Apache-2.0"
|
||||
description: "C++ wrapper for the NimBLE BLE stack"
|
||||
url: "https://github.com/h2zero/esp-nimble-cpp"
|
||||
@@ -16,7 +16,7 @@ dependencies:
|
||||
rules:
|
||||
- if: "target in [esp32p4]"
|
||||
espressif/esp_wifi_remote:
|
||||
version: ">=0.5.3"
|
||||
version: "<0.5.4"
|
||||
rules:
|
||||
- if: "target in [esp32p4]"
|
||||
idf:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "esp-nimble-cpp",
|
||||
"version": "2.4.0",
|
||||
"version": "2.2.1",
|
||||
"description": "C++ wrapper for the NimBLE BLE stack",
|
||||
"keywords": [
|
||||
"BLE",
|
||||
@@ -19,10 +19,5 @@
|
||||
"email": "ryan@nable-embedded.io",
|
||||
"url": "https://github.com/h2zero/esp-nimble-cpp",
|
||||
"maintainer": true
|
||||
},
|
||||
"build": {
|
||||
"flags": [
|
||||
"-DCONFIG_NIMBLE_CPP_IDF=1"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,8 +15,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "NimBLE2904.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && 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) {
|
||||
@@ -69,4 +71,4 @@ void NimBLE2904::setUnit(uint16_t unit) {
|
||||
setValue(m_data);
|
||||
} // setUnit
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
#ifndef NIMBLE_CPP_2904_H_
|
||||
#define NIMBLE_CPP_2904_H_
|
||||
|
||||
#include "syscfg/syscfg.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
|
||||
# include "NimBLEDescriptor.h"
|
||||
|
||||
@@ -79,5 +79,5 @@ class NimBLE2904 : public NimBLEDescriptor {
|
||||
NimBLE2904Data m_data{};
|
||||
}; // NimBLE2904
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
#endif // CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL
|
||||
#endif // NIMBLE_CPP_2904_H_
|
||||
|
||||
@@ -15,36 +15,21 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "NimBLEAddress.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
# include "NimBLEAddress.h"
|
||||
# include "NimBLELog.h"
|
||||
|
||||
# include <algorithm>
|
||||
|
||||
# ifndef MYNEWT_VAL_NIMBLE_CPP_ADDR_FMT_EXCLUDE_DELIMITER
|
||||
# ifndef CONFIG_NIMBLE_CPP_ADDR_FMT_EXCLUDE_DELIMITER
|
||||
# define MYNEWT_VAL_NIMBLE_CPP_ADDR_FMT_EXCLUDE_DELIMITER (0)
|
||||
# else
|
||||
# define MYNEWT_VAL_NIMBLE_CPP_ADDR_FMT_EXCLUDE_DELIMITER CONFIG_NIMBLE_CPP_ADDR_FMT_EXCLUDE_DELIMITER
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# ifndef MYNEWT_VAL_NIMBLE_CPP_ADDR_FMT_UPPERCASE
|
||||
# ifndef CONFIG_NIMBLE_CPP_ADDR_FMT_UPPERCASE
|
||||
# define MYNEWT_VAL_NIMBLE_CPP_ADDR_FMT_UPPERCASE (1)
|
||||
# else
|
||||
# define MYNEWT_VAL_NIMBLE_CPP_ADDR_FMT_UPPERCASE CONFIG_NIMBLE_CPP_ADDR_FMT_UPPERCASE
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if MYNEWT_VAL(NIMBLE_CPP_ADDR_FMT_EXCLUDE_DELIMITER)
|
||||
# ifdef CONFIG_NIMBLE_CPP_ADDR_FMT_EXCLUDE_DELIMITER
|
||||
# define NIMBLE_CPP_ADDR_DELIMITER ""
|
||||
# else
|
||||
# define NIMBLE_CPP_ADDR_DELIMITER ":"
|
||||
# endif
|
||||
|
||||
# if MYNEWT_VAL(NIMBLE_CPP_ADDR_FMT_UPPERCASE)
|
||||
# ifdef CONFIG_NIMBLE_CPP_ADDR_FMT_UPPERCASE
|
||||
# define NIMBLE_CPP_ADDR_FMT "%02X%s%02X%s%02X%s%02X%s%02X%s%02X"
|
||||
# else
|
||||
# define NIMBLE_CPP_ADDR_FMT "%02x%s%02x%s%02x%s%02x%s%02x%s%02x"
|
||||
@@ -239,16 +224,11 @@ NimBLEAddress::operator std::string() const {
|
||||
snprintf(buffer,
|
||||
sizeof(buffer),
|
||||
NIMBLE_CPP_ADDR_FMT,
|
||||
this->val[5],
|
||||
NIMBLE_CPP_ADDR_DELIMITER,
|
||||
this->val[4],
|
||||
NIMBLE_CPP_ADDR_DELIMITER,
|
||||
this->val[3],
|
||||
NIMBLE_CPP_ADDR_DELIMITER,
|
||||
this->val[2],
|
||||
NIMBLE_CPP_ADDR_DELIMITER,
|
||||
this->val[1],
|
||||
NIMBLE_CPP_ADDR_DELIMITER,
|
||||
this->val[5], NIMBLE_CPP_ADDR_DELIMITER,
|
||||
this->val[4], NIMBLE_CPP_ADDR_DELIMITER,
|
||||
this->val[3], NIMBLE_CPP_ADDR_DELIMITER,
|
||||
this->val[2], NIMBLE_CPP_ADDR_DELIMITER,
|
||||
this->val[1], NIMBLE_CPP_ADDR_DELIMITER,
|
||||
this->val[0]);
|
||||
return std::string{buffer};
|
||||
} // operator std::string
|
||||
|
||||
@@ -17,9 +17,8 @@
|
||||
|
||||
#ifndef NIMBLE_CPP_ADDRESS_H_
|
||||
#define NIMBLE_CPP_ADDRESS_H_
|
||||
|
||||
#include "syscfg/syscfg.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
# if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
# include "nimble/ble.h"
|
||||
@@ -67,5 +66,5 @@ class NimBLEAddress : private ble_addr_t {
|
||||
operator uint64_t() const;
|
||||
};
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_ENABLED
|
||||
#endif // NIMBLE_CPP_ADDRESS_H_
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
#endif /* NIMBLE_CPP_ADDRESS_H_ */
|
||||
|
||||
@@ -15,10 +15,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "NimBLEAdvertisedDevice.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_OBSERVER)
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||
|
||||
# include "NimBLEDevice.h"
|
||||
# include "NimBLEAdvertisedDevice.h"
|
||||
# include "NimBLEUtils.h"
|
||||
# include "NimBLELog.h"
|
||||
|
||||
@@ -31,14 +32,13 @@ static const char* LOG_TAG = "NimBLEAdvertisedDevice";
|
||||
* @param [in] event The advertisement event data.
|
||||
*/
|
||||
NimBLEAdvertisedDevice::NimBLEAdvertisedDevice(const ble_gap_event* event, uint8_t eventType)
|
||||
# if MYNEWT_VAL(BLE_EXT_ADV)
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
: m_address{event->ext_disc.addr},
|
||||
m_advType{eventType},
|
||||
m_rssi{event->ext_disc.rssi},
|
||||
m_callbackSent{0},
|
||||
m_advLength{event->ext_disc.length_data},
|
||||
m_isLegacyAdv{!!(event->ext_disc.props & BLE_HCI_ADV_LEGACY_MASK)},
|
||||
m_dataStatus{event->ext_disc.data_status},
|
||||
m_sid{event->ext_disc.sid},
|
||||
m_primPhy{event->ext_disc.prim_phy},
|
||||
m_secPhy{event->ext_disc.sec_phy},
|
||||
@@ -59,18 +59,9 @@ NimBLEAdvertisedDevice::NimBLEAdvertisedDevice(const ble_gap_event* event, uint8
|
||||
* @param [in] event The advertisement event data.
|
||||
*/
|
||||
void NimBLEAdvertisedDevice::update(const ble_gap_event* event, uint8_t eventType) {
|
||||
# if MYNEWT_VAL(BLE_EXT_ADV)
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
const auto& disc = event->ext_disc;
|
||||
if (m_dataStatus == BLE_GAP_EXT_ADV_DATA_STATUS_INCOMPLETE) {
|
||||
m_payload.reserve(m_advLength + disc.length_data);
|
||||
m_payload.insert(m_payload.end(), disc.data, disc.data + disc.length_data);
|
||||
m_dataStatus = disc.data_status;
|
||||
m_advLength = m_payload.size();
|
||||
return;
|
||||
}
|
||||
|
||||
m_dataStatus = disc.data_status;
|
||||
m_isLegacyAdv = disc.props & BLE_HCI_ADV_LEGACY_MASK;
|
||||
m_isLegacyAdv = disc.props & BLE_HCI_ADV_LEGACY_MASK;
|
||||
# else
|
||||
const auto& disc = event->disc;
|
||||
# endif
|
||||
@@ -96,11 +87,11 @@ const NimBLEAddress& NimBLEAdvertisedDevice::getAddress() const {
|
||||
/**
|
||||
* @brief Get the advertisement type.
|
||||
* @return The advertising type the device is reporting:
|
||||
* * BLE_HCI_ADV_RPT_EVTYPE_ADV_IND (0) - indirect advertising - connectable and scannable
|
||||
* * BLE_HCI_ADV_RPT_EVTYPE_DIR_IND (1) - direct advertising - connectable
|
||||
* * BLE_HCI_ADV_RPT_EVTYPE_SCAN_IND (2) - indirect scan response - not connectable - scannable
|
||||
* * BLE_HCI_ADV_RPT_EVTYPE_NONCONN_IND (3) - beacon only - not connectable - not scannable
|
||||
* * BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP (4) - scan response
|
||||
* * BLE_HCI_ADV_TYPE_ADV_IND (0) - indirect advertising
|
||||
* * BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD (1) - direct advertising - high duty cycle
|
||||
* * BLE_HCI_ADV_TYPE_ADV_SCAN_IND (2) - indirect scan response
|
||||
* * BLE_HCI_ADV_TYPE_ADV_NONCONN_IND (3) - indirect advertising - not connectable
|
||||
* * BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_LD (4) - direct advertising - low duty cycle
|
||||
*/
|
||||
uint8_t NimBLEAdvertisedDevice::getAdvType() const {
|
||||
return m_advType;
|
||||
@@ -590,7 +581,7 @@ bool NimBLEAdvertisedDevice::haveTXPower() const {
|
||||
return findAdvField(BLE_HS_ADV_TYPE_TX_PWR_LVL) > 0;
|
||||
} // haveTXPower
|
||||
|
||||
# if MYNEWT_VAL(BLE_EXT_ADV)
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
/**
|
||||
* @brief Get the set ID of the extended advertisement.
|
||||
* @return The set ID.
|
||||
@@ -627,18 +618,6 @@ uint8_t NimBLEAdvertisedDevice::getSecondaryPhy() const {
|
||||
uint16_t NimBLEAdvertisedDevice::getPeriodicInterval() const {
|
||||
return m_periodicItvl;
|
||||
} // getPeriodicInterval
|
||||
|
||||
/**
|
||||
* @brief Get the advertisement data status.
|
||||
* @return The advertisement data status.
|
||||
* One of:
|
||||
* * BLE_GAP_EXT_ADV_DATA_STATUS_COMPLETE (0) - Complete extended advertising data
|
||||
* * BLE_GAP_EXT_ADV_DATA_STATUS_INCOMPLETE (1) - Incomplete extended advertising data, more to come
|
||||
* * BLE_GAP_EXT_ADV_DATA_STATUS_TRUNCATED (2) - Incomplete extended advertising data, no more to come
|
||||
*/
|
||||
uint8_t NimBLEAdvertisedDevice::getDataStatus() const {
|
||||
return m_dataStatus;
|
||||
} // getDataStatus
|
||||
# endif
|
||||
|
||||
uint8_t NimBLEAdvertisedDevice::findAdvField(uint8_t type, uint8_t index, size_t* data_loc) const {
|
||||
@@ -752,7 +731,7 @@ std::string NimBLEAdvertisedDevice::toString() const {
|
||||
* @brief Get the length of the advertisement data in the payload.
|
||||
* @return The number of bytes in the payload that is from the advertisement.
|
||||
*/
|
||||
uint16_t NimBLEAdvertisedDevice::getAdvLength() const {
|
||||
uint8_t NimBLEAdvertisedDevice::getAdvLength() const {
|
||||
return m_advLength;
|
||||
}
|
||||
|
||||
@@ -773,13 +752,12 @@ uint8_t NimBLEAdvertisedDevice::getAddressType() const {
|
||||
* @return True if the device is connectable.
|
||||
*/
|
||||
bool NimBLEAdvertisedDevice::isConnectable() const {
|
||||
# if MYNEWT_VAL(BLE_EXT_ADV)
|
||||
if (!m_isLegacyAdv) {
|
||||
return (m_advType & BLE_HCI_ADV_CONN_MASK) || (m_advType & BLE_HCI_ADV_DIRECT_MASK);
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
if (m_isLegacyAdv) {
|
||||
return m_advType == BLE_HCI_ADV_RPT_EVTYPE_ADV_IND || m_advType == BLE_HCI_ADV_RPT_EVTYPE_DIR_IND;
|
||||
}
|
||||
# endif
|
||||
|
||||
return m_advType == BLE_HCI_ADV_RPT_EVTYPE_ADV_IND || m_advType == BLE_HCI_ADV_RPT_EVTYPE_DIR_IND;
|
||||
return (m_advType & BLE_HCI_ADV_CONN_MASK) || (m_advType & BLE_HCI_ADV_DIRECT_MASK);
|
||||
} // isConnectable
|
||||
|
||||
/**
|
||||
@@ -795,7 +773,7 @@ bool NimBLEAdvertisedDevice::isScannable() const {
|
||||
* @return True if legacy (Bluetooth 4.x), false if extended (bluetooth 5.x).
|
||||
*/
|
||||
bool NimBLEAdvertisedDevice::isLegacyAdvertisement() const {
|
||||
# if MYNEWT_VAL(BLE_EXT_ADV)
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
return m_isLegacyAdv;
|
||||
# else
|
||||
return true;
|
||||
@@ -836,4 +814,4 @@ const std::vector<uint8_t>::const_iterator NimBLEAdvertisedDevice::end() const {
|
||||
return m_payload.cend();
|
||||
}
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_OBSERVER)
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
#ifndef NIMBLE_CPP_ADVERTISED_DEVICE_H_
|
||||
#define NIMBLE_CPP_ADVERTISED_DEVICE_H_
|
||||
|
||||
#include "syscfg/syscfg.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_OBSERVER)
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||
|
||||
# include "NimBLEAddress.h"
|
||||
# include "NimBLEScan.h"
|
||||
@@ -69,7 +69,7 @@ class NimBLEAdvertisedDevice {
|
||||
NimBLEAddress getTargetAddress(uint8_t index = 0) const;
|
||||
uint8_t getTargetAddressCount() const;
|
||||
int8_t getTXPower() const;
|
||||
uint16_t getAdvLength() const;
|
||||
uint8_t getAdvLength() const;
|
||||
uint8_t getAddressType() const;
|
||||
bool isAdvertisingService(const NimBLEUUID& uuid) const;
|
||||
bool haveAppearance() const;
|
||||
@@ -87,12 +87,11 @@ class NimBLEAdvertisedDevice {
|
||||
bool isConnectable() const;
|
||||
bool isScannable() const;
|
||||
bool isLegacyAdvertisement() const;
|
||||
# if MYNEWT_VAL(BLE_EXT_ADV)
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
uint8_t getSetId() const;
|
||||
uint8_t getPrimaryPhy() const;
|
||||
uint8_t getSecondaryPhy() const;
|
||||
uint16_t getPeriodicInterval() const;
|
||||
uint8_t getDataStatus() const;
|
||||
# endif
|
||||
operator NimBLEAddress() const;
|
||||
|
||||
@@ -162,11 +161,10 @@ class NimBLEAdvertisedDevice {
|
||||
uint8_t m_advType{};
|
||||
int8_t m_rssi{};
|
||||
uint8_t m_callbackSent{};
|
||||
uint16_t m_advLength{};
|
||||
uint8_t m_advLength{};
|
||||
|
||||
# if MYNEWT_VAL(BLE_EXT_ADV)
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
bool m_isLegacyAdv{};
|
||||
uint8_t m_dataStatus{};
|
||||
uint8_t m_sid{};
|
||||
uint8_t m_primPhy{};
|
||||
uint8_t m_secPhy{};
|
||||
@@ -176,5 +174,5 @@ class NimBLEAdvertisedDevice {
|
||||
std::vector<uint8_t> m_payload;
|
||||
};
|
||||
|
||||
#endif /* CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_OBSERVER) */
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_OBSERVER */
|
||||
#endif /* NIMBLE_CPP_ADVERTISED_DEVICE_H_ */
|
||||
|
||||
@@ -15,9 +15,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "NimBLEAdvertisementData.h"
|
||||
#if (CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_BROADCASTER) && !MYNEWT_VAL(BLE_EXT_ADV)) || defined(_DOXYGEN_)
|
||||
#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"
|
||||
@@ -583,4 +585,4 @@ std::string NimBLEAdvertisementData::toString() const {
|
||||
return str;
|
||||
} // toString
|
||||
|
||||
#endif // (CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_BROADCASTER) && !MYNEWT_VAL(BLE_EXT_ADV)) || defined(_DOXYGEN_)
|
||||
#endif // CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER && !CONFIG_BT_NIMBLE_EXT_ADV
|
||||
|
||||
@@ -18,8 +18,9 @@
|
||||
#ifndef NIMBLE_CPP_ADVERTISEMENT_DATA_H_
|
||||
#define NIMBLE_CPP_ADVERTISEMENT_DATA_H_
|
||||
|
||||
#include "syscfg/syscfg.h"
|
||||
#if (CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_BROADCASTER) && !MYNEWT_VAL(BLE_EXT_ADV)) || defined(_DOXYGEN_)
|
||||
#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>
|
||||
@@ -74,5 +75,5 @@ class NimBLEAdvertisementData {
|
||||
std::vector<uint8_t> m_payload{};
|
||||
}; // NimBLEAdvertisementData
|
||||
|
||||
#endif // (CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_BROADCASTER) && !MYNEWT_VAL(BLE_EXT_ADV)) || defined(_DOXYGEN_)
|
||||
#endif // CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER && !CONFIG_BT_NIMBLE_EXT_ADV
|
||||
#endif // NIMBLE_CPP_ADVERTISEMENT_DATA_H_
|
||||
|
||||
@@ -15,14 +15,16 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "NimBLEAdvertising.h"
|
||||
#if (CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_BROADCASTER) && !MYNEWT_VAL(BLE_EXT_ADV)) || defined(_DOXYGEN_)
|
||||
#include "nimconfig.h"
|
||||
#if (defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER) && !CONFIG_BT_NIMBLE_EXT_ADV) || \
|
||||
defined(_DOXYGEN_)
|
||||
|
||||
# if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
# include "services/gap/ble_svc_gap.h"
|
||||
# else
|
||||
# include "nimble/nimble/host/services/gap/include/services/gap/ble_svc_gap.h"
|
||||
# endif
|
||||
# include "NimBLEAdvertising.h"
|
||||
# include "NimBLEDevice.h"
|
||||
# include "NimBLEServer.h"
|
||||
# include "NimBLEUtils.h"
|
||||
@@ -42,7 +44,7 @@ NimBLEAdvertising::NimBLEAdvertising()
|
||||
m_duration{BLE_HS_FOREVER},
|
||||
m_scanResp{false},
|
||||
m_advDataSet{false} {
|
||||
# if !MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
# if !defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
m_advParams.conn_mode = BLE_GAP_CONN_MODE_NON;
|
||||
# else
|
||||
m_advParams.conn_mode = BLE_GAP_CONN_MODE_UND;
|
||||
@@ -195,11 +197,10 @@ bool NimBLEAdvertising::start(uint32_t duration, const NimBLEAddress* dirAddr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
NimBLEServer* pServer = NimBLEDevice::getServer();
|
||||
if (pServer != nullptr && !pServer->start()) { // make sure the GATT server is ready before advertising
|
||||
NIMBLE_LOGE(LOG_TAG, "Failed to start GATT server");
|
||||
return false;
|
||||
if (pServer != nullptr) {
|
||||
pServer->start(); // make sure the GATT server is ready before advertising
|
||||
}
|
||||
# endif
|
||||
|
||||
@@ -221,7 +222,7 @@ bool NimBLEAdvertising::start(uint32_t duration, const NimBLEAddress* dirAddr) {
|
||||
duration = BLE_HS_FOREVER;
|
||||
}
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
int rc = ble_gap_adv_start(NimBLEDevice::m_ownAddrType,
|
||||
(dirAddr != nullptr) ? dirAddr->getBase() : NULL,
|
||||
duration,
|
||||
@@ -621,4 +622,4 @@ bool NimBLEAdvertising::setServiceData(const NimBLEUUID& uuid, const std::string
|
||||
return setServiceData(uuid, reinterpret_cast<const uint8_t*>(data.data()), data.length());
|
||||
} // setServiceData
|
||||
|
||||
#endif // (CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_BROADCASTER) && !MYNEWT_VAL(BLE_EXT_ADV)) || defined(_DOXYGEN_)
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER && !CONFIG_BT_NIMBLE_EXT_ADV */
|
||||
|
||||
@@ -18,8 +18,9 @@
|
||||
#ifndef NIMBLE_CPP_ADVERTISING_H_
|
||||
#define NIMBLE_CPP_ADVERTISING_H_
|
||||
|
||||
#include "syscfg/syscfg.h"
|
||||
#if (CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_BROADCASTER) && !MYNEWT_VAL(BLE_EXT_ADV)) || defined(_DOXYGEN_)
|
||||
#include "nimconfig.h"
|
||||
#if (defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER) && !CONFIG_BT_NIMBLE_EXT_ADV) || \
|
||||
defined(_DOXYGEN_)
|
||||
|
||||
# if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
# include "host/ble_gap.h"
|
||||
@@ -105,5 +106,5 @@ class NimBLEAdvertising {
|
||||
bool m_advDataSet : 1;
|
||||
};
|
||||
|
||||
#endif // (CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_BROADCASTER) && !MYNEWT_VAL(BLE_EXT_ADV)) || defined(_DOXYGEN_)
|
||||
#endif // NIMBLE_CPP_ADVERTISING_H_
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER && !CONFIG_BT_NIMBLE_EXT_ADV */
|
||||
#endif /* NIMBLE_CPP_ADVERTISING_H_ */
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "NimBLEAttValue.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
# if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
# include "nimble/nimble_npl.h"
|
||||
@@ -24,7 +24,7 @@
|
||||
# include "nimble/nimble/include/nimble/nimble_npl.h"
|
||||
# endif
|
||||
|
||||
# include "NimBLEUtils.h"
|
||||
# include "NimBLEAttValue.h"
|
||||
# include "NimBLELog.h"
|
||||
|
||||
static const char* LOG_TAG = "NimBLEAttValue";
|
||||
@@ -35,7 +35,7 @@ NimBLEAttValue::NimBLEAttValue(uint16_t init_len, uint16_t max_len)
|
||||
m_attr_max_len{std::min<uint16_t>(BLE_ATT_ATTR_MAX_LEN, max_len)},
|
||||
m_attr_len{},
|
||||
m_capacity{init_len}
|
||||
# if MYNEWT_VAL(NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED)
|
||||
# if CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
|
||||
,
|
||||
m_timestamp{}
|
||||
# endif
|
||||
@@ -105,8 +105,7 @@ void NimBLEAttValue::deepCopy(const NimBLEAttValue& source) {
|
||||
|
||||
// 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.
|
||||
m_attr_value[0] = '\0'; // Set the first byte to 0 incase the len of the new value is 0.
|
||||
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;
|
||||
}
|
||||
@@ -134,7 +133,7 @@ NimBLEAttValue& NimBLEAttValue::append(const uint8_t* value, uint16_t len) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
# if MYNEWT_VAL(NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED)
|
||||
# if CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
|
||||
time_t t = time(nullptr);
|
||||
# else
|
||||
time_t t = 0;
|
||||
@@ -160,4 +159,4 @@ uint8_t NimBLEAttValue::operator[](int pos) const {
|
||||
return m_attr_value[pos];
|
||||
}
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_ENABLED
|
||||
#endif // CONFIG_BT_ENABLED
|
||||
|
||||
@@ -17,9 +17,8 @@
|
||||
|
||||
#ifndef NIMBLE_CPP_ATTVALUE_H
|
||||
#define NIMBLE_CPP_ATTVALUE_H
|
||||
|
||||
#include "syscfg/syscfg.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
# ifdef NIMBLE_CPP_ARDUINO_STRING_AVAILABLE
|
||||
# include <Arduino.h>
|
||||
@@ -31,30 +30,20 @@
|
||||
# include <cstring>
|
||||
# include <cstdint>
|
||||
|
||||
# ifndef MYNEWT_VAL_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
|
||||
# ifndef CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
|
||||
# define MYNEWT_VAL_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED 0
|
||||
# else
|
||||
# define MYNEWT_VAL_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
|
||||
# endif
|
||||
# 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
|
||||
|
||||
# ifndef MYNEWT_VAL_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH
|
||||
# ifndef CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH
|
||||
# define MYNEWT_VAL_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH 20
|
||||
# else
|
||||
# define MYNEWT_VAL_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if MYNEWT_VAL(NIMBLE_CPP_ATT_VALUE_INIT_LENGTH) > BLE_ATT_ATTR_MAX_LEN
|
||||
# error NIMBLE_CPP_ATT_VALUE_INIT_LENGTH cannot be larger than 512 (BLE_ATT_ATTR_MAX_LEN)
|
||||
# elif MYNEWT_VAL(NIMBLE_CPP_ATT_VALUE_INIT_LENGTH) < 1
|
||||
# error NIMBLE_CPP_ATT_VALUE_INIT_LENGTH cannot be less than 1; Range = 1 : 512
|
||||
# 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. */
|
||||
@@ -73,14 +62,6 @@ 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 {};
|
||||
|
||||
/* Used to determine if the type passed to a template has a value_type member (std::vector, std::array, std::string, etc.). */
|
||||
template <typename T, typename = void>
|
||||
struct Has_value_type : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct Has_value_type<T, decltype(void(sizeof(typename T::value_type)))>
|
||||
: 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
|
||||
@@ -92,7 +73,7 @@ class NimBLEAttValue {
|
||||
uint16_t m_attr_max_len{};
|
||||
uint16_t m_attr_len{};
|
||||
uint16_t m_capacity{};
|
||||
# if MYNEWT_VAL(NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED)
|
||||
# if CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
|
||||
time_t m_timestamp{};
|
||||
# endif
|
||||
void deepCopy(const NimBLEAttValue& source);
|
||||
@@ -103,7 +84,7 @@ class NimBLEAttValue {
|
||||
* @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 = MYNEWT_VAL(NIMBLE_CPP_ATT_VALUE_INIT_LENGTH), uint16_t max_len = BLE_ATT_ATTR_MAX_LEN);
|
||||
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.
|
||||
@@ -188,7 +169,7 @@ class NimBLEAttValue {
|
||||
/** @brief Iterator end */
|
||||
const uint8_t* end() const { return m_attr_value + m_attr_len; }
|
||||
|
||||
# if MYNEWT_VAL(NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED)
|
||||
# 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; }
|
||||
|
||||
@@ -228,7 +209,7 @@ class NimBLEAttValue {
|
||||
|
||||
const NimBLEAttValue& getValue(time_t* timestamp = nullptr) const {
|
||||
if (timestamp != nullptr) {
|
||||
# if MYNEWT_VAL(NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED)
|
||||
# if CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
|
||||
*timestamp = m_timestamp;
|
||||
# else
|
||||
*timestamp = 0;
|
||||
@@ -282,32 +263,13 @@ class NimBLEAttValue {
|
||||
/**
|
||||
* @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 with `value_type`.
|
||||
* Correctly calculates byte size for containers with multi-byte element types.
|
||||
* @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 && Has_value_type<T>::value, bool>::type
|
||||
# endif
|
||||
setValue(const T& v) {
|
||||
return setValue(
|
||||
reinterpret_cast<const uint8_t*>(v.data()),
|
||||
v.size() * sizeof(typename T::value_type)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 without `value_type`.
|
||||
*/
|
||||
template <typename T>
|
||||
# ifdef _DOXYGEN_
|
||||
bool
|
||||
# else
|
||||
typename std::enable_if<Has_data_size<T>::value && !Has_value_type<T>::value, bool>::type
|
||||
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());
|
||||
@@ -322,11 +284,7 @@ class NimBLEAttValue {
|
||||
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) {
|
||||
if constexpr (Has_value_type<T>::value) {
|
||||
return setValue(reinterpret_cast<const uint8_t*>(s.data()), s.size() * sizeof(typename T::value_type));
|
||||
} else {
|
||||
return setValue(reinterpret_cast<const uint8_t*>(s.data()), s.size());
|
||||
}
|
||||
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 {
|
||||
@@ -347,17 +305,17 @@ class NimBLEAttValue {
|
||||
*/
|
||||
template <typename T>
|
||||
T getValue(time_t* timestamp = nullptr, bool skipSizeCheck = false) const {
|
||||
if (!skipSizeCheck && size() < sizeof(T)) {
|
||||
return T();
|
||||
}
|
||||
if (timestamp != nullptr) {
|
||||
# if MYNEWT_VAL(NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED)
|
||||
# if CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
|
||||
*timestamp = m_timestamp;
|
||||
# else
|
||||
*timestamp = 0;
|
||||
# endif
|
||||
}
|
||||
|
||||
if (!skipSizeCheck && size() < sizeof(T)) {
|
||||
return T();
|
||||
}
|
||||
return *(reinterpret_cast<const T*>(m_attr_value));
|
||||
}
|
||||
|
||||
@@ -404,5 +362,5 @@ class NimBLEAttValue {
|
||||
# endif
|
||||
};
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_ENABLED
|
||||
#endif // NIMBLE_CPP_ATTVALUE_H_
|
||||
#endif /*(CONFIG_BT_ENABLED) */
|
||||
#endif /* NIMBLE_CPP_ATTVALUE_H_ */
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
#ifndef NIMBLE_CPP_ATTRIBUTE_H_
|
||||
#define NIMBLE_CPP_ATTRIBUTE_H_
|
||||
|
||||
#include "syscfg/syscfg.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED && (MYNEWT_VAL(BLE_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_ROLE_CENTRAL))
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && (defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) || defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL))
|
||||
|
||||
# include "NimBLEUUID.h"
|
||||
|
||||
@@ -56,5 +56,5 @@ class NimBLEAttribute {
|
||||
uint16_t m_handle{0};
|
||||
};
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_ENABLED && (MYNEWT_VAL(BLE_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_ROLE_CENTRAL))
|
||||
#endif // CONFIG_BT_ENABLED && (CONFIG_BT_NIMBLE_ROLE_PERIPHERAL || CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
#endif // NIMBLE_CPP_ATTRIBUTE_H_
|
||||
|
||||
@@ -15,9 +15,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "NimBLEBeacon.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_BROADCASTER)
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||
|
||||
# include "NimBLEBeacon.h"
|
||||
# include "NimBLEUUID.h"
|
||||
# include "NimBLELog.h"
|
||||
|
||||
@@ -137,4 +138,4 @@ void NimBLEBeacon::setSignalPower(int8_t signalPower) {
|
||||
m_beaconData.signalPower = signalPower;
|
||||
} // setSignalPower
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_BROADCASTER)
|
||||
#endif // CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER
|
||||
|
||||
@@ -18,13 +18,12 @@
|
||||
#ifndef NIMBLE_CPP_BEACON_H_
|
||||
#define NIMBLE_CPP_BEACON_H_
|
||||
|
||||
#include "syscfg/syscfg.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_BROADCASTER)
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||
|
||||
class NimBLEUUID;
|
||||
|
||||
# include <cstdint>
|
||||
# include <vector>
|
||||
|
||||
/**
|
||||
* @brief Representation of a beacon.
|
||||
@@ -41,10 +40,6 @@ class NimBLEBeacon {
|
||||
uint16_t major{};
|
||||
uint16_t minor{};
|
||||
int8_t signalPower{};
|
||||
operator std::vector<uint8_t> () const {
|
||||
return std::vector<uint8_t>(reinterpret_cast<const uint8_t*>(this),
|
||||
reinterpret_cast<const uint8_t*>(this) + sizeof(BeaconData));
|
||||
}
|
||||
} __attribute__((packed));
|
||||
|
||||
const BeaconData& getData();
|
||||
@@ -65,5 +60,5 @@ class NimBLEBeacon {
|
||||
BeaconData m_beaconData;
|
||||
}; // NimBLEBeacon
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
#endif // NIMBLE_CPP_BEACON_H_
|
||||
#endif // CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL
|
||||
|
||||
@@ -15,16 +15,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "NimBLECharacteristic.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
|
||||
# if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
# if !defined(ESP_IDF_VERSION_MAJOR) || ESP_IDF_VERSION_MAJOR < 5
|
||||
# define ble_gatts_notify_custom ble_gattc_notify_custom
|
||||
# define ble_gatts_indicate_custom ble_gattc_indicate_custom
|
||||
# endif
|
||||
# endif
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
|
||||
# include "NimBLECharacteristic.h"
|
||||
# include "NimBLE2904.h"
|
||||
# include "NimBLEDevice.h"
|
||||
# include "NimBLELog.h"
|
||||
@@ -165,27 +159,21 @@ void NimBLECharacteristic::removeDescriptor(NimBLEDescriptor* pDescriptor, bool
|
||||
/**
|
||||
* @brief Return the BLE Descriptor for the given UUID.
|
||||
* @param [in] uuid The UUID of the descriptor.
|
||||
* @param [in] index The index of the descriptor to return (used when multiple descriptors have the same UUID).
|
||||
* @return A pointer to the descriptor object or nullptr if not found.
|
||||
*/
|
||||
NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const char* uuid, uint16_t index) const {
|
||||
return getDescriptorByUUID(NimBLEUUID(uuid), index);
|
||||
NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const char* uuid) const {
|
||||
return getDescriptorByUUID(NimBLEUUID(uuid));
|
||||
} // getDescriptorByUUID
|
||||
|
||||
/**
|
||||
* @brief Return the BLE Descriptor for the given UUID.
|
||||
* @param [in] uuid The UUID of the descriptor.
|
||||
* @param [in] index The index of the descriptor to return (used when multiple descriptors have the same UUID).
|
||||
* @return A pointer to the descriptor object or nullptr if not found.
|
||||
*/
|
||||
NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const NimBLEUUID& uuid, uint16_t index) const {
|
||||
uint16_t position = 0;
|
||||
NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const NimBLEUUID& uuid) const {
|
||||
for (const auto& dsc : m_vDescriptors) {
|
||||
if (dsc->getUUID() == uuid) {
|
||||
if (position == index) {
|
||||
return dsc;
|
||||
}
|
||||
position++;
|
||||
return dsc;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
@@ -231,8 +219,7 @@ void NimBLECharacteristic::setService(NimBLEService* pService) {
|
||||
* @return True if the indication was sent successfully, false otherwise.
|
||||
*/
|
||||
bool NimBLECharacteristic::indicate(uint16_t connHandle) const {
|
||||
auto value{m_value}; // make a copy to avoid issues if the value is changed while indicating
|
||||
return sendValue(value.data(), value.size(), false, connHandle);
|
||||
return sendValue(nullptr, 0, false, connHandle);
|
||||
} // indicate
|
||||
|
||||
/**
|
||||
@@ -254,8 +241,7 @@ bool NimBLECharacteristic::indicate(const uint8_t* value, size_t length, uint16_
|
||||
* @return True if the notification was sent successfully, false otherwise.
|
||||
*/
|
||||
bool NimBLECharacteristic::notify(uint16_t connHandle) const {
|
||||
auto value{m_value}; // make a copy to avoid issues if the value is changed while notifying
|
||||
return sendValue(value.data(), value.size(), true, connHandle);
|
||||
return sendValue(nullptr, 0, true, connHandle);
|
||||
} // notify
|
||||
|
||||
/**
|
||||
@@ -279,159 +265,51 @@ bool NimBLECharacteristic::notify(const uint8_t* value, size_t length, uint16_t
|
||||
* @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 {
|
||||
ble_npl_hw_enter_critical();
|
||||
const auto subs = getSubscribers(); // make a copy to avoid issues if subscribers change while sending
|
||||
ble_npl_hw_exit_critical(0);
|
||||
int rc = 0;
|
||||
|
||||
bool chSpecified = connHandle != BLE_HS_CONN_HANDLE_NONE;
|
||||
bool requireSecure = m_properties & (BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_READ_AUTHEN | BLE_GATT_CHR_F_READ_AUTHOR);
|
||||
int rc = chSpecified ? BLE_HS_ENOENT : 0; // if handle specified, assume not found until sent
|
||||
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.
|
||||
}
|
||||
|
||||
// Notify all connected peers unless a specific handle is provided
|
||||
for (const auto& entry : subs) {
|
||||
uint16_t ch = entry.getConnHandle();
|
||||
if (ch == BLE_HS_CONN_HANDLE_NONE || (chSpecified && ch != connHandle)) {
|
||||
continue;
|
||||
// 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;
|
||||
}
|
||||
|
||||
if (isNotification) {
|
||||
rc = ble_gattc_notify_custom(ch, m_handle, om);
|
||||
} else {
|
||||
rc = ble_gattc_indicate_custom(ch, m_handle, om);
|
||||
}
|
||||
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "<< sendValue: failed to send value, rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (requireSecure && !entry.isSecured()) {
|
||||
NIMBLE_LOGW(LOG_TAG, "skipping notify/indicate to connHandle=%d, link not secured", entry.getConnHandle());
|
||||
continue;
|
||||
}
|
||||
|
||||
// Must re-create the data buffer on each iteration because it is freed by the calls below.
|
||||
uint8_t retries = 10; // wait up to 10ms for a free buffer
|
||||
os_mbuf* om = ble_hs_mbuf_from_flat(value, length);
|
||||
while (!om && --retries) {
|
||||
ble_npl_time_delay(ble_npl_time_ms_to_ticks32(1));
|
||||
om = ble_hs_mbuf_from_flat(value, length);
|
||||
}
|
||||
|
||||
if (!om) {
|
||||
rc = BLE_HS_ENOMEM;
|
||||
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_gatts_notify_custom(ch, m_handle, om);
|
||||
rc = ble_gattc_notify_custom(connHandle, m_handle, NULL);
|
||||
} else {
|
||||
rc = ble_gatts_indicate_custom(ch, m_handle, om);
|
||||
}
|
||||
|
||||
if (rc != 0 || chSpecified) {
|
||||
break;
|
||||
rc = ble_gattc_indicate_custom(connHandle, m_handle, NULL);
|
||||
}
|
||||
} else { // Notify or indicate to all connected peers the characteristic value
|
||||
ble_gatts_chr_updated(m_handle);
|
||||
}
|
||||
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "failed to send value, rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return rc == 0;
|
||||
} // sendValue
|
||||
|
||||
/**
|
||||
* @brief Process a subscription or unsubscription request from a peer.
|
||||
* @param[in] connInfo A reference to the connection info of the peer.
|
||||
* @param[in] subVal The subscription value (bitmask).
|
||||
*/
|
||||
void NimBLECharacteristic::processSubRequest(NimBLEConnInfo& connInfo, uint8_t subVal) const {
|
||||
// Only allocate subscribers for characteristics that support notify or indicate.
|
||||
const uint16_t props = getProperties();
|
||||
if (!(props & (BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_INDICATE))) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto found = false;
|
||||
auto firstFree = -1;
|
||||
for (auto& entry : m_subPeers) {
|
||||
if (entry.getConnHandle() == connInfo.getConnHandle()) {
|
||||
found = true;
|
||||
if (!subVal) {
|
||||
ble_npl_hw_enter_critical();
|
||||
entry = SubPeerEntry{}; // unsubscribed, reset entry
|
||||
ble_npl_hw_exit_critical(0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (firstFree == -1 && entry.getConnHandle() == BLE_HS_CONN_HANDLE_NONE) {
|
||||
firstFree = &entry - &m_subPeers[0];
|
||||
}
|
||||
}
|
||||
|
||||
if (!found && subVal) {
|
||||
if (firstFree >= 0) {
|
||||
ble_npl_hw_enter_critical();
|
||||
m_subPeers[firstFree].setConnHandle(connInfo.getConnHandle());
|
||||
m_subPeers[firstFree].setSubNotify(subVal & 0x1);
|
||||
m_subPeers[firstFree].setSubIndicate(subVal & 0x2);
|
||||
m_subPeers[firstFree].setSecured(connInfo.isEncrypted() || connInfo.isAuthenticated() || connInfo.isBonded());
|
||||
if (m_properties & (BLE_GATT_CHR_F_READ_AUTHEN | BLE_GATT_CHR_F_READ_AUTHOR | BLE_GATT_CHR_F_READ_ENC)) {
|
||||
// characteristic requires security/authorization
|
||||
if (!m_subPeers[firstFree].isSecured()) {
|
||||
m_subPeers[firstFree].setAwaitingSecure(true);
|
||||
ble_npl_hw_exit_critical(0);
|
||||
NimBLEDevice::startSecurity(connInfo.getConnHandle());
|
||||
NIMBLE_LOGD(LOG_TAG,
|
||||
"Subscription deferred until link is secured for connHandle=%d",
|
||||
connInfo.getConnHandle());
|
||||
return;
|
||||
}
|
||||
}
|
||||
ble_npl_hw_exit_critical(0);
|
||||
} else {
|
||||
// should never happen, but log just in case
|
||||
NIMBLE_LOGE(LOG_TAG, "No free subscription slots");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_pCallbacks->onSubscribe(const_cast<NimBLECharacteristic*>(this), const_cast<NimBLEConnInfo&>(connInfo), subVal);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Update the security status of a subscribed peer.
|
||||
* @param[in] peerInfo A reference to the connection info of the peer.
|
||||
*/
|
||||
void NimBLECharacteristic::updatePeerStatus(const NimBLEConnInfo& peerInfo) const {
|
||||
if (!(getProperties() & (NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::INDICATE))) {
|
||||
return;
|
||||
}
|
||||
|
||||
ble_npl_hw_enter_critical();
|
||||
for (auto& entry : m_subPeers) {
|
||||
if (entry.getConnHandle() == peerInfo.getConnHandle()) {
|
||||
entry.setSecured(peerInfo.isEncrypted() || peerInfo.isAuthenticated() || peerInfo.isBonded());
|
||||
if (entry.isAwaitingSecure()) {
|
||||
entry.setAwaitingSecure(false);
|
||||
ble_npl_hw_exit_critical(0);
|
||||
m_pCallbacks->onSubscribe(const_cast<NimBLECharacteristic*>(this),
|
||||
const_cast<NimBLEConnInfo&>(peerInfo),
|
||||
entry.isSubNotify() | (entry.isSubIndicate() << 1));
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
ble_npl_hw_exit_critical(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handle a read event from a client.
|
||||
* @param [in] connInfo A reference to a NimBLEConnInfo instance containing the peer info.
|
||||
*/
|
||||
void NimBLECharacteristic::readEvent(NimBLEConnInfo& connInfo) {
|
||||
m_pCallbacks->onRead(this, connInfo);
|
||||
} // readEvent
|
||||
|
||||
/**
|
||||
* @brief Handle a write event from a client.
|
||||
* @param [in] val A pointer to the data written by the client.
|
||||
* @param [in] len The length of the data written by the client.
|
||||
* @param [in] connInfo A reference to a NimBLEConnInfo instance containing the peer info.
|
||||
*/
|
||||
void NimBLECharacteristic::writeEvent(const uint8_t* val, uint16_t len, NimBLEConnInfo& connInfo) {
|
||||
setValue(val, len);
|
||||
m_pCallbacks->onWrite(this, connInfo);
|
||||
@@ -505,18 +383,6 @@ void NimBLECharacteristicCallbacks::onStatus(NimBLECharacteristic* pCharacterist
|
||||
NIMBLE_LOGD("NimBLECharacteristicCallbacks", "onStatus: default");
|
||||
} // onStatus
|
||||
|
||||
/**
|
||||
* @brief Callback function to support a Notify/Indicate Status report.
|
||||
* @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] 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.
|
||||
*/
|
||||
void NimBLECharacteristicCallbacks::onStatus(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo, 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.
|
||||
@@ -533,4 +399,4 @@ void NimBLECharacteristicCallbacks::onSubscribe(NimBLECharacteristic* pCharacter
|
||||
NIMBLE_LOGD("NimBLECharacteristicCallbacks", "onSubscribe: default");
|
||||
}
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||
|
||||
@@ -17,9 +17,8 @@
|
||||
|
||||
#ifndef NIMBLE_CPP_CHARACTERISTIC_H_
|
||||
#define NIMBLE_CPP_CHARACTERISTIC_H_
|
||||
|
||||
#include "syscfg/syscfg.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
|
||||
class NimBLECharacteristicCallbacks;
|
||||
class NimBLEService;
|
||||
@@ -31,7 +30,6 @@ class NimBLE2904;
|
||||
|
||||
# include <string>
|
||||
# include <vector>
|
||||
# include <array>
|
||||
|
||||
/**
|
||||
* @brief The model of a BLE Characteristic.
|
||||
@@ -69,8 +67,8 @@ class NimBLECharacteristic : public NimBLELocalValueAttribute {
|
||||
uint32_t properties = NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE,
|
||||
uint16_t maxLen = BLE_ATT_ATTR_MAX_LEN);
|
||||
NimBLE2904* create2904();
|
||||
NimBLEDescriptor* getDescriptorByUUID(const char* uuid, uint16_t index = 0) const;
|
||||
NimBLEDescriptor* getDescriptorByUUID(const NimBLEUUID& uuid, uint16_t index = 0) const;
|
||||
NimBLEDescriptor* getDescriptorByUUID(const char* uuid) const;
|
||||
NimBLEDescriptor* getDescriptorByUUID(const NimBLEUUID& uuid) const;
|
||||
NimBLEDescriptor* getDescriptorByHandle(uint16_t handle) const;
|
||||
NimBLEService* getService() const;
|
||||
|
||||
@@ -89,9 +87,7 @@ class NimBLECharacteristic : public NimBLELocalValueAttribute {
|
||||
# ifdef _DOXYGEN_
|
||||
bool
|
||||
# else
|
||||
typename std::enable_if<!std::is_pointer<T>::value && !std::is_array<T>::value && !Has_c_str_length<T>::value &&
|
||||
!Has_data_size<T>::value,
|
||||
bool>::type
|
||||
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);
|
||||
@@ -113,23 +109,7 @@ class NimBLECharacteristic : public NimBLELocalValueAttribute {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Template to send a notification with a value from a class that has a data() and size() method with value_type.
|
||||
* @param [in] v The value to send.
|
||||
* @param [in] connHandle Optional, a connection handle to send the notification to.
|
||||
* @details Correctly calculates byte size for containers with multi-byte element types.
|
||||
*/
|
||||
template <typename T>
|
||||
# ifdef _DOXYGEN_
|
||||
bool
|
||||
# else
|
||||
typename std::enable_if<Has_data_size<T>::value && Has_value_type<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() * sizeof(typename T::value_type), connHandle);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Template to send a notification with a value from a class that has a data() and size() method without value_type.
|
||||
* @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.
|
||||
*/
|
||||
@@ -137,7 +117,7 @@ class NimBLECharacteristic : public NimBLELocalValueAttribute {
|
||||
# ifdef _DOXYGEN_
|
||||
bool
|
||||
# else
|
||||
typename std::enable_if<Has_data_size<T>::value && !Has_value_type<T>::value, bool>::type
|
||||
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);
|
||||
@@ -153,9 +133,7 @@ class NimBLECharacteristic : public NimBLELocalValueAttribute {
|
||||
# ifdef _DOXYGEN_
|
||||
bool
|
||||
# else
|
||||
typename std::enable_if<!std::is_pointer<T>::value && !std::is_array<T>::value && !Has_c_str_length<T>::value &&
|
||||
!Has_data_size<T>::value,
|
||||
bool>::type
|
||||
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);
|
||||
@@ -177,23 +155,7 @@ class NimBLECharacteristic : public NimBLELocalValueAttribute {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Template to send a indication with a value from a class that has a data() and size() method with value_type.
|
||||
* @param [in] v The value to send.
|
||||
* @param [in] connHandle Optional, a connection handle to send the notification to.
|
||||
* @details Correctly calculates byte size for containers with multi-byte element types.
|
||||
*/
|
||||
template <typename T>
|
||||
# ifdef _DOXYGEN_
|
||||
bool
|
||||
# else
|
||||
typename std::enable_if<Has_data_size<T>::value && Has_value_type<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() * sizeof(typename T::value_type), connHandle);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Template to send a indication with a value from a class that has a data() and size() method without value_type.
|
||||
* @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.
|
||||
*/
|
||||
@@ -201,7 +163,7 @@ class NimBLECharacteristic : public NimBLELocalValueAttribute {
|
||||
# ifdef _DOXYGEN_
|
||||
bool
|
||||
# else
|
||||
typename std::enable_if<Has_data_size<T>::value && !Has_value_type<T>::value, bool>::type
|
||||
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);
|
||||
@@ -220,16 +182,10 @@ class NimBLECharacteristic : public NimBLELocalValueAttribute {
|
||||
* @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 && !std::is_array<T>::value, bool>::type notify(
|
||||
const T& value, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const {
|
||||
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) {
|
||||
if constexpr (Has_value_type<T>::value) {
|
||||
return notify(reinterpret_cast<const uint8_t*>(value.data()),
|
||||
value.size() * sizeof(typename T::value_type),
|
||||
connHandle);
|
||||
} else {
|
||||
return notify(reinterpret_cast<const uint8_t*>(value.data()), value.size(), connHandle);
|
||||
}
|
||||
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 {
|
||||
@@ -248,16 +204,10 @@ class NimBLECharacteristic : public NimBLELocalValueAttribute {
|
||||
* @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 && !std::is_array<T>::value, bool>::type indicate(
|
||||
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) {
|
||||
if constexpr (Has_value_type<T>::value) {
|
||||
return indicate(reinterpret_cast<const uint8_t*>(value.data()),
|
||||
value.size() * sizeof(typename T::value_type),
|
||||
connHandle);
|
||||
} else {
|
||||
return indicate(reinterpret_cast<const uint8_t*>(value.data()), value.size(), connHandle);
|
||||
}
|
||||
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 {
|
||||
@@ -278,33 +228,9 @@ class NimBLECharacteristic : public NimBLELocalValueAttribute {
|
||||
bool is_notification = true,
|
||||
uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const;
|
||||
|
||||
struct SubPeerEntry {
|
||||
enum : uint8_t { AWAITING_SECURE = 1 << 0, SECURE = 1 << 1, SUB_NOTIFY = 1 << 2, SUB_INDICATE = 1 << 3 };
|
||||
void setConnHandle(uint16_t connHandle) { m_connHandle = connHandle; }
|
||||
uint16_t getConnHandle() const { return m_connHandle; }
|
||||
void setAwaitingSecure(bool awaiting) { awaiting ? m_flags |= AWAITING_SECURE : m_flags &= ~AWAITING_SECURE; }
|
||||
void setSecured(bool secure) { secure ? m_flags |= SECURE : m_flags &= ~SECURE; }
|
||||
void setSubNotify(bool notify) { notify ? m_flags |= SUB_NOTIFY : m_flags &= ~SUB_NOTIFY; }
|
||||
void setSubIndicate(bool indicate) { indicate ? m_flags |= SUB_INDICATE : m_flags &= ~SUB_INDICATE; }
|
||||
bool isSubNotify() const { return m_flags & SUB_NOTIFY; }
|
||||
bool isSubIndicate() const { return m_flags & SUB_INDICATE; }
|
||||
bool isSecured() const { return m_flags & SECURE; }
|
||||
bool isAwaitingSecure() const { return m_flags & AWAITING_SECURE; }
|
||||
|
||||
private:
|
||||
uint16_t m_connHandle{BLE_HS_CONN_HANDLE_NONE};
|
||||
uint8_t m_flags{0};
|
||||
} __attribute__((packed));
|
||||
|
||||
using SubPeerArray = std::array<SubPeerEntry, MYNEWT_VAL(BLE_MAX_CONNECTIONS)>;
|
||||
SubPeerArray getSubscribers() const { return m_subPeers; }
|
||||
void processSubRequest(NimBLEConnInfo& connInfo, uint8_t subVal) const;
|
||||
void updatePeerStatus(const NimBLEConnInfo& peerInfo) const;
|
||||
|
||||
NimBLECharacteristicCallbacks* m_pCallbacks{nullptr};
|
||||
NimBLEService* m_pService{nullptr};
|
||||
std::vector<NimBLEDescriptor*> m_vDescriptors{};
|
||||
mutable SubPeerArray m_subPeers{};
|
||||
}; // NimBLECharacteristic
|
||||
|
||||
/**
|
||||
@@ -319,10 +245,9 @@ class NimBLECharacteristicCallbacks {
|
||||
virtual ~NimBLECharacteristicCallbacks() {}
|
||||
virtual void onRead(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo);
|
||||
virtual void onWrite(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo);
|
||||
virtual void onStatus(NimBLECharacteristic* pCharacteristic, int code); // deprecated
|
||||
virtual void onStatus(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo, int code);
|
||||
virtual void onStatus(NimBLECharacteristic* pCharacteristic, int code);
|
||||
virtual void onSubscribe(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo, uint16_t subValue);
|
||||
};
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
#endif // NIMBLE_CPP_CHARACTERISTIC_H_
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||
#endif /*NIMBLE_CPP_CHARACTERISTIC_H_*/
|
||||
|
||||
@@ -15,9 +15,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "NimBLEClient.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_CENTRAL)
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
|
||||
# include "NimBLEClient.h"
|
||||
# include "NimBLERemoteService.h"
|
||||
# include "NimBLERemoteCharacteristic.h"
|
||||
# include "NimBLEDevice.h"
|
||||
@@ -68,7 +69,7 @@ NimBLEClient::NimBLEClient(const NimBLEAddress& peerAddress)
|
||||
m_terminateFailCount{0},
|
||||
m_asyncSecureAttempt{0},
|
||||
m_config{},
|
||||
# if MYNEWT_VAL(BLE_EXT_ADV)
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
m_phyMask{BLE_GAP_LE_PHY_1M_MASK | BLE_GAP_LE_PHY_2M_MASK | BLE_GAP_LE_PHY_CODED_MASK},
|
||||
# endif
|
||||
m_connParams{16,
|
||||
@@ -125,7 +126,6 @@ size_t NimBLEClient::deleteService(const NimBLEUUID& uuid) {
|
||||
return m_svcVec.size();
|
||||
} // deleteService
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_OBSERVER)
|
||||
/**
|
||||
* @brief Connect to an advertising device.
|
||||
* @param [in] pDevice A pointer to the advertised device instance to connect to.
|
||||
@@ -141,7 +141,6 @@ bool NimBLEClient::connect(const NimBLEAdvertisedDevice* pDevice, bool deleteAtt
|
||||
NimBLEAddress address(pDevice->getAddress());
|
||||
return connect(address, deleteAttributes, asyncConnect, exchangeMTU);
|
||||
} // connect
|
||||
# endif
|
||||
|
||||
/**
|
||||
* @brief Connect to the BLE Server using the address of the last connected device, or the address\n
|
||||
@@ -204,7 +203,7 @@ bool NimBLEClient::connect(const NimBLEAddress& address, bool deleteAttributes,
|
||||
m_config.exchangeMTU = exchangeMTU;
|
||||
|
||||
do {
|
||||
# if MYNEWT_VAL(BLE_EXT_ADV)
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
rc = ble_gap_ext_connect(NimBLEDevice::m_ownAddrType,
|
||||
peerAddr,
|
||||
m_connectTimeout,
|
||||
@@ -228,15 +227,10 @@ bool NimBLEClient::connect(const NimBLEAddress& address, bool deleteAttributes,
|
||||
break;
|
||||
|
||||
case BLE_HS_EBUSY:
|
||||
# if MYNEWT_VAL(BLE_ROLE_OBSERVER)
|
||||
|
||||
// Scan was active, stop it through the NimBLEScan API to release any tasks and call the callback.
|
||||
if (!NimBLEDevice::getScan()->stop()) {
|
||||
rc = BLE_HS_EUNKNOWN;
|
||||
}
|
||||
# else
|
||||
rc = BLE_HS_EUNKNOWN;
|
||||
# endif
|
||||
break;
|
||||
|
||||
case BLE_HS_EDONE:
|
||||
@@ -402,7 +396,7 @@ void NimBLEClient::setConfig(NimBLEClient::Config config) {
|
||||
m_config = config;
|
||||
} // setConfig
|
||||
|
||||
# if MYNEWT_VAL(BLE_EXT_ADV)
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
/**
|
||||
* @brief Set the PHY types to use when connecting to a server.
|
||||
* @param [in] mask A bitmask indicating what PHYS to connect with.\n
|
||||
@@ -414,7 +408,6 @@ void NimBLEClient::setConfig(NimBLEClient::Config config) {
|
||||
void NimBLEClient::setConnectPhy(uint8_t mask) {
|
||||
m_phyMask = mask;
|
||||
} // setConnectPhy
|
||||
# endif
|
||||
|
||||
/**
|
||||
* @brief Request a change to the PHY used for this peer connection.
|
||||
@@ -457,6 +450,7 @@ bool NimBLEClient::getPhy(uint8_t* txPhy, uint8_t* rxPhy) {
|
||||
|
||||
return rc == 0;
|
||||
} // getPhy
|
||||
# endif
|
||||
|
||||
/**
|
||||
* @brief Set the connection parameters to use when connecting to a server.
|
||||
@@ -934,18 +928,8 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
|
||||
switch (event->type) {
|
||||
case BLE_GAP_EVENT_DISCONNECT: {
|
||||
// workaround for bug in NimBLE stack where disconnect event argument is not passed correctly
|
||||
pClient = NimBLEDevice::getClientByPeerAddress(event->disconnect.conn.peer_ota_addr);
|
||||
pClient = NimBLEDevice::getClientByHandle(event->disconnect.conn.conn_handle);
|
||||
if (pClient == nullptr) {
|
||||
pClient = NimBLEDevice::getClientByPeerAddress(event->disconnect.conn.peer_id_addr);
|
||||
}
|
||||
|
||||
// try by connection handle
|
||||
if (pClient == nullptr) {
|
||||
pClient = NimBLEDevice::getClientByHandle(event->disconnect.conn.conn_handle);
|
||||
}
|
||||
|
||||
if (pClient == nullptr) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Disconnected client not found, conn_handle=%d", event->disconnect.conn.conn_handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -970,9 +954,7 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
|
||||
pClient->m_asyncSecureAttempt = 0;
|
||||
|
||||
// Don't call the disconnect callback if we are waiting for a connection to complete and it fails
|
||||
if (rc == (BLE_HS_ERR_HCI_BASE + BLE_ERR_CONN_ESTABLISHMENT) && pClient->m_config.asyncConnect) {
|
||||
pClient->m_pClientCallbacks->onConnectFail(pClient, rc);
|
||||
} else {
|
||||
if (rc != (BLE_HS_ERR_HCI_BASE + BLE_ERR_CONN_ESTABLISHMENT) || pClient->m_config.asyncConnect) {
|
||||
pClient->m_pClientCallbacks->onDisconnect(pClient, rc);
|
||||
}
|
||||
|
||||
@@ -1000,10 +982,6 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
|
||||
}
|
||||
|
||||
rc = event->connect.status;
|
||||
if (rc == BLE_ERR_UNSUPP_REM_FEATURE) {
|
||||
rc = 0; // Workaround: Ignore unsupported remote feature error as it is not a real error.
|
||||
}
|
||||
|
||||
if (rc == 0) {
|
||||
pClient->m_connHandle = event->connect.conn_handle;
|
||||
|
||||
@@ -1048,46 +1026,33 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
|
||||
} // BLE_GAP_EVENT_TERM_FAILURE
|
||||
|
||||
case BLE_GAP_EVENT_NOTIFY_RX: {
|
||||
if (pClient->m_connHandle != event->notify_rx.conn_handle) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pClient->m_connHandle != event->notify_rx.conn_handle) return 0;
|
||||
NIMBLE_LOGD(LOG_TAG, "Notify Received for handle: %d", event->notify_rx.attr_handle);
|
||||
|
||||
NimBLERemoteCharacteristic* pChr = pClient->getCharacteristic(event->notify_rx.attr_handle);
|
||||
if (pChr == nullptr) {
|
||||
NIMBLE_LOGW(LOG_TAG, "unknown handle: %d", event->notify_rx.attr_handle);
|
||||
return BLE_ATT_ERR_INVALID_HANDLE;
|
||||
}
|
||||
for (const auto& svc : pClient->m_svcVec) {
|
||||
// Dont waste cycles searching services without this handle in its range
|
||||
if (svc->getEndHandle() < event->notify_rx.attr_handle) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto len = event->notify_rx.om->om_len;
|
||||
if (pChr->m_value.setValue(event->notify_rx.om->om_data, len)) {
|
||||
os_mbuf* next;
|
||||
next = SLIST_NEXT(event->notify_rx.om, om_next);
|
||||
while (next != NULL) {
|
||||
pChr->m_value.append(next->om_data, next->om_len);
|
||||
if (pChr->m_value.length() != len + next->om_len) {
|
||||
rc = BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||
NIMBLE_LOGD(LOG_TAG,
|
||||
"checking service %s for handle: %d",
|
||||
svc->getUUID().toString().c_str(),
|
||||
event->notify_rx.attr_handle);
|
||||
|
||||
for (const auto& chr : svc->m_vChars) {
|
||||
if (chr->getHandle() == event->notify_rx.attr_handle) {
|
||||
NIMBLE_LOGD(LOG_TAG, "Got Notification for characteristic %s", chr->toString().c_str());
|
||||
|
||||
uint32_t data_len = OS_MBUF_PKTLEN(event->notify_rx.om);
|
||||
chr->m_value.setValue(event->notify_rx.om->om_data, data_len);
|
||||
|
||||
if (chr->m_notifyCallback != nullptr) {
|
||||
chr->m_notifyCallback(chr, event->notify_rx.om->om_data, data_len, !event->notify_rx.indication);
|
||||
}
|
||||
break;
|
||||
}
|
||||
len += next->om_len;
|
||||
next = SLIST_NEXT(next, om_next);
|
||||
}
|
||||
} else {
|
||||
rc = BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||
}
|
||||
|
||||
if (rc != 0) { // This should never happen
|
||||
NIMBLE_LOGE(LOG_TAG, "notification value error; exceeds limit");
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (pChr->m_notifyCallback != nullptr) {
|
||||
// TODO: change this callback to use the NimBLEAttValue class instead of raw data and length
|
||||
pChr->m_notifyCallback(pChr,
|
||||
const_cast<uint8_t*>(pChr->m_value.getValue().data()),
|
||||
pChr->m_value.length(),
|
||||
!event->notify_rx.indication);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1176,6 +1141,7 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
|
||||
break;
|
||||
} // BLE_GAP_EVENT_IDENTITY_RESOLVED
|
||||
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
case BLE_GAP_EVENT_PHY_UPDATE_COMPLETE: {
|
||||
NimBLEConnInfo peerInfo;
|
||||
rc = ble_gap_conn_find(event->phy_updated.conn_handle, &peerInfo.m_desc);
|
||||
@@ -1186,6 +1152,7 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
|
||||
pClient->m_pClientCallbacks->onPhyUpdate(pClient, event->phy_updated.tx_phy, event->phy_updated.rx_phy);
|
||||
return 0;
|
||||
} // BLE_GAP_EVENT_PHY_UPDATE_COMPLETE
|
||||
# endif
|
||||
|
||||
case BLE_GAP_EVENT_MTU: {
|
||||
if (pClient->m_connHandle != event->mtu.conn_handle) {
|
||||
@@ -1210,16 +1177,7 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (event->passkey.params.action == BLE_SM_IOACT_DISP) {
|
||||
struct ble_sm_io pkey = {0, 0};
|
||||
pkey.action = event->passkey.params.action;
|
||||
pkey.passkey = NimBLEDevice::getSecurityPasskey();
|
||||
if (pkey.passkey == 123456) {
|
||||
pkey.passkey = pClient->m_pClientCallbacks->onPassKeyDisplay(peerInfo);
|
||||
}
|
||||
rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
|
||||
NIMBLE_LOGD(LOG_TAG, "BLE_SM_IOACT_DISP; ble_sm_inject_io result: %d", rc);
|
||||
} else if (event->passkey.params.action == BLE_SM_IOACT_NUMCMP) {
|
||||
if (event->passkey.params.action == BLE_SM_IOACT_NUMCMP) {
|
||||
NIMBLE_LOGD(LOG_TAG, "Passkey on device's display: %" PRIu32, event->passkey.params.numcmp);
|
||||
pClient->m_pClientCallbacks->onConfirmPasskey(peerInfo, event->passkey.params.numcmp);
|
||||
} else if (event->passkey.params.action == BLE_SM_IOACT_OOB) {
|
||||
@@ -1323,11 +1281,6 @@ void NimBLEClientCallbacks::onPassKeyEntry(NimBLEConnInfo& connInfo) {
|
||||
NimBLEDevice::injectPassKey(connInfo, 123456);
|
||||
} // onPassKeyEntry
|
||||
|
||||
uint32_t NimBLEClientCallbacks::onPassKeyDisplay(NimBLEConnInfo& connInfo) {
|
||||
NIMBLE_LOGD(CB_TAG, "onPassKeyDisplay: default");
|
||||
return NimBLEDevice::getSecurityPasskey();
|
||||
} // onPassKeyDisplay
|
||||
|
||||
void NimBLEClientCallbacks::onAuthenticationComplete(NimBLEConnInfo& connInfo) {
|
||||
NIMBLE_LOGD(CB_TAG, "onAuthenticationComplete: default");
|
||||
} // onAuthenticationComplete
|
||||
@@ -1345,9 +1298,10 @@ void NimBLEClientCallbacks::onMTUChange(NimBLEClient* pClient, uint16_t mtu) {
|
||||
NIMBLE_LOGD(CB_TAG, "onMTUChange: default");
|
||||
} // onMTUChange
|
||||
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
void NimBLEClientCallbacks::onPhyUpdate(NimBLEClient* pClient, uint8_t txPhy, uint8_t rxPhy) {
|
||||
NIMBLE_LOGD(CB_TAG, "onPhyUpdate: default, txPhy: %d, rxPhy: %d", txPhy, rxPhy);
|
||||
} // onPhyUpdate
|
||||
#
|
||||
# endif
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_CENTRAL)
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
#ifndef NIMBLE_CPP_CLIENT_H_
|
||||
#define NIMBLE_CPP_CLIENT_H_
|
||||
|
||||
#include "syscfg/syscfg.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_CENTRAL)
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
|
||||
# if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
# include "host/ble_gap.h"
|
||||
@@ -48,12 +48,10 @@ struct NimBLETaskData;
|
||||
*/
|
||||
class NimBLEClient {
|
||||
public:
|
||||
# if MYNEWT_VAL(BLE_ROLE_OBSERVER)
|
||||
bool connect(const NimBLEAdvertisedDevice* device,
|
||||
bool deleteAttributes = true,
|
||||
bool asyncConnect = false,
|
||||
bool exchangeMTU = true);
|
||||
# endif
|
||||
bool connect(const NimBLEAddress& address, bool deleteAttributes = true, bool asyncConnect = false, bool exchangeMTU = true);
|
||||
bool connect(bool deleteAttributes = true, bool asyncConnect = false, bool exchangeMTU = true);
|
||||
bool disconnect(uint8_t reason = BLE_ERR_REM_USER_CONN_TERM);
|
||||
@@ -95,11 +93,11 @@ class NimBLEClient {
|
||||
const NimBLEAttValue& value,
|
||||
bool response = false);
|
||||
|
||||
# if MYNEWT_VAL(BLE_EXT_ADV)
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
void setConnectPhy(uint8_t phyMask);
|
||||
# endif
|
||||
bool updatePhy(uint8_t txPhysMask, uint8_t rxPhysMask, uint16_t phyOptions = 0);
|
||||
bool getPhy(uint8_t* txPhy, uint8_t* rxPhy);
|
||||
# endif
|
||||
|
||||
struct Config {
|
||||
uint8_t deleteCallbacks : 1; // Delete the callback object when the client is deleted.
|
||||
@@ -137,7 +135,7 @@ class NimBLEClient {
|
||||
mutable uint8_t m_asyncSecureAttempt;
|
||||
Config m_config;
|
||||
|
||||
# if MYNEWT_VAL(BLE_EXT_ADV)
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
uint8_t m_phyMask;
|
||||
# endif
|
||||
ble_gap_conn_params m_connParams;
|
||||
@@ -187,13 +185,6 @@ class NimBLEClientCallbacks {
|
||||
*/
|
||||
virtual void onPassKeyEntry(NimBLEConnInfo& connInfo);
|
||||
|
||||
/**
|
||||
* @brief Called when using passkey entry pairing and the passkey should be displayed.
|
||||
* @param [in] connInfo A reference to a NimBLEConnInfo instance containing the peer info.
|
||||
* @return The passkey to display to the user. The peer device must enter this passkey to complete the pairing.
|
||||
*/
|
||||
virtual uint32_t onPassKeyDisplay(NimBLEConnInfo& connInfo);
|
||||
|
||||
/**
|
||||
* @brief Called when the pairing procedure is complete.
|
||||
* @param [in] connInfo A reference to a NimBLEConnInfo instance containing the peer info.\n
|
||||
@@ -222,6 +213,7 @@ class NimBLEClientCallbacks {
|
||||
*/
|
||||
virtual void onMTUChange(NimBLEClient* pClient, uint16_t MTU);
|
||||
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
/**
|
||||
* @brief Called when the PHY update procedure is complete.
|
||||
* @param [in] pClient A pointer to the client whose PHY was updated.
|
||||
@@ -234,7 +226,8 @@ class NimBLEClientCallbacks {
|
||||
* * BLE_GAP_LE_PHY_CODED
|
||||
*/
|
||||
virtual void onPhyUpdate(NimBLEClient* pClient, uint8_t txPhy, uint8_t rxPhy);
|
||||
# endif
|
||||
};
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_CENTRAL)
|
||||
#endif // NIMBLE_CPP_CLIENT_H_
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|
||||
#endif /* NIMBLE_CPP_CLIENT_H_ */
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef NIMBLE_CPP_CONNINFO_H_
|
||||
#define NIMBLE_CPP_CONNINFO_H_
|
||||
#ifndef NIMBLECONNINFO_H_
|
||||
#define NIMBLECONNINFO_H_
|
||||
|
||||
#if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
# include "host/ble_gap.h"
|
||||
@@ -25,7 +25,6 @@
|
||||
#endif
|
||||
|
||||
#include "NimBLEAddress.h"
|
||||
#include <cstdio>
|
||||
|
||||
/**
|
||||
* @brief Connection information.
|
||||
@@ -71,41 +70,6 @@ class NimBLEConnInfo {
|
||||
/** @brief Gets the key size used to encrypt the connection */
|
||||
uint8_t getSecKeySize() const { return m_desc.sec_state.key_size; }
|
||||
|
||||
/** @brief Get a string representation of the connection info, useful for debugging */
|
||||
std::string toString() const {
|
||||
std::string str;
|
||||
// 294 chars max expected from all labels + worst-case values, round up to 300.
|
||||
str.resize(300);
|
||||
|
||||
snprintf(&str[0],
|
||||
str.size(),
|
||||
" Address: %s\n"
|
||||
" ID Address: %s\n"
|
||||
" Connection Handle: %u\n"
|
||||
" Connection Interval: %.1f ms\n"
|
||||
" Connection Timeout: %u ms\n"
|
||||
" Connection Latency: %u\n"
|
||||
" MTU: %u bytes\n"
|
||||
" Role: %s\n"
|
||||
" Bonded: %s\n"
|
||||
" Encrypted: %s\n"
|
||||
" Authenticated: %s\n"
|
||||
" Security Key Size: %u\n",
|
||||
getAddress().toString().c_str(),
|
||||
getIdAddress().toString().c_str(),
|
||||
getConnHandle(),
|
||||
getConnInterval() * 1.25f,
|
||||
getConnTimeout() * 10,
|
||||
getConnLatency(),
|
||||
getMTU(),
|
||||
isMaster() ? "Master" : "Slave",
|
||||
isBonded() ? "Yes" : "No",
|
||||
isEncrypted() ? "Yes" : "No",
|
||||
isAuthenticated() ? "Yes" : "No",
|
||||
getSecKeySize());
|
||||
return str;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class NimBLEServer;
|
||||
friend class NimBLEClient;
|
||||
@@ -116,5 +80,4 @@ class NimBLEConnInfo {
|
||||
NimBLEConnInfo() {};
|
||||
NimBLEConnInfo(ble_gap_conn_desc desc) { m_desc = desc; }
|
||||
};
|
||||
|
||||
#endif // NIMBLE_CPP_CONNINFO_H_
|
||||
#endif
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020-2025 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_VERSION_H_
|
||||
#define NIMBLE_CPP_VERSION_H_
|
||||
|
||||
/** @brief NimBLE-Arduino library major version number. */
|
||||
#define NIMBLE_CPP_VERSION_MAJOR 2
|
||||
|
||||
/** @brief NimBLE-Arduino library minor version number. */
|
||||
#define NIMBLE_CPP_VERSION_MINOR 4
|
||||
|
||||
/** @brief NimBLE-Arduino library patch version number. */
|
||||
#define NIMBLE_CPP_VERSION_PATCH 0
|
||||
|
||||
/**
|
||||
* @brief Macro to create a version number for comparison.
|
||||
* @param major Major version number.
|
||||
* @param minor Minor version number.
|
||||
* @param patch Patch version number.
|
||||
* @details Example usage:
|
||||
* @code{.cpp}
|
||||
* #if NIMBLE_CPP_VERSION >= NIMBLE_CPP_VERSION_VAL(2, 0, 0)
|
||||
* // Using NimBLE-Arduino v2 or later
|
||||
* #endif
|
||||
* @endcode
|
||||
*/
|
||||
#define NIMBLE_CPP_VERSION_VAL(major, minor, patch) (((major) << 16) | ((minor) << 8) | (patch))
|
||||
|
||||
/**
|
||||
* @brief The library version as a single integer for compile-time comparison.
|
||||
* @details Format: (major << 16) | (minor << 8) | patch
|
||||
*/
|
||||
#define NIMBLE_CPP_VERSION \
|
||||
NIMBLE_CPP_VERSION_VAL(NIMBLE_CPP_VERSION_MAJOR, NIMBLE_CPP_VERSION_MINOR, NIMBLE_CPP_VERSION_PATCH)
|
||||
|
||||
/** @cond NIMBLE_CPP_INTERNAL */
|
||||
#define NIMBLE_CPP_VERSION_STRINGIFY_IMPL(x) #x
|
||||
#define NIMBLE_CPP_VERSION_STRINGIFY(x) NIMBLE_CPP_VERSION_STRINGIFY_IMPL(x)
|
||||
/** @endcond */
|
||||
|
||||
/**
|
||||
* @brief Optional Semantic Versioning prerelease suffix.
|
||||
* @details Include the leading '-' when defined, for example: "-beta.1"
|
||||
*/
|
||||
#ifndef NIMBLE_CPP_VERSION_PRERELEASE
|
||||
# define NIMBLE_CPP_VERSION_PRERELEASE ""
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Optional Semantic Versioning build metadata suffix.
|
||||
* @details Include the leading '+' when defined, for example: "+sha.abcd1234"
|
||||
*/
|
||||
#ifndef NIMBLE_CPP_VERSION_BUILD_METADATA
|
||||
# define NIMBLE_CPP_VERSION_BUILD_METADATA ""
|
||||
#endif
|
||||
|
||||
/** @brief library version as a prefixed Semantic Versioning string. */
|
||||
#define NIMBLE_CPP_VERSION_STR \
|
||||
"NimBLE-CPP " \
|
||||
NIMBLE_CPP_VERSION_STRINGIFY(NIMBLE_CPP_VERSION_MAJOR) "." \
|
||||
NIMBLE_CPP_VERSION_STRINGIFY(NIMBLE_CPP_VERSION_MINOR) "." \
|
||||
NIMBLE_CPP_VERSION_STRINGIFY(NIMBLE_CPP_VERSION_PATCH) \
|
||||
NIMBLE_CPP_VERSION_PRERELEASE NIMBLE_CPP_VERSION_BUILD_METADATA
|
||||
|
||||
#endif // NIMBLE_CPP_VERSION_H_
|
||||
@@ -15,10 +15,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "NimBLEDescriptor.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
|
||||
# include "NimBLEService.h"
|
||||
# include "NimBLEDescriptor.h"
|
||||
# include "NimBLELog.h"
|
||||
|
||||
# include <string>
|
||||
@@ -147,4 +148,4 @@ void NimBLEDescriptorCallbacks::onWrite(NimBLEDescriptor* pDescriptor, NimBLECon
|
||||
NIMBLE_LOGD("NimBLEDescriptorCallbacks", "onWrite: default");
|
||||
} // onWrite
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
#ifndef NIMBLE_CPP_DESCRIPTOR_H_
|
||||
#define NIMBLE_CPP_DESCRIPTOR_H_
|
||||
|
||||
#include "syscfg/syscfg.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
|
||||
# include "NimBLELocalValueAttribute.h"
|
||||
# include <string>
|
||||
@@ -72,5 +72,5 @@ class NimBLEDescriptorCallbacks {
|
||||
|
||||
# include "NimBLE2904.h"
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
#endif // NIMBLE_CPP_DESCRIPTOR_H_
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||
#endif /* NIMBLE_CPP_DESCRIPTOR_H_ */
|
||||
|
||||
@@ -15,8 +15,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "NimBLEDevice.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
# include "NimBLEDevice.h"
|
||||
# include "NimBLEUtils.h"
|
||||
|
||||
# ifdef ESP_PLATFORM
|
||||
# include "esp_err.h"
|
||||
@@ -56,6 +59,14 @@
|
||||
# include "esp32-hal-bt.h"
|
||||
# endif
|
||||
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
# include "NimBLEClient.h"
|
||||
# endif
|
||||
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
# include "NimBLEServer.h"
|
||||
# endif
|
||||
|
||||
# include "NimBLELog.h"
|
||||
|
||||
static const char* LOG_TAG = "NimBLEDevice";
|
||||
@@ -65,30 +76,27 @@ extern "C" void ble_store_config_init(void);
|
||||
/**
|
||||
* Singletons for the NimBLEDevice.
|
||||
*/
|
||||
NimBLEDeviceCallbacks NimBLEDevice::defaultDeviceCallbacks{};
|
||||
NimBLEDeviceCallbacks NimBLEDevice::defaultDeviceCallbacks{};
|
||||
NimBLEDeviceCallbacks* NimBLEDevice::m_pDeviceCallbacks = &defaultDeviceCallbacks;
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_OBSERVER)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||
NimBLEScan* NimBLEDevice::m_pScan = nullptr;
|
||||
# endif
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
NimBLEServer* NimBLEDevice::m_pServer = nullptr;
|
||||
# if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM)
|
||||
NimBLEL2CAPServer* NimBLEDevice::m_pL2CAPServer = nullptr;
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_BROADCASTER)
|
||||
# if MYNEWT_VAL(BLE_EXT_ADV)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
NimBLEExtAdvertising* NimBLEDevice::m_bleAdvertising = nullptr;
|
||||
# else
|
||||
NimBLEAdvertising* NimBLEDevice::m_bleAdvertising = nullptr;
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_CENTRAL)
|
||||
std::array<NimBLEClient*, MYNEWT_VAL(BLE_MAX_CONNECTIONS)> NimBLEDevice::m_pClients{};
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
std::array<NimBLEClient*, NIMBLE_MAX_CONNECTIONS> NimBLEDevice::m_pClients{nullptr};
|
||||
# endif
|
||||
|
||||
bool NimBLEDevice::m_initialized{false};
|
||||
@@ -98,15 +106,10 @@ ble_gap_event_listener NimBLEDevice::m_listener{};
|
||||
std::vector<NimBLEAddress> NimBLEDevice::m_whiteList{};
|
||||
uint8_t NimBLEDevice::m_ownAddrType{BLE_OWN_ADDR_PUBLIC};
|
||||
|
||||
# if NIMBLE_CPP_SCAN_DUPL_ENABLED
|
||||
uint16_t NimBLEDevice::m_scanDuplicateSize{100};
|
||||
uint8_t NimBLEDevice::m_scanFilterMode{0};
|
||||
uint16_t NimBLEDevice::m_scanDuplicateResetTime{0};
|
||||
# if SOC_ESP_NIMBLE_CONTROLLER
|
||||
extern "C" int ble_vhci_disc_duplicate_set_max_cache_size(int max_cache_size);
|
||||
extern "C" int ble_vhci_disc_duplicate_set_period_refresh_time(int refresh_period_time);
|
||||
extern "C" int ble_vhci_disc_duplicate_mode_disable(int mode);
|
||||
extern "C" int ble_vhci_disc_duplicate_mode_enable(int mode);
|
||||
# ifdef ESP_PLATFORM
|
||||
# ifdef CONFIG_BTDM_BLE_SCAN_DUPL
|
||||
uint16_t NimBLEDevice::m_scanDuplicateSize{CONFIG_BTDM_SCAN_DUPL_CACHE_SIZE};
|
||||
uint8_t NimBLEDevice::m_scanFilterMode{CONFIG_BTDM_SCAN_DUPL_TYPE};
|
||||
# endif
|
||||
# endif
|
||||
|
||||
@@ -114,7 +117,7 @@ extern "C" int ble_vhci_disc_duplicate_mode_enable(int mode);
|
||||
/* SERVER FUNCTIONS */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
/**
|
||||
* @brief Create an instance of a server.
|
||||
* @return A pointer to the instance of the server.
|
||||
@@ -122,6 +125,9 @@ extern "C" int ble_vhci_disc_duplicate_mode_enable(int mode);
|
||||
NimBLEServer* NimBLEDevice::createServer() {
|
||||
if (NimBLEDevice::m_pServer == nullptr) {
|
||||
NimBLEDevice::m_pServer = new NimBLEServer();
|
||||
ble_gatts_reset();
|
||||
ble_svc_gap_init();
|
||||
ble_svc_gatt_init();
|
||||
}
|
||||
|
||||
return m_pServer;
|
||||
@@ -134,35 +140,14 @@ NimBLEServer* NimBLEDevice::createServer() {
|
||||
NimBLEServer* NimBLEDevice::getServer() {
|
||||
return m_pServer;
|
||||
} // getServer
|
||||
|
||||
# if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM)
|
||||
/**
|
||||
* @brief Create an instance of a L2CAP server.
|
||||
* @return A pointer to the instance of the L2CAP server.
|
||||
*/
|
||||
NimBLEL2CAPServer* NimBLEDevice::createL2CAPServer() {
|
||||
if (NimBLEDevice::m_pL2CAPServer == nullptr) {
|
||||
NimBLEDevice::m_pL2CAPServer = new NimBLEL2CAPServer();
|
||||
}
|
||||
return m_pL2CAPServer;
|
||||
} // createL2CAPServer
|
||||
|
||||
/**
|
||||
* @brief Get the instance of the L2CAP server.
|
||||
* @return A pointer to the L2CAP server instance or nullptr if none have been created.
|
||||
*/
|
||||
NimBLEL2CAPServer* NimBLEDevice::getL2CAPServer() {
|
||||
return m_pL2CAPServer;
|
||||
} // getL2CAPServer
|
||||
# endif // #if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM)
|
||||
# endif // #if MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
# endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* ADVERTISING FUNCTIONS */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_BROADCASTER)
|
||||
# if MYNEWT_VAL(BLE_EXT_ADV)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
/**
|
||||
* @brief Get the instance of the extended advertising object.
|
||||
* @return A pointer to the extended advertising object.
|
||||
@@ -196,7 +181,7 @@ bool NimBLEDevice::stopAdvertising(uint8_t instId) {
|
||||
} // stopAdvertising
|
||||
# endif
|
||||
|
||||
# if !MYNEWT_VAL(BLE_EXT_ADV) || defined(_DOXYGEN_)
|
||||
# if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_)
|
||||
/**
|
||||
* @brief Get the instance of the advertising object.
|
||||
* @return A pointer to the advertising object.
|
||||
@@ -225,7 +210,7 @@ bool NimBLEDevice::startAdvertising(uint32_t duration) {
|
||||
bool NimBLEDevice::stopAdvertising() {
|
||||
return getAdvertising()->stop();
|
||||
} // stopAdvertising
|
||||
# endif // #if MYNEWT_VAL(BLE_ROLE_BROADCASTER)
|
||||
# endif // #if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* SCAN FUNCTIONS */
|
||||
@@ -236,7 +221,7 @@ bool NimBLEDevice::stopAdvertising() {
|
||||
* @return The scanning object reference. This is a singleton object. The caller should not
|
||||
* try and release/delete it.
|
||||
*/
|
||||
# if MYNEWT_VAL(BLE_ROLE_OBSERVER)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||
NimBLEScan* NimBLEDevice::getScan() {
|
||||
if (m_pScan == nullptr) {
|
||||
m_pScan = new NimBLEScan();
|
||||
@@ -246,7 +231,7 @@ NimBLEScan* NimBLEDevice::getScan() {
|
||||
} // getScan
|
||||
|
||||
# ifdef ESP_PLATFORM
|
||||
# if CONFIG_BTDM_BLE_SCAN_DUPL || CONFIG_BT_LE_SCAN_DUPL
|
||||
# ifdef CONFIG_BTDM_BLE_SCAN_DUPL
|
||||
/**
|
||||
* @brief Set the duplicate filter cache size for filtering scanned devices.
|
||||
* @param [in] size The number of advertisements filtered before the cache is reset.\n
|
||||
@@ -293,34 +278,15 @@ void NimBLEDevice::setScanFilterMode(uint8_t mode) {
|
||||
|
||||
m_scanFilterMode = mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the time in seconds to reset the duplicate cache.
|
||||
* @param [in] time The time in seconds to reset the cache.
|
||||
* @details When the cache is reset all scanned devices will be reported again
|
||||
* even if already seen in the current scan. If set to 0 the cache will never be reset.
|
||||
*/
|
||||
void NimBLEDevice::setScanDuplicateCacheResetTime(uint16_t time) {
|
||||
if (m_initialized) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Cannot change scan cache reset time while initialized");
|
||||
return;
|
||||
} else if (time > 1000) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Invalid scan cache reset time");
|
||||
return;
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "Set duplicate cache reset time to: %u", time);
|
||||
m_scanDuplicateResetTime = time;
|
||||
}
|
||||
# endif // CONFIG_BTDM_BLE_SCAN_DUPL || CONFIG_BT_LE_SCAN_DUPL
|
||||
# endif // CONFIG_BTDM_BLE_SCAN_DUPL
|
||||
# endif // ESP_PLATFORM
|
||||
# endif // MYNEWT_VAL(BLE_ROLE_OBSERVER)
|
||||
# endif // #if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* CLIENT FUNCTIONS */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_CENTRAL)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
/**
|
||||
* @brief Creates a new client object, each client can connect to 1 peripheral device.
|
||||
* @return A pointer to the new client object, or nullptr on error.
|
||||
@@ -343,7 +309,7 @@ NimBLEClient* NimBLEDevice::createClient(const NimBLEAddress& peerAddress) {
|
||||
}
|
||||
}
|
||||
|
||||
NIMBLE_LOGE(LOG_TAG, "Unable to create client; already at max: %d", MYNEWT_VAL(BLE_MAX_CONNECTIONS));
|
||||
NIMBLE_LOGE(LOG_TAG, "Unable to create client; already at max: %d", NIMBLE_MAX_CONNECTIONS);
|
||||
return nullptr;
|
||||
} // createClient
|
||||
|
||||
@@ -455,7 +421,7 @@ std::vector<NimBLEClient*> NimBLEDevice::getConnectedClients() {
|
||||
return clients;
|
||||
} // getConnectedClients
|
||||
|
||||
# endif // MYNEWT_VAL(BLE_ROLE_CENTRAL)
|
||||
# endif // #if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* TRANSMIT POWER */
|
||||
@@ -510,14 +476,14 @@ bool NimBLEDevice::setPower(int8_t dbm, NimBLETxPowerType type) {
|
||||
dbm++; // round up to the next multiple of 3 to be able to target 20dbm
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
esp_power_level_t espPwr = static_cast<esp_power_level_t>(dbm / 3 + ESP_PWR_LVL_N0);
|
||||
bool success = false;
|
||||
esp_power_level_t espPwr = static_cast<esp_power_level_t>(dbm / 3 + ESP_PWR_LVL_N0);
|
||||
if (type == NimBLETxPowerType::All) {
|
||||
success = setPowerLevel(espPwr, ESP_BLE_PWR_TYPE_ADV);
|
||||
success &= setPowerLevel(espPwr, ESP_BLE_PWR_TYPE_SCAN);
|
||||
success &= setPowerLevel(espPwr, ESP_BLE_PWR_TYPE_DEFAULT);
|
||||
} else if (type == NimBLETxPowerType::Advertise) {
|
||||
success = setPowerLevel(espPwr, ESP_BLE_PWR_TYPE_ADV);
|
||||
success = setPowerLevel(espPwr, ESP_BLE_PWR_TYPE_ADV);
|
||||
} else if (type == NimBLETxPowerType::Scan) {
|
||||
success = setPowerLevel(espPwr, ESP_BLE_PWR_TYPE_SCAN);
|
||||
} else if (type == NimBLETxPowerType::Connection) {
|
||||
@@ -529,13 +495,15 @@ bool NimBLEDevice::setPower(int8_t dbm, NimBLETxPowerType type) {
|
||||
# else
|
||||
(void)type; // unused
|
||||
NIMBLE_LOGD(LOG_TAG, ">> setPower: %d", dbm);
|
||||
int rc = ble_phy_tx_power_set(dbm);
|
||||
ble_hci_vs_set_tx_pwr_cp cmd{dbm};
|
||||
ble_hci_vs_set_tx_pwr_rp rsp{0};
|
||||
int rc = ble_hs_hci_send_vs_cmd(BLE_HCI_OCF_VS_SET_TX_PWR, &cmd, sizeof(cmd), &rsp, sizeof(rsp));
|
||||
if (rc) {
|
||||
NIMBLE_LOGE(LOG_TAG, "failed to set TX power, rc: %04x\n", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "TX power set to %d dBm\n", dbm);
|
||||
NIMBLE_LOGD(LOG_TAG, "TX power set to %d dBm\n", rsp.tx_power);
|
||||
return true;
|
||||
# endif
|
||||
} // setPower
|
||||
@@ -571,7 +539,7 @@ int NimBLEDevice::getPower(NimBLETxPowerType type) {
|
||||
# endif
|
||||
# else
|
||||
(void)type; // unused
|
||||
return ble_phy_tx_power_get();
|
||||
return ble_phy_txpwr_get();
|
||||
# endif
|
||||
} // getPower
|
||||
|
||||
@@ -606,12 +574,11 @@ uint16_t NimBLEDevice::getMTU() {
|
||||
/* BOND MANAGEMENT */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_CENTRAL) || MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL) || defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
/**
|
||||
* @brief Gets the number of bonded peers stored
|
||||
*/
|
||||
int NimBLEDevice::getNumBonds() {
|
||||
# if MYNEWT_VAL(BLE_STORE_MAX_BONDS)
|
||||
ble_addr_t peer_id_addrs[MYNEWT_VAL(BLE_STORE_MAX_BONDS)];
|
||||
int num_peers, rc;
|
||||
rc = ble_store_util_bonded_peers(&peer_id_addrs[0], &num_peers, MYNEWT_VAL(BLE_STORE_MAX_BONDS));
|
||||
@@ -620,9 +587,6 @@ int NimBLEDevice::getNumBonds() {
|
||||
}
|
||||
|
||||
return num_peers;
|
||||
# else
|
||||
return 0;
|
||||
# endif
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -630,13 +594,10 @@ int NimBLEDevice::getNumBonds() {
|
||||
* @returns True on success.
|
||||
*/
|
||||
bool NimBLEDevice::deleteAllBonds() {
|
||||
int numBonds = NimBLEDevice::getNumBonds();
|
||||
for (int i = numBonds - 1; i >= 0; i--) {
|
||||
auto addr = NimBLEDevice::getBondedAddress(i);
|
||||
if (!NimBLEDevice::deleteBond(addr)) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Failed to delete bond for address: %s", addr.toString().c_str());
|
||||
return false;
|
||||
}
|
||||
int rc = ble_store_clear();
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Failed to delete all bonds; rc=%d", rc);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -656,7 +617,6 @@ bool NimBLEDevice::deleteBond(const NimBLEAddress& address) {
|
||||
* @returns True if bonded.
|
||||
*/
|
||||
bool NimBLEDevice::isBonded(const NimBLEAddress& address) {
|
||||
# if MYNEWT_VAL(BLE_STORE_MAX_BONDS)
|
||||
ble_addr_t peer_id_addrs[MYNEWT_VAL(BLE_STORE_MAX_BONDS)];
|
||||
int num_peers, rc;
|
||||
|
||||
@@ -671,8 +631,7 @@ bool NimBLEDevice::isBonded(const NimBLEAddress& address) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
# endif
|
||||
(void)address; // unused
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -682,19 +641,14 @@ bool NimBLEDevice::isBonded(const NimBLEAddress& address) {
|
||||
* @returns NimBLEAddress of the found bonded peer or null address if not found.
|
||||
*/
|
||||
NimBLEAddress NimBLEDevice::getBondedAddress(int index) {
|
||||
# if MYNEWT_VAL(BLE_STORE_MAX_BONDS)
|
||||
ble_addr_t peer_id_addrs[MYNEWT_VAL(BLE_STORE_MAX_BONDS)];
|
||||
int num_peers, rc;
|
||||
rc = ble_store_util_bonded_peers(&peer_id_addrs[0], &num_peers, MYNEWT_VAL(BLE_STORE_MAX_BONDS));
|
||||
if (rc != 0 || index >= num_peers || index < 0) {
|
||||
if (rc != 0 || index > num_peers || index < 0) {
|
||||
return NimBLEAddress{};
|
||||
}
|
||||
|
||||
return NimBLEAddress(peer_id_addrs[index]);
|
||||
# else
|
||||
(void)index; // unused
|
||||
return NimBLEAddress{};
|
||||
# endif
|
||||
}
|
||||
# endif
|
||||
|
||||
@@ -773,7 +727,7 @@ size_t NimBLEDevice::getWhiteListCount() {
|
||||
* @returns The NimBLEAddress at the whitelist index or null address if not found.
|
||||
*/
|
||||
NimBLEAddress NimBLEDevice::getWhiteListAddress(size_t index) {
|
||||
if (index >= m_whiteList.size()) {
|
||||
if (index > m_whiteList.size()) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Invalid index; %u", index);
|
||||
return NimBLEAddress{};
|
||||
}
|
||||
@@ -785,6 +739,7 @@ NimBLEAddress NimBLEDevice::getWhiteListAddress(size_t index) {
|
||||
/* STACK FUNCTIONS */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_)
|
||||
/**
|
||||
* @brief Set the preferred default phy to use for connections.
|
||||
* @param [in] txPhyMask TX PHY. Can be mask of following:
|
||||
@@ -807,6 +762,7 @@ bool NimBLEDevice::setDefaultPhy(uint8_t txPhyMask, uint8_t rxPhyMask) {
|
||||
|
||||
return rc == 0;
|
||||
}
|
||||
# endif
|
||||
|
||||
/**
|
||||
* @brief Host reset, we pass the message so we don't make calls until re-synced.
|
||||
@@ -857,13 +813,13 @@ void NimBLEDevice::onSync(void) {
|
||||
m_synced = true;
|
||||
|
||||
if (m_initialized) {
|
||||
# if MYNEWT_VAL(BLE_ROLE_OBSERVER)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||
if (m_pScan != nullptr) {
|
||||
m_pScan->onHostSync();
|
||||
}
|
||||
# endif
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_BROADCASTER)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||
if (m_bleAdvertising != nullptr) {
|
||||
m_bleAdvertising->onHostSync();
|
||||
}
|
||||
@@ -875,7 +831,7 @@ void NimBLEDevice::onSync(void) {
|
||||
* @brief The main host task.
|
||||
*/
|
||||
void NimBLEDevice::host_task(void* param) {
|
||||
NIMBLE_LOGI(LOG_TAG, "NimBLE Started!");
|
||||
NIMBLE_LOGI(LOG_TAG, "BLE Host Task Started");
|
||||
nimble_port_run(); // This function will return only when nimble_port_stop() is executed
|
||||
nimble_port_freertos_deinit();
|
||||
} // host_task
|
||||
@@ -886,10 +842,9 @@ void NimBLEDevice::host_task(void* param) {
|
||||
*/
|
||||
bool NimBLEDevice::init(const std::string& deviceName) {
|
||||
if (!m_initialized) {
|
||||
NIMBLE_LOGD(LOG_TAG, "Starting %s", getVersion());
|
||||
# ifdef ESP_PLATFORM
|
||||
|
||||
# if defined(CONFIG_ENABLE_ARDUINO_DEPENDS) && SOC_BT_SUPPORTED
|
||||
# ifdef CONFIG_ENABLE_ARDUINO_DEPENDS
|
||||
// make sure the linker includes esp32-hal-bt.c so Arduino init doesn't release BLE memory.
|
||||
btStarted();
|
||||
# endif
|
||||
@@ -911,69 +866,36 @@ bool NimBLEDevice::init(const std::string& deviceName) {
|
||||
esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT);
|
||||
# endif
|
||||
|
||||
# if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) || !defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
# if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) | !defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
||||
# if defined(CONFIG_IDF_TARGET_ESP32)
|
||||
bt_cfg.mode = ESP_BT_MODE_BLE;
|
||||
bt_cfg.ble_max_conn = MYNEWT_VAL(BLE_MAX_CONNECTIONS);
|
||||
# elif defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
bt_cfg.ble_max_act =
|
||||
MYNEWT_VAL(BLE_MAX_CONNECTIONS) + MYNEWT_VAL(BLE_ROLE_BROADCASTER) + MYNEWT_VAL(BLE_ROLE_OBSERVER);
|
||||
# if defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
bt_cfg.bluetooth_mode = ESP_BT_MODE_BLE;
|
||||
# else
|
||||
bt_cfg.nimble_max_connections = MYNEWT_VAL(BLE_MAX_CONNECTIONS);
|
||||
bt_cfg.mode = ESP_BT_MODE_BLE;
|
||||
bt_cfg.ble_max_conn = CONFIG_BT_NIMBLE_MAX_CONNECTIONS;
|
||||
# endif
|
||||
|
||||
# if NIMBLE_CPP_SCAN_DUPL_ENABLED
|
||||
# if !SOC_ESP_NIMBLE_CONTROLLER
|
||||
# ifdef CONFIG_BTDM_BLE_SCAN_DUPL
|
||||
bt_cfg.normal_adv_size = m_scanDuplicateSize;
|
||||
bt_cfg.scan_duplicate_type = m_scanFilterMode;
|
||||
bt_cfg.scan_duplicate_mode = 0; // Ensure normal filter mode, could be set to mesh in default config
|
||||
# if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
bt_cfg.dup_list_refresh_period = m_scanDuplicateResetTime;
|
||||
# endif
|
||||
# else // SOC_ESP_NIMBLE_CONTROLLER
|
||||
bt_cfg.ble_ll_rsp_dup_list_count = m_scanDuplicateSize;
|
||||
bt_cfg.ble_ll_adv_dup_list_count = m_scanDuplicateSize;
|
||||
# endif // SOC_ESP_NIMBLE_CONTROLLER
|
||||
# endif
|
||||
err = esp_bt_controller_init(&bt_cfg);
|
||||
if (err != ESP_OK) {
|
||||
NIMBLE_LOGE(LOG_TAG, "esp_bt_controller_init() failed; err=%d", err);
|
||||
return false;
|
||||
}
|
||||
|
||||
# if SOC_ESP_NIMBLE_CONTROLLER
|
||||
int mode = (1UL << 4); // FILTER_DUPLICATE_EXCEPTION_FOR_MESH
|
||||
switch (m_scanFilterMode) {
|
||||
case 1:
|
||||
mode |= (1UL << 3); // FILTER_DUPLICATE_ADVDATA
|
||||
break;
|
||||
case 2:
|
||||
mode |= ((1UL << 2) | (1UL << 3)); // FILTER_DUPLICATE_ADDRESS | FILTER_DUPLICATE_ADVDATA
|
||||
break;
|
||||
default:
|
||||
mode |= ((1UL << 0) | (1UL << 2)); // FILTER_DUPLICATE_PDUTYPE | FILTER_DUPLICATE_ADDRESS
|
||||
}
|
||||
|
||||
ble_vhci_disc_duplicate_mode_disable(0xFFFFFFFF);
|
||||
ble_vhci_disc_duplicate_mode_enable(mode);
|
||||
ble_vhci_disc_duplicate_set_max_cache_size(m_scanDuplicateSize);
|
||||
ble_vhci_disc_duplicate_set_period_refresh_time(m_scanDuplicateResetTime);
|
||||
# endif // SOC_ESP_NIMBLE_CONTROLLER
|
||||
# endif // NIMBLE_CPP_SCAN_DUPL_ENABLED
|
||||
|
||||
err = esp_bt_controller_enable(ESP_BT_MODE_BLE);
|
||||
if (err != ESP_OK) {
|
||||
NIMBLE_LOGE(LOG_TAG, "esp_bt_controller_enable() failed; err=%d", err);
|
||||
return false;
|
||||
}
|
||||
|
||||
# if CONFIG_BT_NIMBLE_LEGACY_VHCI_ENABLE
|
||||
err = esp_nimble_hci_init();
|
||||
if (err != ESP_OK) {
|
||||
NIMBLE_LOGE(LOG_TAG, "esp_nimble_hci_init() failed; err=%d", err);
|
||||
return false;
|
||||
}
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
nimble_port_init();
|
||||
@@ -989,7 +911,7 @@ bool NimBLEDevice::init(const std::string& deviceName) {
|
||||
ble_hs_cfg.sm_io_cap = BLE_HS_IO_NO_INPUT_OUTPUT;
|
||||
ble_hs_cfg.sm_bonding = 0;
|
||||
ble_hs_cfg.sm_mitm = 0;
|
||||
ble_hs_cfg.sm_sc = 0;
|
||||
ble_hs_cfg.sm_sc = 1;
|
||||
ble_hs_cfg.sm_our_key_dist = BLE_SM_PAIR_KEY_DIST_ENC;
|
||||
ble_hs_cfg.sm_their_key_dist = BLE_SM_PAIR_KEY_DIST_ENC;
|
||||
# if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
|
||||
@@ -1008,7 +930,6 @@ bool NimBLEDevice::init(const std::string& deviceName) {
|
||||
}
|
||||
|
||||
m_initialized = true; // Set the initialization flag to ensure we are only initialized once.
|
||||
NIMBLE_LOGD(LOG_TAG, "Initialized");
|
||||
return true;
|
||||
} // init
|
||||
|
||||
@@ -1039,34 +960,28 @@ bool NimBLEDevice::deinit(bool clearAll) {
|
||||
}
|
||||
|
||||
if (clearAll) {
|
||||
# if MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
if (NimBLEDevice::m_pServer != nullptr) {
|
||||
delete NimBLEDevice::m_pServer;
|
||||
NimBLEDevice::m_pServer = nullptr;
|
||||
}
|
||||
# if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM)
|
||||
if (NimBLEDevice::m_pL2CAPServer != nullptr) {
|
||||
delete NimBLEDevice::m_pL2CAPServer;
|
||||
NimBLEDevice::m_pL2CAPServer = nullptr;
|
||||
}
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_BROADCASTER)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||
if (NimBLEDevice::m_bleAdvertising != nullptr) {
|
||||
delete NimBLEDevice::m_bleAdvertising;
|
||||
NimBLEDevice::m_bleAdvertising = nullptr;
|
||||
}
|
||||
# endif
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_OBSERVER)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||
if (NimBLEDevice::m_pScan != nullptr) {
|
||||
delete NimBLEDevice::m_pScan;
|
||||
NimBLEDevice::m_pScan = nullptr;
|
||||
}
|
||||
# endif
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_CENTRAL)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
for (auto clt : m_pClients) {
|
||||
deleteClient(clt);
|
||||
}
|
||||
@@ -1123,16 +1038,18 @@ bool NimBLEDevice::setOwnAddrType(uint8_t type) {
|
||||
|
||||
m_ownAddrType = type;
|
||||
|
||||
# if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY)
|
||||
if (type == BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT || type == BLE_OWN_ADDR_RPA_RANDOM_DEFAULT) {
|
||||
# ifdef CONFIG_IDF_TARGET_ESP32
|
||||
// esp32 controller does not support RPA so we must use the random static for calls to the stack
|
||||
// the host will take care of the random private address generation/setting.
|
||||
m_ownAddrType = BLE_OWN_ADDR_RANDOM;
|
||||
rc = ble_hs_pvcy_rpa_config(NIMBLE_HOST_ENABLE_RPA);
|
||||
} else {
|
||||
rc = ble_hs_pvcy_rpa_config(NIMBLE_HOST_DISABLE_PRIVACY);
|
||||
}
|
||||
# endif
|
||||
} else {
|
||||
# ifdef CONFIG_IDF_TARGET_ESP32
|
||||
rc = ble_hs_pvcy_rpa_config(NIMBLE_HOST_DISABLE_PRIVACY);
|
||||
# endif
|
||||
}
|
||||
|
||||
return rc == 0;
|
||||
} // setOwnAddrType
|
||||
@@ -1267,7 +1184,7 @@ bool NimBLEDevice::startSecurity(uint16_t connHandle, int* rcPtr) {
|
||||
return rc == 0 || rc == BLE_HS_EALREADY;
|
||||
} // startSecurity
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_CENTRAL) || MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL) || defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
/**
|
||||
* @brief Inject the provided passkey into the Security Manager.
|
||||
* @param [in] peerInfo Connection information for the peer.
|
||||
@@ -1275,17 +1192,10 @@ bool NimBLEDevice::startSecurity(uint16_t connHandle, int* rcPtr) {
|
||||
* @return true if the passkey was injected successfully.
|
||||
*/
|
||||
bool NimBLEDevice::injectPassKey(const NimBLEConnInfo& peerInfo, uint32_t passkey) {
|
||||
#if MYNEWT_VAL(BLE_SM_LEGACY)
|
||||
ble_sm_io pkey{.action = BLE_SM_IOACT_INPUT, .passkey = passkey};
|
||||
int rc = ble_sm_inject_io(peerInfo.getConnHandle(), &pkey);
|
||||
NIMBLE_LOGD(LOG_TAG, "BLE_SM_IOACT_INPUT; ble_sm_inject_io result: %d", rc);
|
||||
return rc == 0;
|
||||
#else
|
||||
(void)peerInfo;
|
||||
(void)passkey;
|
||||
NIMBLE_LOGE(LOG_TAG, "Passkey entry not supported with current security settings");
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1294,19 +1204,12 @@ bool NimBLEDevice::injectPassKey(const NimBLEConnInfo& peerInfo, uint32_t passke
|
||||
* @param [in] accept Whether the user confirmed or declined the comparison.
|
||||
*/
|
||||
bool NimBLEDevice::injectConfirmPasskey(const NimBLEConnInfo& peerInfo, bool accept) {
|
||||
#if MYNEWT_VAL(BLE_SM_SC)
|
||||
ble_sm_io pkey{.action = BLE_SM_IOACT_NUMCMP, .numcmp_accept = accept};
|
||||
int rc = ble_sm_inject_io(peerInfo.getConnHandle(), &pkey);
|
||||
NIMBLE_LOGD(LOG_TAG, "BLE_SM_IOACT_NUMCMP; ble_sm_inject_io result: %d", rc);
|
||||
return rc == 0;
|
||||
#else
|
||||
(void)peerInfo;
|
||||
(void)accept;
|
||||
NIMBLE_LOGE(LOG_TAG, "Numeric comparison not supported with current security settings");
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
# endif // MYNEWT_VAL(BLE_ROLE_CENTRAL) || MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
# endif // CONFIG_BT_NIMBLE_ROLE_CENTRAL || CONFIG_BT_NIMBLE_ROLE_PERIPHERAL
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* UTILITIES */
|
||||
@@ -1317,24 +1220,22 @@ bool NimBLEDevice::injectConfirmPasskey(const NimBLEConnInfo& peerInfo, bool acc
|
||||
* @param [in] deviceName The name to set.
|
||||
*/
|
||||
bool NimBLEDevice::setDeviceName(const std::string& deviceName) {
|
||||
# if !defined(MYNEWT_VAL_BLE_GATTS) || MYNEWT_VAL(BLE_GATTS) > 0
|
||||
int rc = ble_svc_gap_device_name_set(deviceName.c_str());
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Device name not set - too long");
|
||||
return false;
|
||||
}
|
||||
# endif
|
||||
|
||||
return true;
|
||||
} // setDeviceName
|
||||
|
||||
/**
|
||||
* @brief Set a custom callback for gap events.
|
||||
* @param [in] handler The function to call when gap events occur.
|
||||
* @param [in] arg Argument to pass to the handler.
|
||||
* @returns
|
||||
*/
|
||||
bool NimBLEDevice::setCustomGapHandler(gap_event_handler handler, void* arg) {
|
||||
int rc = ble_gap_event_listener_register(&m_listener, handler, arg);
|
||||
bool NimBLEDevice::setCustomGapHandler(gap_event_handler handler) {
|
||||
int rc = ble_gap_event_listener_register(&m_listener, handler, NULL);
|
||||
if (rc == BLE_HS_EALREADY) {
|
||||
NIMBLE_LOGI(LOG_TAG, "Already listening to GAP events.");
|
||||
return true;
|
||||
@@ -1353,15 +1254,7 @@ std::string NimBLEDevice::toString() {
|
||||
return getAddress().toString();
|
||||
} // toString
|
||||
|
||||
/**
|
||||
* @brief Return the library version as a string.
|
||||
* @return A const char* containing library version information.
|
||||
*/
|
||||
const char* NimBLEDevice::getVersion() {
|
||||
return NIMBLE_CPP_VERSION_STR;
|
||||
} // getVersion
|
||||
|
||||
# if MYNEWT_VAL(NIMBLE_CPP_DEBUG_ASSERT_ENABLED) || __DOXYGEN__
|
||||
# if CONFIG_NIMBLE_CPP_DEBUG_ASSERT_ENABLED || __DOXYGEN__
|
||||
/**
|
||||
* @brief Debug assert - weak function.
|
||||
* @param [in] file The file where the assert occurred.
|
||||
@@ -1372,7 +1265,7 @@ void nimble_cpp_assert(const char* file, unsigned line) {
|
||||
ble_npl_time_delay(10);
|
||||
abort();
|
||||
}
|
||||
# endif // MYNEWT_VAL(NIMBLE_CPP_DEBUG_ASSERT_ENABLED)
|
||||
# endif // CONFIG_NIMBLE_CPP_DEBUG_ASSERT_ENABLED
|
||||
|
||||
void NimBLEDevice::setDeviceCallbacks(NimBLEDeviceCallbacks* cb) {
|
||||
m_pDeviceCallbacks = cb ? cb : &defaultDeviceCallbacks;
|
||||
@@ -1383,4 +1276,4 @@ int NimBLEDeviceCallbacks::onStoreStatus(struct ble_store_status_event* event, v
|
||||
return ble_store_util_status_rr(event, arg);
|
||||
}
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_ENABLED
|
||||
#endif // CONFIG_BT_ENABLED
|
||||
|
||||
@@ -18,15 +18,12 @@
|
||||
#ifndef NIMBLE_CPP_DEVICE_H_
|
||||
#define NIMBLE_CPP_DEVICE_H_
|
||||
|
||||
#include "NimBLECppVersion.h"
|
||||
#include "syscfg/syscfg.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
# ifdef ESP_PLATFORM
|
||||
# ifndef CONFIG_IDF_TARGET_ESP32P4
|
||||
# include <esp_bt.h>
|
||||
# endif
|
||||
# define NIMBLE_CPP_SCAN_DUPL_ENABLED \
|
||||
(CONFIG_BTDM_BLE_SCAN_DUPL || CONFIG_BT_LE_SCAN_DUPL || CONFIG_BT_CTRL_BLE_SCAN_DUPL)
|
||||
# endif
|
||||
|
||||
# if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
@@ -43,31 +40,28 @@
|
||||
# include <string>
|
||||
# include <vector>
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_CENTRAL)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
# include <array>
|
||||
class NimBLEClient;
|
||||
# endif
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_OBSERVER)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||
class NimBLEScan;
|
||||
# endif
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_BROADCASTER)
|
||||
# if MYNEWT_VAL(BLE_EXT_ADV)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
class NimBLEExtAdvertising;
|
||||
# else
|
||||
class NimBLEAdvertising;
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
class NimBLEServer;
|
||||
# if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM)
|
||||
class NimBLEL2CAPServer;
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_ROLE_CENTRAL)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) || defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
class NimBLEConnInfo;
|
||||
# endif
|
||||
|
||||
@@ -101,15 +95,19 @@ class NimBLEDeviceCallbacks;
|
||||
# define BLEEddystoneTLM NimBLEEddystoneTLM
|
||||
# define BLEEddystoneURL NimBLEEddystoneURL
|
||||
# define BLEConnInfo NimBLEConnInfo
|
||||
# define BLEL2CAPServer NimBLEL2CAPServer
|
||||
# define BLEL2CAPService NimBLEL2CAPService
|
||||
# define BLEL2CAPServiceCallbacks NimBLEL2CAPServiceCallbacks
|
||||
# define BLEL2CAPClient NimBLEL2CAPClient
|
||||
# define BLEL2CAPClientCallbacks NimBLEL2CAPClientCallbacks
|
||||
# define BLEL2CAPChannel NimBLEL2CAPChannel
|
||||
# define BLEL2CAPChannelCallbacks NimBLEL2CAPChannelCallbacks
|
||||
|
||||
enum class NimBLETxPowerType { All = 0, Advertise = 1, Scan = 2, Connection = 3 };
|
||||
# ifdef CONFIG_BT_NIMBLE_MAX_CONNECTIONS
|
||||
# define NIMBLE_MAX_CONNECTIONS CONFIG_BT_NIMBLE_MAX_CONNECTIONS
|
||||
# else
|
||||
# define NIMBLE_MAX_CONNECTIONS CONFIG_NIMBLE_MAX_CONNECTIONS
|
||||
# endif
|
||||
|
||||
enum class NimBLETxPowerType {
|
||||
All = 0,
|
||||
Advertise = 1,
|
||||
Scan = 2,
|
||||
Connection = 3
|
||||
};
|
||||
|
||||
typedef int (*gap_event_handler)(ble_gap_event* event, void* arg);
|
||||
|
||||
@@ -124,7 +122,6 @@ class NimBLEDevice {
|
||||
static bool isInitialized();
|
||||
static NimBLEAddress getAddress();
|
||||
static std::string toString();
|
||||
static const char* getVersion();
|
||||
static bool whiteListAdd(const NimBLEAddress& address);
|
||||
static bool whiteListRemove(const NimBLEAddress& address);
|
||||
static bool onWhiteList(const NimBLEAddress& address);
|
||||
@@ -136,8 +133,7 @@ class NimBLEDevice {
|
||||
static void setDeviceCallbacks(NimBLEDeviceCallbacks* cb);
|
||||
static void setScanDuplicateCacheSize(uint16_t cacheSize);
|
||||
static void setScanFilterMode(uint8_t type);
|
||||
static void setScanDuplicateCacheResetTime(uint16_t time);
|
||||
static bool setCustomGapHandler(gap_event_handler handler, void* arg = nullptr);
|
||||
static bool setCustomGapHandler(gap_event_handler handler);
|
||||
static void setSecurityAuth(bool bonding, bool mitm, bool sc);
|
||||
static void setSecurityAuth(uint8_t auth);
|
||||
static void setSecurityIOCap(uint8_t iocap);
|
||||
@@ -153,7 +149,6 @@ class NimBLEDevice {
|
||||
static void host_task(void* param);
|
||||
static int getPower(NimBLETxPowerType type = NimBLETxPowerType::All);
|
||||
static bool setPower(int8_t dbm, NimBLETxPowerType type = NimBLETxPowerType::All);
|
||||
static bool setDefaultPhy(uint8_t txPhyMask, uint8_t rxPhyMask);
|
||||
|
||||
# ifdef ESP_PLATFORM
|
||||
# ifndef CONFIG_IDF_TARGET_ESP32P4
|
||||
@@ -162,39 +157,39 @@ class NimBLEDevice {
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_OBSERVER)
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
static bool setDefaultPhy(uint8_t txPhyMask, uint8_t rxPhyMask);
|
||||
# endif
|
||||
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||
static NimBLEScan* getScan();
|
||||
# endif
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
static NimBLEServer* createServer();
|
||||
static NimBLEServer* getServer();
|
||||
# if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM)
|
||||
static NimBLEL2CAPServer* createL2CAPServer();
|
||||
static NimBLEL2CAPServer* getL2CAPServer();
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_ROLE_CENTRAL)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) || defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
static bool injectConfirmPasskey(const NimBLEConnInfo& peerInfo, bool accept);
|
||||
static bool injectPassKey(const NimBLEConnInfo& peerInfo, uint32_t pin);
|
||||
# endif
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_BROADCASTER)
|
||||
# if MYNEWT_VAL(BLE_EXT_ADV)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
static NimBLEExtAdvertising* getAdvertising();
|
||||
static bool startAdvertising(uint8_t instId, int duration = 0, int maxEvents = 0);
|
||||
static bool stopAdvertising(uint8_t instId);
|
||||
static bool stopAdvertising();
|
||||
# endif
|
||||
# if !MYNEWT_VAL(BLE_EXT_ADV) || defined(_DOXYGEN_)
|
||||
# if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_)
|
||||
static NimBLEAdvertising* getAdvertising();
|
||||
static bool startAdvertising(uint32_t duration = 0);
|
||||
static bool stopAdvertising();
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_CENTRAL)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
static NimBLEClient* createClient();
|
||||
static NimBLEClient* createClient(const NimBLEAddress& peerAddress);
|
||||
static bool deleteClient(NimBLEClient* pClient);
|
||||
@@ -205,7 +200,7 @@ class NimBLEDevice {
|
||||
static std::vector<NimBLEClient*> getConnectedClients();
|
||||
# endif
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_CENTRAL) || MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL) || defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
static bool deleteBond(const NimBLEAddress& address);
|
||||
static int getNumBonds();
|
||||
static bool isBonded(const NimBLEAddress& address);
|
||||
@@ -223,95 +218,85 @@ class NimBLEDevice {
|
||||
static NimBLEDeviceCallbacks* m_pDeviceCallbacks;
|
||||
static NimBLEDeviceCallbacks defaultDeviceCallbacks;
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_OBSERVER)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||
static NimBLEScan* m_pScan;
|
||||
# endif
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
static NimBLEServer* m_pServer;
|
||||
# if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM)
|
||||
static NimBLEL2CAPServer* m_pL2CAPServer;
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_BROADCASTER)
|
||||
# if MYNEWT_VAL(BLE_EXT_ADV)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
static NimBLEExtAdvertising* m_bleAdvertising;
|
||||
# else
|
||||
static NimBLEAdvertising* m_bleAdvertising;
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_CENTRAL)
|
||||
static std::array<NimBLEClient*, MYNEWT_VAL(BLE_MAX_CONNECTIONS)> m_pClients;
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
static std::array<NimBLEClient*, NIMBLE_MAX_CONNECTIONS> m_pClients;
|
||||
# endif
|
||||
|
||||
# ifdef ESP_PLATFORM
|
||||
# if NIMBLE_CPP_SCAN_DUPL_ENABLED
|
||||
# ifdef CONFIG_BTDM_BLE_SCAN_DUPL
|
||||
static uint16_t m_scanDuplicateSize;
|
||||
static uint8_t m_scanFilterMode;
|
||||
static uint16_t m_scanDuplicateResetTime;
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_CENTRAL)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
friend class NimBLEClient;
|
||||
# endif
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_OBSERVER)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||
friend class NimBLEScan;
|
||||
# endif
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
friend class NimBLEServer;
|
||||
friend class NimBLECharacteristic;
|
||||
# endif
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_BROADCASTER)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||
friend class NimBLEAdvertising;
|
||||
# if MYNEWT_VAL(BLE_EXT_ADV)
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
friend class NimBLEExtAdvertising;
|
||||
friend class NimBLEExtAdvertisement;
|
||||
# endif
|
||||
# endif
|
||||
};
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_CENTRAL)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
# include "NimBLEClient.h"
|
||||
# include "NimBLERemoteService.h"
|
||||
# include "NimBLERemoteCharacteristic.h"
|
||||
# include "NimBLERemoteDescriptor.h"
|
||||
# endif
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_OBSERVER)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||
# include "NimBLEScan.h"
|
||||
# endif
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
# include "NimBLEServer.h"
|
||||
# include "NimBLEService.h"
|
||||
# include "NimBLECharacteristic.h"
|
||||
# include "NimBLEDescriptor.h"
|
||||
# if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM)
|
||||
# include "NimBLEL2CAPServer.h"
|
||||
# include "NimBLEL2CAPChannel.h"
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_BROADCASTER)
|
||||
# if MYNEWT_VAL(BLE_EXT_ADV)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
# include "NimBLEExtAdvertising.h"
|
||||
# else
|
||||
# include "NimBLEAdvertising.h"
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_CENTRAL) || MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL) || defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
# include "NimBLEConnInfo.h"
|
||||
# include "NimBLEStream.h"
|
||||
# endif
|
||||
|
||||
# include "NimBLEAddress.h"
|
||||
# include "NimBLEUtils.h"
|
||||
|
||||
/**
|
||||
@@ -336,5 +321,5 @@ class NimBLEDeviceCallbacks {
|
||||
virtual int onStoreStatus(struct ble_store_status_event* event, void* arg);
|
||||
};
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_ENABLED
|
||||
#endif // CONFIG_BT_ENABLED
|
||||
#endif // NIMBLE_CPP_DEVICE_H_
|
||||
|
||||
@@ -15,9 +15,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "NimBLEEddystoneTLM.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_BROADCASTER)
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||
|
||||
# include "NimBLEEddystoneTLM.h"
|
||||
# include "NimBLEUUID.h"
|
||||
# include "NimBLELog.h"
|
||||
|
||||
@@ -215,4 +216,4 @@ void NimBLEEddystoneTLM::setTime(uint32_t tmil) {
|
||||
m_eddystoneData.tmil = tmil;
|
||||
} // setTime
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_BROADCASTER)
|
||||
#endif // CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
#ifndef NIMBLE_CPP_EDDYSTONETLM_H_
|
||||
#define NIMBLE_CPP_EDDYSTONETLM_H_
|
||||
|
||||
#include "syscfg/syscfg.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_BROADCASTER)
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||
|
||||
class NimBLEUUID;
|
||||
|
||||
@@ -66,5 +66,5 @@ class NimBLEEddystoneTLM {
|
||||
|
||||
}; // NimBLEEddystoneTLM
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_BROADCASTER)
|
||||
#endif // CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER
|
||||
#endif // NIMBLE_CPP_EDDYSTONETLM_H_
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "NimBLEExtAdvertising.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_BROADCASTER) && MYNEWT_VAL(BLE_EXT_ADV)
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER) && CONFIG_BT_NIMBLE_EXT_ADV
|
||||
|
||||
# if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
# include "services/gap/ble_svc_gap.h"
|
||||
@@ -24,6 +24,7 @@
|
||||
# include "nimble/nimble/host/services/gap/include/services/gap/ble_svc_gap.h"
|
||||
# endif
|
||||
|
||||
# include "NimBLEExtAdvertising.h"
|
||||
# include "NimBLEDevice.h"
|
||||
# include "NimBLEServer.h"
|
||||
# include "NimBLEUtils.h"
|
||||
@@ -38,7 +39,7 @@ static const char* LOG_TAG = "NimBLEExtAdvertising";
|
||||
NimBLEExtAdvertising::NimBLEExtAdvertising()
|
||||
: m_deleteCallbacks{false},
|
||||
m_pCallbacks{&defaultCallbacks},
|
||||
m_advStatus(MYNEWT_VAL(BLE_MULTI_ADV_INSTANCES) + 1, false) {}
|
||||
m_advStatus(CONFIG_BT_NIMBLE_MAX_EXT_ADV_INSTANCES + 1, false) {}
|
||||
|
||||
/**
|
||||
* @brief Destructor: deletes callback instances if requested.
|
||||
@@ -68,7 +69,7 @@ bool NimBLEExtAdvertising::setInstanceData(uint8_t instId, NimBLEExtAdvertisemen
|
||||
adv.m_params.scan_req_notif = false;
|
||||
}
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
NimBLEServer* pServer = NimBLEDevice::getServer();
|
||||
if (pServer != nullptr) {
|
||||
pServer->start(); // make sure the GATT server is ready before advertising
|
||||
@@ -391,7 +392,7 @@ void NimBLEExtAdvertisement::setTxPower(int8_t dbm) {
|
||||
* @param [in] enable True = connectable.
|
||||
*/
|
||||
void NimBLEExtAdvertisement::setConnectable(bool enable) {
|
||||
# if MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
m_params.connectable = enable;
|
||||
# endif
|
||||
} // setConnectable
|
||||
@@ -531,7 +532,7 @@ void NimBLEExtAdvertisement::clearData() {
|
||||
* @details This will completely replace any data that was previously set.
|
||||
*/
|
||||
bool NimBLEExtAdvertisement::setData(const uint8_t* data, size_t length) {
|
||||
if (length > MYNEWT_VAL(BLE_EXT_ADV_MAX_SIZE)) {
|
||||
if (length > CONFIG_BT_NIMBLE_MAX_EXT_ADV_DATA_LEN) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -546,7 +547,7 @@ bool NimBLEExtAdvertisement::setData(const uint8_t* data, size_t length) {
|
||||
* @return True if successful, false if the data is too large.
|
||||
*/
|
||||
bool NimBLEExtAdvertisement::addData(const uint8_t* data, size_t length) {
|
||||
if (m_payload.size() + length > MYNEWT_VAL(BLE_EXT_ADV_MAX_SIZE)) {
|
||||
if (m_payload.size() + length > CONFIG_BT_NIMBLE_MAX_EXT_ADV_DATA_LEN) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -560,7 +561,7 @@ bool NimBLEExtAdvertisement::addData(const uint8_t* data, size_t length) {
|
||||
* @return True if successful, false if the data is too large.
|
||||
*/
|
||||
bool NimBLEExtAdvertisement::addData(const std::string& data) {
|
||||
if (m_payload.size() + data.length() > MYNEWT_VAL(BLE_EXT_ADV_MAX_SIZE)) {
|
||||
if (m_payload.size() + data.length() > CONFIG_BT_NIMBLE_MAX_EXT_ADV_DATA_LEN) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -616,11 +617,6 @@ bool NimBLEExtAdvertisement::setFlags(uint8_t flag) {
|
||||
* @return True if successful.
|
||||
*/
|
||||
bool NimBLEExtAdvertisement::setManufacturerData(const uint8_t* data, size_t length) {
|
||||
if (length > 0xFF - 1) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Manufacturer data too long!");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t header[2];
|
||||
header[0] = length + 1;
|
||||
header[1] = BLE_HS_ADV_TYPE_MFG_DATA;
|
||||
@@ -657,11 +653,6 @@ bool NimBLEExtAdvertisement::setManufacturerData(const std::vector<uint8_t>& dat
|
||||
* @return True if successful.
|
||||
*/
|
||||
bool NimBLEExtAdvertisement::setURI(const std::string& uri) {
|
||||
if (uri.length() > 0xFF - 1) {
|
||||
NIMBLE_LOGE(LOG_TAG, "URI too long!");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t header[2];
|
||||
header[0] = uri.length() + 1;
|
||||
header[1] = BLE_HS_ADV_TYPE_URI;
|
||||
@@ -680,11 +671,6 @@ bool NimBLEExtAdvertisement::setURI(const std::string& uri) {
|
||||
* @return True if successful.
|
||||
*/
|
||||
bool NimBLEExtAdvertisement::setName(const std::string& name, bool isComplete) {
|
||||
if (name.length() > 0xFF - 1) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Name too long!");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t header[2];
|
||||
header[0] = name.length() + 1;
|
||||
header[1] = isComplete ? BLE_HS_ADV_TYPE_COMP_NAME : BLE_HS_ADV_TYPE_INCOMP_NAME;
|
||||
@@ -725,7 +711,7 @@ bool NimBLEExtAdvertisement::addServiceUUID(const NimBLEUUID& serviceUUID) {
|
||||
length += 2;
|
||||
}
|
||||
|
||||
if (length + getDataSize() > MYNEWT_VAL(BLE_EXT_ADV_MAX_SIZE)) {
|
||||
if (length + getDataSize() > CONFIG_BT_NIMBLE_MAX_EXT_ADV_DATA_LEN) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Cannot add UUID, data length exceeded!");
|
||||
return false;
|
||||
}
|
||||
@@ -932,13 +918,9 @@ bool NimBLEExtAdvertisement::setServices(bool complete, uint8_t size, const std:
|
||||
*/
|
||||
bool NimBLEExtAdvertisement::setServiceData(const NimBLEUUID& uuid, const uint8_t* data, size_t length) {
|
||||
uint8_t uuidBytes = uuid.bitSize() / 8;
|
||||
if (length + uuidBytes + 2 > 0xFF) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Service data too long!");
|
||||
return false;
|
||||
}
|
||||
uint8_t sDataLen = 2 + uuidBytes + length;
|
||||
|
||||
uint8_t sDataLen = 2 + uuidBytes + length;
|
||||
if (m_payload.size() + sDataLen > MYNEWT_VAL(BLE_EXT_ADV_MAX_SIZE)) {
|
||||
if (m_payload.size() + sDataLen > CONFIG_BT_NIMBLE_MAX_EXT_ADV_DATA_LEN) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1109,4 +1091,4 @@ std::string NimBLEExtAdvertisement::toString() const {
|
||||
return str;
|
||||
} // toString
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_BROADCASTER) && MYNEWT_VAL(BLE_EXT_ADV)
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER && CONFIG_BT_NIMBLE_EXT_ADV */
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
#ifndef NIMBLE_CPP_EXTADVERTISING_H_
|
||||
#define NIMBLE_CPP_EXTADVERTISING_H_
|
||||
|
||||
#include "syscfg/syscfg.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_BROADCASTER) && MYNEWT_VAL(BLE_EXT_ADV)
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER) && CONFIG_BT_NIMBLE_EXT_ADV
|
||||
|
||||
# if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
# include "host/ble_gap.h"
|
||||
@@ -159,5 +159,5 @@ class NimBLEExtAdvertisingCallbacks {
|
||||
virtual void onScanRequest(NimBLEExtAdvertising* pAdv, uint8_t instId, NimBLEAddress addr);
|
||||
}; // NimBLEExtAdvertisingCallbacks
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_BROADCASTER) && MYNEWT_VAL(BLE_EXT_ADV)
|
||||
#endif // CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER && CONFIG_BT_NIMBLE_EXT_ADV
|
||||
#endif // NIMBLE_CPP_EXTADVERTISING_H_
|
||||
|
||||
@@ -15,9 +15,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "NimBLEHIDDevice.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_BROADCASTER) && MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
|
||||
# include "NimBLEHIDDevice.h"
|
||||
# include "NimBLEServer.h"
|
||||
# include "NimBLEService.h"
|
||||
# include "NimBLE2904.h"
|
||||
@@ -84,7 +85,9 @@ void NimBLEHIDDevice::setReportMap(uint8_t* map, uint16_t size) {
|
||||
* This function called when all the services have been created.
|
||||
*/
|
||||
void NimBLEHIDDevice::startServices() {
|
||||
// no-op now, services started by server start.
|
||||
m_deviceInfoSvc->start();
|
||||
m_hidSvc->start();
|
||||
m_batterySvc->start();
|
||||
} // startServices
|
||||
|
||||
/**
|
||||
@@ -338,4 +341,4 @@ NimBLEService* NimBLEHIDDevice::getBatteryService() {
|
||||
return m_batterySvc;
|
||||
} // getBatteryService
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
#ifndef NIMBLE_CPP_HIDDEVICE_H_
|
||||
#define NIMBLE_CPP_HIDDEVICE_H_
|
||||
|
||||
#include "syscfg/syscfg.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_BROADCASTER) && MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
|
||||
# include <stdint.h>
|
||||
# include <string>
|
||||
@@ -49,8 +49,7 @@ class NimBLEHIDDevice {
|
||||
NimBLEHIDDevice(NimBLEServer* server);
|
||||
|
||||
void setReportMap(uint8_t* map, uint16_t);
|
||||
void startServices() __attribute__((deprecated("Services are now started by the server when start() is called, "
|
||||
"this function is no longer needed and will be removed in a future release.")));
|
||||
void startServices();
|
||||
bool setManufacturer(const std::string& name);
|
||||
void setPnp(uint8_t sig, uint16_t vid, uint16_t pid, uint16_t version);
|
||||
void setHidInfo(uint8_t country, uint8_t flags);
|
||||
@@ -86,5 +85,5 @@ class NimBLEHIDDevice {
|
||||
NimBLECharacteristic* locateReportCharacteristicByIdAndType(uint8_t reportId, uint8_t reportType);
|
||||
};
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_BROADCASTER) && MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
#endif // CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
#endif // NIMBLE_CPP_HIDDEVICE_H_
|
||||
|
||||
@@ -1,314 +0,0 @@
|
||||
//
|
||||
// (C) Dr. Michael 'Mickey' Lauer <mickey@vanille-media.de>
|
||||
//
|
||||
|
||||
#include "NimBLEL2CAPChannel.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM)
|
||||
|
||||
# include "NimBLEClient.h"
|
||||
# include "NimBLELog.h"
|
||||
# include "NimBLEUtils.h"
|
||||
|
||||
# if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
# include "host/ble_gap.h"
|
||||
# else
|
||||
# include "nimble/nimble/host/include/host/ble_gap.h"
|
||||
# endif
|
||||
|
||||
// L2CAP buffer block size
|
||||
# define L2CAP_BUF_BLOCK_SIZE (250)
|
||||
# define L2CAP_BUF_SIZE_MTUS_PER_CHANNEL (3)
|
||||
// Round-up integer division
|
||||
# define CEIL_DIVIDE(a, b) (((a) + (b) - 1) / (b))
|
||||
# define ROUND_DIVIDE(a, b) (((a) + (b) / 2) / (b))
|
||||
// Retry
|
||||
constexpr uint32_t RetryTimeout = 50;
|
||||
constexpr int RetryCounter = 3;
|
||||
|
||||
NimBLEL2CAPChannel::NimBLEL2CAPChannel(uint16_t psm, uint16_t mtu, NimBLEL2CAPChannelCallbacks* callbacks)
|
||||
: psm(psm), mtu(mtu), callbacks(callbacks) {
|
||||
assert(mtu); // fail here, if MTU is too little
|
||||
assert(callbacks); // fail here, if no callbacks are given
|
||||
assert(setupMemPool()); // fail here, if the memory pool could not be setup
|
||||
|
||||
NIMBLE_LOGI(LOG_TAG, "L2CAP COC 0x%04X initialized w/ L2CAP MTU %i", this->psm, this->mtu);
|
||||
};
|
||||
|
||||
NimBLEL2CAPChannel::~NimBLEL2CAPChannel() {
|
||||
teardownMemPool();
|
||||
|
||||
NIMBLE_LOGI(LOG_TAG, "L2CAP COC 0x%04X shutdown and freed.", this->psm);
|
||||
}
|
||||
|
||||
bool NimBLEL2CAPChannel::setupMemPool() {
|
||||
const size_t buf_blocks = CEIL_DIVIDE(mtu, L2CAP_BUF_BLOCK_SIZE) * L2CAP_BUF_SIZE_MTUS_PER_CHANNEL;
|
||||
NIMBLE_LOGD(LOG_TAG, "Computed number of buf_blocks = %d", buf_blocks);
|
||||
|
||||
_coc_memory = malloc(OS_MEMPOOL_SIZE(buf_blocks, L2CAP_BUF_BLOCK_SIZE) * sizeof(os_membuf_t));
|
||||
if (_coc_memory == 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Can't allocate _coc_memory: %d", errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto rc = os_mempool_init(&_coc_mempool, buf_blocks, L2CAP_BUF_BLOCK_SIZE, _coc_memory, "appbuf");
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Can't os_mempool_init: %d", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto rc2 = os_mbuf_pool_init(&_coc_mbuf_pool, &_coc_mempool, L2CAP_BUF_BLOCK_SIZE, buf_blocks);
|
||||
if (rc2 != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Can't os_mbuf_pool_init: %d", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
this->receiveBuffer = (uint8_t*)malloc(mtu);
|
||||
if (!this->receiveBuffer) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Can't malloc receive buffer: %d, %s", errno, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NimBLEL2CAPChannel::teardownMemPool() {
|
||||
if (this->callbacks) {
|
||||
delete this->callbacks;
|
||||
}
|
||||
if (this->receiveBuffer) {
|
||||
free(this->receiveBuffer);
|
||||
}
|
||||
if (_coc_memory) {
|
||||
free(_coc_memory);
|
||||
}
|
||||
}
|
||||
|
||||
int NimBLEL2CAPChannel::writeFragment(std::vector<uint8_t>::const_iterator begin, std::vector<uint8_t>::const_iterator end) {
|
||||
auto toSend = end - begin;
|
||||
|
||||
if (stalled) {
|
||||
NIMBLE_LOGD(LOG_TAG, "L2CAP Channel waiting for unstall...");
|
||||
NimBLETaskData taskData;
|
||||
m_pTaskData = &taskData;
|
||||
NimBLEUtils::taskWait(taskData, BLE_NPL_TIME_FOREVER);
|
||||
m_pTaskData = nullptr;
|
||||
stalled = false;
|
||||
NIMBLE_LOGD(LOG_TAG, "L2CAP Channel unstalled!");
|
||||
}
|
||||
|
||||
struct ble_l2cap_chan_info info;
|
||||
ble_l2cap_get_chan_info(channel, &info);
|
||||
// Take the minimum of our and peer MTU
|
||||
auto mtu = info.peer_coc_mtu < info.our_coc_mtu ? info.peer_coc_mtu : info.our_coc_mtu;
|
||||
|
||||
if (toSend > mtu) {
|
||||
return -BLE_HS_EBADDATA;
|
||||
}
|
||||
|
||||
auto retries = RetryCounter;
|
||||
|
||||
while (retries--) {
|
||||
auto txd = os_mbuf_get_pkthdr(&_coc_mbuf_pool, 0);
|
||||
if (!txd) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Can't os_mbuf_get_pkthdr.");
|
||||
return -BLE_HS_ENOMEM;
|
||||
}
|
||||
auto append = os_mbuf_append(txd, &(*begin), toSend);
|
||||
if (append != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Can't os_mbuf_append: %d", append);
|
||||
return append;
|
||||
}
|
||||
|
||||
auto res = ble_l2cap_send(channel, txd);
|
||||
switch (res) {
|
||||
case 0:
|
||||
NIMBLE_LOGD(LOG_TAG, "L2CAP COC 0x%04X sent %d bytes.", this->psm, toSend);
|
||||
return 0;
|
||||
|
||||
case BLE_HS_ESTALLED:
|
||||
stalled = true;
|
||||
NIMBLE_LOGD(LOG_TAG, "L2CAP COC 0x%04X sent %d bytes.", this->psm, toSend);
|
||||
NIMBLE_LOGW(LOG_TAG,
|
||||
"ble_l2cap_send returned BLE_HS_ESTALLED. Next send will wait for unstalled event...");
|
||||
return 0;
|
||||
|
||||
case BLE_HS_ENOMEM:
|
||||
case BLE_HS_EAGAIN:
|
||||
case BLE_HS_EBUSY:
|
||||
NIMBLE_LOGD(LOG_TAG, "ble_l2cap_send returned %d. Retrying shortly...", res);
|
||||
os_mbuf_free_chain(txd);
|
||||
ble_npl_time_delay(ble_npl_time_ms_to_ticks32(RetryTimeout));
|
||||
continue;
|
||||
|
||||
default:
|
||||
NIMBLE_LOGE(LOG_TAG, "ble_l2cap_send failed: %d", res);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
NIMBLE_LOGE(LOG_TAG, "Retries exhausted, dropping %d bytes to send.", toSend);
|
||||
return -BLE_HS_EREJECT;
|
||||
}
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_CENTRAL)
|
||||
NimBLEL2CAPChannel* NimBLEL2CAPChannel::connect(NimBLEClient* client,
|
||||
uint16_t psm,
|
||||
uint16_t mtu,
|
||||
NimBLEL2CAPChannelCallbacks* callbacks) {
|
||||
if (!client->isConnected()) {
|
||||
NIMBLE_LOGE(
|
||||
LOG_TAG,
|
||||
"Client is not connected. Before connecting via L2CAP, a GAP connection must have been established");
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
auto channel = new NimBLEL2CAPChannel(psm, mtu, callbacks);
|
||||
|
||||
auto sdu_rx = os_mbuf_get_pkthdr(&channel->_coc_mbuf_pool, 0);
|
||||
if (!sdu_rx) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Can't allocate SDU buffer: %d, %s", errno, strerror(errno));
|
||||
return nullptr;
|
||||
}
|
||||
auto rc = ble_l2cap_connect(client->getConnHandle(), psm, mtu, sdu_rx, NimBLEL2CAPChannel::handleL2capEvent, channel);
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "ble_l2cap_connect failed: %d", rc);
|
||||
}
|
||||
return channel;
|
||||
}
|
||||
# endif // MYNEWT_VAL(BLE_ROLE_CENTRAL)
|
||||
|
||||
bool NimBLEL2CAPChannel::write(const std::vector<uint8_t>& bytes) {
|
||||
if (!this->channel) {
|
||||
NIMBLE_LOGW(LOG_TAG, "L2CAP Channel not open");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ble_l2cap_chan_info info;
|
||||
ble_l2cap_get_chan_info(channel, &info);
|
||||
auto mtu = info.peer_coc_mtu < info.our_coc_mtu ? info.peer_coc_mtu : info.our_coc_mtu;
|
||||
|
||||
auto start = bytes.begin();
|
||||
while (start != bytes.end()) {
|
||||
auto end = start + mtu < bytes.end() ? start + mtu : bytes.end();
|
||||
if (writeFragment(start, end) < 0) {
|
||||
return false;
|
||||
}
|
||||
start = end;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// private
|
||||
int NimBLEL2CAPChannel::handleConnectionEvent(struct ble_l2cap_event* event) {
|
||||
channel = event->connect.chan;
|
||||
struct ble_l2cap_chan_info info;
|
||||
ble_l2cap_get_chan_info(channel, &info);
|
||||
NIMBLE_LOGI(LOG_TAG,
|
||||
"L2CAP COC 0x%04X connected. Local MTU = %d [%d], remote MTU = %d [%d].",
|
||||
psm,
|
||||
info.our_coc_mtu,
|
||||
info.our_l2cap_mtu,
|
||||
info.peer_coc_mtu,
|
||||
info.peer_l2cap_mtu);
|
||||
if (info.our_coc_mtu > info.peer_coc_mtu) {
|
||||
NIMBLE_LOGW(LOG_TAG, "L2CAP COC 0x%04X connected, but local MTU is bigger than remote MTU.", psm);
|
||||
}
|
||||
auto mtu = info.peer_coc_mtu < info.our_coc_mtu ? info.peer_coc_mtu : info.our_coc_mtu;
|
||||
callbacks->onConnect(this, mtu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int NimBLEL2CAPChannel::handleAcceptEvent(struct ble_l2cap_event* event) {
|
||||
NIMBLE_LOGI(LOG_TAG, "L2CAP COC 0x%04X accept.", psm);
|
||||
if (!callbacks->shouldAcceptConnection(this)) {
|
||||
NIMBLE_LOGI(LOG_TAG, "L2CAP COC 0x%04X refused by delegate.", psm);
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct os_mbuf* sdu_rx = os_mbuf_get_pkthdr(&_coc_mbuf_pool, 0);
|
||||
assert(sdu_rx != NULL);
|
||||
ble_l2cap_recv_ready(event->accept.chan, sdu_rx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int NimBLEL2CAPChannel::handleDataReceivedEvent(struct ble_l2cap_event* event) {
|
||||
NIMBLE_LOGD(LOG_TAG, "L2CAP COC 0x%04X data received.", psm);
|
||||
|
||||
struct os_mbuf* rxd = event->receive.sdu_rx;
|
||||
assert(rxd != NULL);
|
||||
|
||||
int rx_len = (int)OS_MBUF_PKTLEN(rxd);
|
||||
assert(rx_len <= (int)mtu);
|
||||
|
||||
int res = os_mbuf_copydata(rxd, 0, rx_len, receiveBuffer);
|
||||
assert(res == 0);
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "L2CAP COC 0x%04X received %d bytes.", psm, rx_len);
|
||||
|
||||
res = os_mbuf_free_chain(rxd);
|
||||
assert(res == 0);
|
||||
|
||||
std::vector<uint8_t> incomingData(receiveBuffer, receiveBuffer + rx_len);
|
||||
callbacks->onRead(this, incomingData);
|
||||
|
||||
struct os_mbuf* next = os_mbuf_get_pkthdr(&_coc_mbuf_pool, 0);
|
||||
assert(next != NULL);
|
||||
|
||||
res = ble_l2cap_recv_ready(channel, next);
|
||||
assert(res == 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int NimBLEL2CAPChannel::handleTxUnstalledEvent(struct ble_l2cap_event* event) {
|
||||
if (m_pTaskData != nullptr) {
|
||||
NimBLEUtils::taskRelease(*m_pTaskData, event->tx_unstalled.status);
|
||||
}
|
||||
|
||||
NIMBLE_LOGI(LOG_TAG, "L2CAP COC 0x%04X transmit unstalled.", psm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int NimBLEL2CAPChannel::handleDisconnectionEvent(struct ble_l2cap_event* event) {
|
||||
NIMBLE_LOGI(LOG_TAG, "L2CAP COC 0x%04X disconnected.", psm);
|
||||
channel = NULL;
|
||||
callbacks->onDisconnect(this);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* STATIC */
|
||||
int NimBLEL2CAPChannel::handleL2capEvent(struct ble_l2cap_event* event, void* arg) {
|
||||
NIMBLE_LOGD(LOG_TAG, "handleL2capEvent: handling l2cap event %d", event->type);
|
||||
NimBLEL2CAPChannel* self = reinterpret_cast<NimBLEL2CAPChannel*>(arg);
|
||||
|
||||
int returnValue = 0;
|
||||
|
||||
switch (event->type) {
|
||||
case BLE_L2CAP_EVENT_COC_CONNECTED:
|
||||
returnValue = self->handleConnectionEvent(event);
|
||||
break;
|
||||
|
||||
case BLE_L2CAP_EVENT_COC_DISCONNECTED:
|
||||
returnValue = self->handleDisconnectionEvent(event);
|
||||
break;
|
||||
|
||||
case BLE_L2CAP_EVENT_COC_ACCEPT:
|
||||
returnValue = self->handleAcceptEvent(event);
|
||||
break;
|
||||
|
||||
case BLE_L2CAP_EVENT_COC_DATA_RECEIVED:
|
||||
returnValue = self->handleDataReceivedEvent(event);
|
||||
break;
|
||||
|
||||
case BLE_L2CAP_EVENT_COC_TX_UNSTALLED:
|
||||
returnValue = self->handleTxUnstalledEvent(event);
|
||||
break;
|
||||
|
||||
default:
|
||||
NIMBLE_LOGW(LOG_TAG, "Unhandled l2cap event %d", event->type);
|
||||
break;
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
#endif // #if CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM)
|
||||
@@ -1,126 +0,0 @@
|
||||
//
|
||||
// (C) Dr. Michael 'Mickey' Lauer <mickey@vanille-media.de>
|
||||
//
|
||||
|
||||
#ifndef NIMBLE_CPP_L2CAPCHANNEL_H_
|
||||
#define NIMBLE_CPP_L2CAPCHANNEL_H_
|
||||
|
||||
#include "syscfg/syscfg.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM)
|
||||
|
||||
# include "inttypes.h"
|
||||
# if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
# include "host/ble_l2cap.h"
|
||||
# include "os/os_mbuf.h"
|
||||
# else
|
||||
# include "nimble/nimble/host/include/host/ble_l2cap.h"
|
||||
# include "nimble/porting/nimble/include/os/os_mbuf.h"
|
||||
# endif
|
||||
|
||||
/**** FIX COMPILATION ****/
|
||||
# undef min
|
||||
# undef max
|
||||
/**************************/
|
||||
|
||||
# include <vector>
|
||||
# include <atomic>
|
||||
|
||||
class NimBLEClient;
|
||||
class NimBLEL2CAPChannelCallbacks;
|
||||
struct NimBLETaskData;
|
||||
|
||||
/**
|
||||
* @brief Encapsulates a L2CAP channel.
|
||||
*
|
||||
* This class is used to encapsulate a L2CAP connection oriented channel, both
|
||||
* from the "server" (which waits for the connection to be opened) and the "client"
|
||||
* (which opens the connection) point of view.
|
||||
*/
|
||||
class NimBLEL2CAPChannel {
|
||||
public:
|
||||
/// @brief Open an L2CAP channel via the specified PSM and MTU.
|
||||
/// @param[in] psm The PSM to use.
|
||||
/// @param[in] mtu The MTU to use. Note that this is the local MTU. Upon opening the channel,
|
||||
/// the final MTU will be negotiated to be the minimum of local and remote.
|
||||
/// @param[in] callbacks The callbacks to use. NOTE that these callbacks are called from the
|
||||
/// context of the NimBLE bluetooth task (`nimble_host`) and MUST be handled as fast as possible.
|
||||
/// @return True if the channel was opened successfully, false otherwise.
|
||||
static NimBLEL2CAPChannel* connect(NimBLEClient* client, uint16_t psm, uint16_t mtu, NimBLEL2CAPChannelCallbacks* callbacks);
|
||||
|
||||
/// @brief Write data to the channel.
|
||||
///
|
||||
/// If the size of the data exceeds the MTU, the data will be split into multiple fragments.
|
||||
/// @return true on success, after the data has been sent.
|
||||
/// @return false, if the data can't be sent.
|
||||
///
|
||||
/// NOTE: This function will block until the data has been sent or an error occurred.
|
||||
bool write(const std::vector<uint8_t>& bytes);
|
||||
|
||||
/// @return True, if the channel is connected. False, otherwise.
|
||||
bool isConnected() const { return !!channel; }
|
||||
|
||||
protected:
|
||||
NimBLEL2CAPChannel(uint16_t psm, uint16_t mtu, NimBLEL2CAPChannelCallbacks* callbacks);
|
||||
~NimBLEL2CAPChannel();
|
||||
|
||||
int handleConnectionEvent(struct ble_l2cap_event* event);
|
||||
int handleAcceptEvent(struct ble_l2cap_event* event);
|
||||
int handleDataReceivedEvent(struct ble_l2cap_event* event);
|
||||
int handleTxUnstalledEvent(struct ble_l2cap_event* event);
|
||||
int handleDisconnectionEvent(struct ble_l2cap_event* event);
|
||||
|
||||
private:
|
||||
friend class NimBLEL2CAPServer;
|
||||
static constexpr const char* LOG_TAG = "NimBLEL2CAPChannel";
|
||||
|
||||
const uint16_t psm; // PSM of the channel
|
||||
const uint16_t mtu; // The requested (local) MTU of the channel, might be larger than negotiated MTU
|
||||
struct ble_l2cap_chan* channel = nullptr;
|
||||
NimBLEL2CAPChannelCallbacks* callbacks;
|
||||
uint8_t* receiveBuffer = nullptr; // buffers a full (local) MTU
|
||||
|
||||
// NimBLE memory pool
|
||||
void* _coc_memory = nullptr;
|
||||
struct os_mempool _coc_mempool;
|
||||
struct os_mbuf_pool _coc_mbuf_pool;
|
||||
|
||||
// Runtime handling
|
||||
std::atomic<bool> stalled{false};
|
||||
NimBLETaskData* m_pTaskData{nullptr};
|
||||
|
||||
// Allocate / deallocate NimBLE memory pool
|
||||
bool setupMemPool();
|
||||
void teardownMemPool();
|
||||
|
||||
// Writes data up to the size of the negotiated MTU to the channel.
|
||||
int writeFragment(std::vector<uint8_t>::const_iterator begin, std::vector<uint8_t>::const_iterator end);
|
||||
|
||||
// L2CAP event handler
|
||||
static int handleL2capEvent(struct ble_l2cap_event* event, void* arg);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Callbacks base class for the L2CAP channel.
|
||||
*/
|
||||
class NimBLEL2CAPChannelCallbacks {
|
||||
public:
|
||||
NimBLEL2CAPChannelCallbacks() = default;
|
||||
virtual ~NimBLEL2CAPChannelCallbacks() = default;
|
||||
|
||||
/// Called when the client attempts to open a channel on the server.
|
||||
/// You can choose to accept or deny the connection.
|
||||
/// Default implementation returns true.
|
||||
virtual bool shouldAcceptConnection(NimBLEL2CAPChannel* channel) { return true; }
|
||||
/// Called after a connection has been made.
|
||||
/// Default implementation does nothing.
|
||||
virtual void onConnect(NimBLEL2CAPChannel* channel, uint16_t negotiatedMTU) {};
|
||||
/// Called when data has been read from the channel.
|
||||
/// Default implementation does nothing.
|
||||
virtual void onRead(NimBLEL2CAPChannel* channel, std::vector<uint8_t>& data) {};
|
||||
/// Called after the channel has been disconnected.
|
||||
/// Default implementation does nothing.
|
||||
virtual void onDisconnect(NimBLEL2CAPChannel* channel) {};
|
||||
};
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM)
|
||||
#endif // NIMBLE_CPP_L2CAPCHANNEL_H_
|
||||
@@ -1,40 +0,0 @@
|
||||
//
|
||||
// (C) Dr. Michael 'Mickey' Lauer <mickey@vanille-media.de>
|
||||
//
|
||||
|
||||
#include "NimBLEL2CAPServer.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM)
|
||||
|
||||
# include "NimBLEL2CAPChannel.h"
|
||||
# include "NimBLEDevice.h"
|
||||
# include "NimBLELog.h"
|
||||
|
||||
static const char* LOG_TAG = "NimBLEL2CAPServer";
|
||||
|
||||
NimBLEL2CAPServer::NimBLEL2CAPServer() {
|
||||
// Nothing to do here...
|
||||
}
|
||||
|
||||
NimBLEL2CAPServer::~NimBLEL2CAPServer() {
|
||||
// Delete all services
|
||||
for (auto service : this->services) {
|
||||
delete service;
|
||||
}
|
||||
}
|
||||
|
||||
NimBLEL2CAPChannel* NimBLEL2CAPServer::createService(const uint16_t psm,
|
||||
const uint16_t mtu,
|
||||
NimBLEL2CAPChannelCallbacks* callbacks) {
|
||||
auto service = new NimBLEL2CAPChannel(psm, mtu, callbacks);
|
||||
auto rc = ble_l2cap_create_server(psm, mtu, NimBLEL2CAPChannel::handleL2capEvent, service);
|
||||
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Could not ble_l2cap_create_server: %d", rc);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
this->services.push_back(service);
|
||||
return service;
|
||||
}
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM)
|
||||
@@ -1,41 +0,0 @@
|
||||
//
|
||||
// (C) Dr. Michael 'Mickey' Lauer <mickey@vanille-media.de>
|
||||
//
|
||||
|
||||
#ifndef NIMBLE_CPP_L2CAPSERVER_H_
|
||||
#define NIMBLE_CPP_L2CAPSERVER_H_
|
||||
#include "syscfg/syscfg.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM)
|
||||
|
||||
# include "inttypes.h"
|
||||
# include <vector>
|
||||
|
||||
class NimBLEL2CAPChannel;
|
||||
class NimBLEL2CAPChannelCallbacks;
|
||||
|
||||
/**
|
||||
* @brief L2CAP server class.
|
||||
*
|
||||
* Encapsulates a L2CAP server that can hold multiple services. Every service is represented by a channel object
|
||||
* and an assorted set of callbacks.
|
||||
*/
|
||||
class NimBLEL2CAPServer {
|
||||
public:
|
||||
/// @brief Register a new L2CAP service instance.
|
||||
/// @param psm The port multiplexor service number.
|
||||
/// @param mtu The maximum transmission unit.
|
||||
/// @param callbacks The callbacks for this service.
|
||||
/// @return the newly created object, if the server registration was successful.
|
||||
NimBLEL2CAPChannel* createService(const uint16_t psm, const uint16_t mtu, NimBLEL2CAPChannelCallbacks* callbacks);
|
||||
|
||||
private:
|
||||
NimBLEL2CAPServer();
|
||||
~NimBLEL2CAPServer();
|
||||
std::vector<NimBLEL2CAPChannel*> services;
|
||||
|
||||
friend class NimBLEL2CAPChannel;
|
||||
friend class NimBLEDevice;
|
||||
};
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM)
|
||||
#endif // NIMBLE_CPP_L2CAPSERVER_H_
|
||||
@@ -18,8 +18,8 @@
|
||||
#ifndef NIMBLE_CPP_LOCAL_ATTRIBUTE_H_
|
||||
#define NIMBLE_CPP_LOCAL_ATTRIBUTE_H_
|
||||
|
||||
#include "syscfg/syscfg.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
|
||||
# include "NimBLEAttribute.h"
|
||||
|
||||
@@ -54,5 +54,5 @@ class NimBLELocalAttribute : public NimBLEAttribute {
|
||||
uint8_t m_removed{0};
|
||||
};
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
#endif // CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL
|
||||
#endif // NIMBLE_CPP_LOCAL_ATTRIBUTE_H_
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
#ifndef NIMBLE_LOCAL_VALUE_ATTRIBUTE_H_
|
||||
#define NIMBLE_LOCAL_VALUE_ATTRIBUTE_H_
|
||||
|
||||
#include "syscfg/syscfg.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
|
||||
# if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
# include "host/ble_hs.h"
|
||||
@@ -48,18 +48,30 @@ typedef enum {
|
||||
} NIMBLE_PROPERTY;
|
||||
|
||||
# include "NimBLELocalAttribute.h"
|
||||
# include "NimBLEValueAttribute.h"
|
||||
# include "NimBLEAttValue.h"
|
||||
# include <vector>
|
||||
class NimBLEConnInfo;
|
||||
|
||||
class NimBLELocalValueAttribute : public NimBLELocalAttribute, public NimBLEValueAttribute {
|
||||
class NimBLELocalValueAttribute : public NimBLELocalAttribute {
|
||||
public:
|
||||
/**
|
||||
* @brief Get the properties of the attribute.
|
||||
*/
|
||||
uint16_t getProperties() const { return m_properties; }
|
||||
|
||||
/**
|
||||
* @brief Get the length of the attribute value.
|
||||
* @return The length of the attribute value.
|
||||
*/
|
||||
size_t getLength() const { return m_value.size(); }
|
||||
|
||||
/**
|
||||
* @brief Get a copy of the value of the attribute value.
|
||||
* @param [in] timestamp (Optional) A pointer to a time_t struct to get the time the value set.
|
||||
* @return A copy of the attribute value.
|
||||
*/
|
||||
NimBLEAttValue getValue(time_t* timestamp = nullptr) const { return m_value; }
|
||||
|
||||
/**
|
||||
* @brief Set the value of the attribute value.
|
||||
* @param [in] data The data to set the value to.
|
||||
@@ -88,6 +100,19 @@ class NimBLELocalValueAttribute : public NimBLELocalAttribute, public NimBLEValu
|
||||
m_value.setValue<T>(val);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Template to convert the data to <type\>.
|
||||
* @tparam T The type to convert the data to.
|
||||
* @param [in] timestamp (Optional) A pointer to a time_t struct to get the time the value set.
|
||||
* @param [in] skipSizeCheck (Optional) If true it will skip checking if the data size is less than <tt>sizeof(<type\>)</tt>.
|
||||
* @return The data converted to <type\> or NULL if skipSizeCheck is false and the data is less than <tt>sizeof(<type\>)</tt>.
|
||||
* @details <b>Use:</b> <tt>getValue<type>(×tamp, skipSizeCheck);</tt>
|
||||
*/
|
||||
template <typename T>
|
||||
T getValue(time_t* timestamp = nullptr, bool skipSizeCheck = false) const {
|
||||
return m_value.getValue<T>(timestamp, skipSizeCheck);
|
||||
}
|
||||
|
||||
protected:
|
||||
friend class NimBLEServer;
|
||||
|
||||
@@ -101,8 +126,9 @@ class NimBLELocalValueAttribute : public NimBLELocalAttribute, public NimBLEValu
|
||||
NimBLELocalValueAttribute(const NimBLEUUID& uuid,
|
||||
uint16_t handle,
|
||||
uint16_t maxLen,
|
||||
uint16_t initLen = MYNEWT_VAL(NIMBLE_CPP_ATT_VALUE_INIT_LENGTH))
|
||||
: NimBLELocalAttribute(uuid, handle), NimBLEValueAttribute(maxLen, initLen) {}
|
||||
uint16_t initLen = CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH)
|
||||
: NimBLELocalAttribute(uuid, handle), m_value(initLen, maxLen) {}
|
||||
|
||||
/**
|
||||
* @brief Destroy the NimBLELocalValueAttribute object.
|
||||
*/
|
||||
@@ -137,8 +163,9 @@ class NimBLELocalValueAttribute : public NimBLELocalAttribute, public NimBLEValu
|
||||
*/
|
||||
void setProperties(uint16_t properties) { m_properties = properties; }
|
||||
|
||||
uint16_t m_properties{0};
|
||||
NimBLEAttValue m_value{};
|
||||
uint16_t m_properties{0};
|
||||
};
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
#endif // CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL
|
||||
#endif // NIMBLE_LOCAL_VALUE_ATTRIBUTE_H_
|
||||
|
||||
@@ -18,24 +18,15 @@
|
||||
#ifndef NIMBLE_CPP_LOG_H_
|
||||
#define NIMBLE_CPP_LOG_H_
|
||||
|
||||
#include "syscfg/syscfg.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED
|
||||
|
||||
# ifndef MYNEWT_VAL_NIMBLE_CPP_LOG_LEVEL
|
||||
# ifndef CONFIG_NIMBLE_CPP_LOG_LEVEL
|
||||
# if defined(ARDUINO_ARCH_ESP32) && defined(CORE_DEBUG_LEVEL)
|
||||
# define MYNEWT_VAL_NIMBLE_CPP_LOG_LEVEL CORE_DEBUG_LEVEL
|
||||
# else
|
||||
# define MYNEWT_VAL_NIMBLE_CPP_LOG_LEVEL 0
|
||||
# endif
|
||||
# else
|
||||
# define MYNEWT_VAL_NIMBLE_CPP_LOG_LEVEL CONFIG_NIMBLE_CPP_LOG_LEVEL
|
||||
# endif
|
||||
# endif
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
# if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
# include "esp_log.h"
|
||||
# include "console/console.h"
|
||||
# ifndef CONFIG_NIMBLE_CPP_LOG_LEVEL
|
||||
# define CONFIG_NIMBLE_CPP_LOG_LEVEL 0
|
||||
# endif
|
||||
|
||||
# if defined(CONFIG_NIMBLE_CPP_LOG_OVERRIDE_COLOR)
|
||||
# if CONFIG_LOG_COLORS
|
||||
@@ -129,13 +120,13 @@
|
||||
|
||||
# define NIMBLE_CPP_LOG_PRINT(level, tag, format, ...) \
|
||||
do { \
|
||||
if (MYNEWT_VAL(NIMBLE_CPP_LOG_LEVEL) >= level) NIMBLE_CPP_LOG_LEVEL_LOCAL(level, tag, format, ##__VA_ARGS__); \
|
||||
if (CONFIG_NIMBLE_CPP_LOG_LEVEL >= level) NIMBLE_CPP_LOG_LEVEL_LOCAL(level, tag, format, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
# else
|
||||
# define NIMBLE_CPP_LOG_PRINT(level, tag, format, ...) \
|
||||
do { \
|
||||
if (MYNEWT_VAL(NIMBLE_CPP_LOG_LEVEL) >= level) ESP_LOG_LEVEL_LOCAL(level, tag, format, ##__VA_ARGS__); \
|
||||
if (CONFIG_NIMBLE_CPP_LOG_LEVEL >= level) ESP_LOG_LEVEL_LOCAL(level, tag, format, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
# endif /* CONFIG_NIMBLE_CPP_LOG_OVERRIDE_COLOR */
|
||||
@@ -146,27 +137,35 @@
|
||||
# define NIMBLE_LOGE(tag, format, ...) NIMBLE_CPP_LOG_PRINT(ESP_LOG_ERROR, tag, format, ##__VA_ARGS__)
|
||||
|
||||
# else
|
||||
# include "nimble/porting/nimble/include/syscfg/syscfg.h"
|
||||
# include "nimble/console/console.h"
|
||||
# ifndef CONFIG_NIMBLE_CPP_LOG_LEVEL
|
||||
# if defined(ARDUINO_ARCH_ESP32) && defined(CORE_DEBUG_LEVEL)
|
||||
# define CONFIG_NIMBLE_CPP_LOG_LEVEL CORE_DEBUG_LEVEL
|
||||
# else
|
||||
# define CONFIG_NIMBLE_CPP_LOG_LEVEL 0
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if MYNEWT_VAL(NIMBLE_CPP_LOG_LEVEL) >= 4
|
||||
# if CONFIG_NIMBLE_CPP_LOG_LEVEL >= 4
|
||||
# define NIMBLE_LOGD(tag, format, ...) console_printf("D %s: " format "\n", tag, ##__VA_ARGS__)
|
||||
# else
|
||||
# define NIMBLE_LOGD(tag, format, ...) (void)tag
|
||||
# endif
|
||||
|
||||
# if MYNEWT_VAL(NIMBLE_CPP_LOG_LEVEL) >= 3
|
||||
# if CONFIG_NIMBLE_CPP_LOG_LEVEL >= 3
|
||||
# define NIMBLE_LOGI(tag, format, ...) console_printf("I %s: " format "\n", tag, ##__VA_ARGS__)
|
||||
# else
|
||||
# define NIMBLE_LOGI(tag, format, ...) (void)tag
|
||||
# endif
|
||||
|
||||
# if MYNEWT_VAL(NIMBLE_CPP_LOG_LEVEL) >= 2
|
||||
# if CONFIG_NIMBLE_CPP_LOG_LEVEL >= 2
|
||||
# define NIMBLE_LOGW(tag, format, ...) console_printf("W %s: " format "\n", tag, ##__VA_ARGS__)
|
||||
# else
|
||||
# define NIMBLE_LOGW(tag, format, ...) (void)tag
|
||||
# endif
|
||||
|
||||
# if MYNEWT_VAL(NIMBLE_CPP_LOG_LEVEL) >= 1
|
||||
# if CONFIG_NIMBLE_CPP_LOG_LEVEL >= 1
|
||||
# define NIMBLE_LOGE(tag, format, ...) console_printf("E %s: " format "\n", tag, ##__VA_ARGS__)
|
||||
# else
|
||||
# define NIMBLE_LOGE(tag, format, ...) (void)tag
|
||||
@@ -180,5 +179,5 @@
|
||||
# define NIMBLE_LOGE_IF(cond, tag, format, ...) { if (cond) { NIMBLE_LOGE(tag, format, ##__VA_ARGS__); }}
|
||||
# define NIMBLE_LOGE_RC(rc, tag, format, ...) { if (rc) { NIMBLE_LOGE(tag, format "; rc=%d %s", ##__VA_ARGS__, rc, NimBLEUtils::returnCodeToString(rc)); }}
|
||||
|
||||
#endif /* CONFIG_BT_NIMBLE_ENABLED */
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
#endif /* NIMBLE_CPP_LOG_H_ */
|
||||
@@ -15,9 +15,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "NimBLERemoteCharacteristic.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_CENTRAL)
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
|
||||
# include "NimBLERemoteCharacteristic.h"
|
||||
# include "NimBLERemoteDescriptor.h"
|
||||
# include "NimBLERemoteService.h"
|
||||
# include "NimBLEClient.h"
|
||||
@@ -94,24 +95,8 @@ int NimBLERemoteCharacteristic::descriptorDiscCB(
|
||||
bool NimBLERemoteCharacteristic::retrieveDescriptors(NimBLEDescriptorFilter* pFilter) const {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> retrieveDescriptors() for characteristic: %s", getUUID().toString().c_str());
|
||||
|
||||
const auto pSvc = getRemoteService();
|
||||
uint16_t endHandle = pSvc->getEndHandle();
|
||||
|
||||
// Find the handle of the next characteristic to limit the descriptor search range.
|
||||
const auto& chars = pSvc->getCharacteristics(false);
|
||||
for (auto it = chars.begin(); it != chars.end(); ++it) {
|
||||
if ((*it)->getHandle() == this->getHandle()) {
|
||||
auto next_it = std::next(it);
|
||||
if (next_it != chars.end()) {
|
||||
endHandle = (*next_it)->getHandle() - 1;
|
||||
NIMBLE_LOGD(LOG_TAG, "Search range limited to handle 0x%04X", endHandle);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If this is the last handle then there are no descriptors
|
||||
if (getHandle() == endHandle) {
|
||||
if (getHandle() == getRemoteService()->getEndHandle()) {
|
||||
NIMBLE_LOGD(LOG_TAG, "<< retrieveDescriptors(): found 0 descriptors.");
|
||||
return true;
|
||||
}
|
||||
@@ -124,7 +109,7 @@ bool NimBLERemoteCharacteristic::retrieveDescriptors(NimBLEDescriptorFilter* pFi
|
||||
|
||||
int rc = ble_gattc_disc_all_dscs(getClient()->getConnHandle(),
|
||||
getHandle(),
|
||||
endHandle,
|
||||
getRemoteService()->getEndHandle(),
|
||||
NimBLERemoteCharacteristic::descriptorDiscCB,
|
||||
pFilter);
|
||||
if (rc != 0) {
|
||||
@@ -133,7 +118,7 @@ bool NimBLERemoteCharacteristic::retrieveDescriptors(NimBLEDescriptorFilter* pFi
|
||||
}
|
||||
|
||||
auto prevDscCount = m_vDescriptors.size();
|
||||
NimBLEUtils::taskWait(taskData, BLE_NPL_TIME_FOREVER);
|
||||
NimBLEUtils::taskWait(pFilter->taskData, BLE_NPL_TIME_FOREVER);
|
||||
rc = ((NimBLETaskData*)pFilter->taskData)->m_flags;
|
||||
if (rc != BLE_HS_EDONE) {
|
||||
NIMBLE_LOGE(LOG_TAG, "<< retrieveDescriptors(): failed: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
|
||||
@@ -403,4 +388,4 @@ NimBLEClient* NimBLERemoteCharacteristic::getClient() const {
|
||||
return getRemoteService()->getClient();
|
||||
} // getClient
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_CENTRAL)
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
#ifndef NIMBLE_CPP_REMOTE_CHARACTERISTIC_H_
|
||||
#define NIMBLE_CPP_REMOTE_CHARACTERISTIC_H_
|
||||
|
||||
#include "syscfg/syscfg.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_CENTRAL)
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
|
||||
# include "NimBLERemoteValueAttribute.h"
|
||||
# include <vector>
|
||||
@@ -79,5 +79,5 @@ class NimBLERemoteCharacteristic : public NimBLERemoteValueAttribute {
|
||||
|
||||
}; // NimBLERemoteCharacteristic
|
||||
|
||||
#endif /* CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_CENTRAL) */
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|
||||
#endif /* NIMBLE_CPP_REMOTE_CHARACTERISTIC_H_ */
|
||||
|
||||
@@ -15,9 +15,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "NimBLERemoteDescriptor.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_CENTRAL)
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
|
||||
# include "NimBLERemoteDescriptor.h"
|
||||
# include "NimBLERemoteCharacteristic.h"
|
||||
|
||||
/**
|
||||
@@ -56,4 +57,4 @@ NimBLEClient* NimBLERemoteDescriptor::getClient() const {
|
||||
return m_pRemoteCharacteristic->getClient();
|
||||
}
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_CENTRAL)
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
#ifndef NIMBLE_CPP_REMOTE_DESCRIPTOR_H_
|
||||
#define NIMBLE_CPP_REMOTE_DESCRIPTOR_H_
|
||||
|
||||
#include "syscfg/syscfg.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_CENTRAL)
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
|
||||
# include "NimBLERemoteValueAttribute.h"
|
||||
|
||||
@@ -44,5 +44,5 @@ class NimBLERemoteDescriptor : public NimBLERemoteValueAttribute {
|
||||
const NimBLERemoteCharacteristic* m_pRemoteCharacteristic;
|
||||
};
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_CENTRAL)
|
||||
#endif // NIMBLE_CPP_REMOTE_DESCRIPTOR_H_
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|
||||
#endif /* NIMBLE_CPP_REMOTE_DESCRIPTOR_H_ */
|
||||
|
||||
@@ -15,9 +15,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "NimBLERemoteService.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_CENTRAL)
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
|
||||
# include "NimBLERemoteService.h"
|
||||
# include "NimBLERemoteCharacteristic.h"
|
||||
# include "NimBLEClient.h"
|
||||
# include "NimBLEAttValue.h"
|
||||
@@ -302,4 +303,4 @@ std::string NimBLERemoteService::toString() const {
|
||||
return res;
|
||||
} // toString
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_CENTRAL)
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
#ifndef NIMBLE_CPP_REMOTE_SERVICE_H_
|
||||
#define NIMBLE_CPP_REMOTE_SERVICE_H_
|
||||
|
||||
#include "syscfg/syscfg.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_CENTRAL)
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
|
||||
# include "NimBLEAttribute.h"
|
||||
# include <vector>
|
||||
@@ -64,5 +64,5 @@ class NimBLERemoteService : public NimBLEAttribute {
|
||||
uint16_t m_endHandle{0};
|
||||
}; // NimBLERemoteService
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_CENTRAL)
|
||||
#endif // NIMBLE_CPP_REMOTE_SERVICE_H_
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|
||||
#endif /* NIMBLE_CPP_REMOTE_SERVICE_H_*/
|
||||
|
||||
@@ -15,9 +15,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "NimBLERemoteValueAttribute.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_CENTRAL)
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
|
||||
# include "NimBLERemoteValueAttribute.h"
|
||||
# include "NimBLEClient.h"
|
||||
# include "NimBLEUtils.h"
|
||||
# include "NimBLELog.h"
|
||||
@@ -121,7 +122,7 @@ int NimBLERemoteValueAttribute::onWriteCB(uint16_t conn_handle, const ble_gatt_e
|
||||
* @param [in] timestamp A pointer to a time_t struct to store the time the value was read.
|
||||
* @return The value of the remote characteristic.
|
||||
*/
|
||||
NimBLEAttValue NimBLERemoteValueAttribute::readValue(time_t* timestamp) {
|
||||
NimBLEAttValue NimBLERemoteValueAttribute::readValue(time_t* timestamp) const {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> readValue()");
|
||||
|
||||
NimBLEAttValue value{};
|
||||
@@ -217,4 +218,4 @@ int NimBLERemoteValueAttribute::onReadCB(uint16_t conn_handle, const ble_gatt_er
|
||||
return rc;
|
||||
} // onReadCB
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_CENTRAL)
|
||||
#endif // CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
#ifndef NIMBLE_CPP_REMOTE_VALUE_ATTRIBUTE_H_
|
||||
#define NIMBLE_CPP_REMOTE_VALUE_ATTRIBUTE_H_
|
||||
|
||||
#include "syscfg/syscfg.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_CENTRAL)
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
|
||||
# if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
# include <host/ble_gatt.h>
|
||||
@@ -32,19 +32,32 @@
|
||||
# undef max
|
||||
/**************************/
|
||||
|
||||
# include "NimBLEValueAttribute.h"
|
||||
# include "NimBLEAttribute.h"
|
||||
# include "NimBLEAttValue.h"
|
||||
|
||||
class NimBLEClient;
|
||||
|
||||
class NimBLERemoteValueAttribute : public NimBLEValueAttribute, public NimBLEAttribute {
|
||||
class NimBLERemoteValueAttribute : public NimBLEAttribute {
|
||||
public:
|
||||
/**
|
||||
* @brief Read the value of the remote attribute.
|
||||
* @param [in] timestamp A pointer to a time_t struct to store the time the value was read.
|
||||
* @return The value of the remote attribute.
|
||||
*/
|
||||
NimBLEAttValue readValue(time_t* timestamp = nullptr);
|
||||
NimBLEAttValue readValue(time_t* timestamp = nullptr) const;
|
||||
|
||||
/**
|
||||
* @brief Get the length of the remote attribute value.
|
||||
* @return The length of the remote attribute value.
|
||||
*/
|
||||
size_t getLength() const { return m_value.size(); }
|
||||
|
||||
/**
|
||||
* @brief Get the value of the remote attribute.
|
||||
* @return The value of the remote attribute.
|
||||
* @details This returns a copy of the value to avoid potential race conditions.
|
||||
*/
|
||||
NimBLEAttValue getValue() const { return m_value; }
|
||||
|
||||
/**
|
||||
* Get the client instance that owns this attribute.
|
||||
@@ -109,34 +122,13 @@ class NimBLERemoteValueAttribute : public NimBLEValueAttribute, public NimBLEAtt
|
||||
* @brief Template to set the remote characteristic value to <type\>val.
|
||||
* @param [in] v The value to write.
|
||||
* @param [in] response True == request write response.
|
||||
* @details Only used if the <type\> has a `data()` and `size()` method with `value_type`.
|
||||
* Correctly calculates byte size for containers with multi-byte element types.
|
||||
* @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 && Has_value_type<T>::value, bool>::type
|
||||
# endif
|
||||
writeValue(const T& v, bool response = false) const {
|
||||
return writeValue(
|
||||
reinterpret_cast<const uint8_t*>(v.data()),
|
||||
v.size() * sizeof(typename T::value_type),
|
||||
response
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Template to set the remote characteristic value to <type\>val.
|
||||
* @param [in] v The value to write.
|
||||
* @param [in] response True == request write response.
|
||||
* @details Only used if the <type\> has a `data()` and `size()` method without `value_type`.
|
||||
*/
|
||||
template <typename T>
|
||||
# ifdef _DOXYGEN_
|
||||
bool
|
||||
# else
|
||||
typename std::enable_if<Has_data_size<T>::value && !Has_value_type<T>::value, bool>::type
|
||||
typename std::enable_if<Has_data_size<T>::value, bool>::type
|
||||
# endif
|
||||
writeValue(const T& v, bool response = false) const {
|
||||
return writeValue(reinterpret_cast<const uint8_t*>(v.data()), v.size(), response);
|
||||
@@ -152,11 +144,7 @@ class NimBLERemoteValueAttribute : public NimBLEValueAttribute, public NimBLEAtt
|
||||
template <typename T>
|
||||
typename std::enable_if<!std::is_pointer<T>::value, bool>::type writeValue(const T& v, bool response = false) const {
|
||||
if constexpr (Has_data_size<T>::value) {
|
||||
if constexpr (Has_value_type<T>::value) {
|
||||
return writeValue(reinterpret_cast<const uint8_t*>(v.data()), v.size() * sizeof(typename T::value_type), response);
|
||||
} else {
|
||||
return writeValue(reinterpret_cast<const uint8_t*>(v.data()), v.size(), response);
|
||||
}
|
||||
return writeValue(reinterpret_cast<const uint8_t*>(v.data()), v.size(), response);
|
||||
} else if constexpr (Has_c_str_length<T>::value) {
|
||||
return writeValue(reinterpret_cast<const uint8_t*>(v.c_str()), v.length(), response);
|
||||
} else {
|
||||
@@ -165,6 +153,20 @@ class NimBLERemoteValueAttribute : public NimBLEValueAttribute, public NimBLEAtt
|
||||
}
|
||||
# endif
|
||||
|
||||
/**
|
||||
* @brief Template to convert the remote characteristic data to <type\>.
|
||||
* @tparam T The type to convert the data to.
|
||||
* @param [in] timestamp A pointer to a time_t struct to store the time the value was read.
|
||||
* @param [in] skipSizeCheck If true it will skip checking if the data size is less than <tt>sizeof(<type\>)</tt>.
|
||||
* @return The data converted to <type\> or NULL if skipSizeCheck is false and the data is
|
||||
* less than <tt>sizeof(<type\>)</tt>.
|
||||
* @details <b>Use:</b> <tt>getValue<type>(×tamp, skipSizeCheck);</tt>
|
||||
*/
|
||||
template <typename T>
|
||||
T getValue(time_t* timestamp = nullptr, bool skipSizeCheck = false) const {
|
||||
return m_value.getValue<T>(timestamp, skipSizeCheck);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Template to convert the remote characteristic data to <type\>.
|
||||
* @tparam T The type to convert the data to.
|
||||
@@ -175,16 +177,16 @@ class NimBLERemoteValueAttribute : public NimBLEValueAttribute, public NimBLEAtt
|
||||
* @details <b>Use:</b> <tt>readValue<type>(×tamp, skipSizeCheck);</tt>
|
||||
*/
|
||||
template <typename T>
|
||||
T readValue(time_t* timestamp = nullptr, bool skipSizeCheck = false) {
|
||||
T readValue(time_t* timestamp = nullptr, bool skipSizeCheck = false) const {
|
||||
readValue();
|
||||
return getValue<T>(timestamp, skipSizeCheck);
|
||||
return m_value.getValue<T>(timestamp, skipSizeCheck);
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Construct a new NimBLERemoteValueAttribute object.
|
||||
*/
|
||||
NimBLERemoteValueAttribute(const ble_uuid_any_t& uuid, uint16_t handle) : NimBLEAttribute{uuid, handle} {}
|
||||
NimBLERemoteValueAttribute(const ble_uuid_any_t& uuid, uint16_t handle) : NimBLEAttribute(uuid, handle) {}
|
||||
|
||||
/**
|
||||
* @brief Destroy the NimBLERemoteValueAttribute object.
|
||||
@@ -193,7 +195,9 @@ class NimBLERemoteValueAttribute : public NimBLEValueAttribute, public NimBLEAtt
|
||||
|
||||
static int onReadCB(uint16_t conn_handle, const ble_gatt_error* error, ble_gatt_attr* attr, void* arg);
|
||||
static int onWriteCB(uint16_t conn_handle, const ble_gatt_error* error, ble_gatt_attr* attr, void* arg);
|
||||
|
||||
mutable NimBLEAttValue m_value{};
|
||||
};
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_CENTRAL)
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|
||||
#endif // NIMBLE_CPP_REMOTE_VALUE_ATTRIBUTE_H_
|
||||
|
||||
@@ -15,9 +15,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "NimBLEScan.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_OBSERVER)
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||
|
||||
# include "NimBLEScan.h"
|
||||
# include "NimBLEDevice.h"
|
||||
# include "NimBLELog.h"
|
||||
|
||||
@@ -32,30 +33,16 @@ static NimBLEScanCallbacks defaultScanCallbacks;
|
||||
*/
|
||||
NimBLEScan::NimBLEScan()
|
||||
: m_pScanCallbacks{&defaultScanCallbacks},
|
||||
m_scanParams{
|
||||
.itvl = 0, // default interval
|
||||
.window = 0, // default window
|
||||
.filter_policy = BLE_HCI_SCAN_FILT_NO_WL, // no whitelist scan filter
|
||||
.limited = 0, // no limited scan
|
||||
.passive = 1, // no scan response
|
||||
.filter_duplicates = 1, // filter duplicates
|
||||
# if defined(ESP_PLATFORM) && !defined(CONFIG_USING_NIMBLE_COMPONENT)
|
||||
# if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 4, 2)
|
||||
.disable_observer_mode = 0, // observer role enabled
|
||||
# endif
|
||||
# endif
|
||||
},
|
||||
// default interval + window, no whitelist scan filter,not limited scan, no scan response, filter_duplicates
|
||||
m_scanParams{0, 0, BLE_HCI_SCAN_FILT_NO_WL, 0, 1, 1},
|
||||
m_pTaskData{nullptr},
|
||||
m_maxResults{0xFF} {
|
||||
}
|
||||
m_maxResults{0xFF} {}
|
||||
|
||||
/**
|
||||
* @brief Scan destructor, release any allocated resources.
|
||||
*/
|
||||
NimBLEScan::~NimBLEScan() {
|
||||
for (const auto& dev : m_scanResults.m_deviceVec) {
|
||||
delete dev;
|
||||
}
|
||||
clearResults();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -70,12 +57,7 @@ int NimBLEScan::handleGapEvent(ble_gap_event* event, void* arg) {
|
||||
switch (event->type) {
|
||||
case BLE_GAP_EVENT_EXT_DISC:
|
||||
case BLE_GAP_EVENT_DISC: {
|
||||
if (!pScan->isScanning()) {
|
||||
NIMBLE_LOGI(LOG_TAG, "Scan stopped, ignoring event");
|
||||
return 0;
|
||||
}
|
||||
|
||||
# if MYNEWT_VAL(BLE_EXT_ADV)
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
const auto& disc = event->ext_disc;
|
||||
const bool isLegacyAdv = disc.props & BLE_HCI_ADV_LEGACY_MASK;
|
||||
const auto event_type = isLegacyAdv ? disc.legacy_event_type : disc.props;
|
||||
@@ -86,7 +68,7 @@ int NimBLEScan::handleGapEvent(ble_gap_event* event, void* arg) {
|
||||
# endif
|
||||
NimBLEAddress advertisedAddress(disc.addr);
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_CENTRAL)
|
||||
# ifdef CONFIG_BT_NIMBLE_ROLE_CENTRAL
|
||||
// stop processing if already connected
|
||||
NimBLEClient* pClient = NimBLEDevice::getClientByPeerAddress(advertisedAddress);
|
||||
if (pClient != nullptr && pClient->isConnected()) {
|
||||
@@ -98,7 +80,7 @@ int NimBLEScan::handleGapEvent(ble_gap_event* event, void* arg) {
|
||||
|
||||
// If we've seen this device before get a pointer to it from the vector
|
||||
for (const auto& dev : pScan->m_scanResults.m_deviceVec) {
|
||||
# if MYNEWT_VAL(BLE_EXT_ADV)
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
// Same address but different set ID should create a new advertised device.
|
||||
if (dev->getAddress() == advertisedAddress && dev->getSetId() == disc.sid)
|
||||
# else
|
||||
@@ -129,22 +111,13 @@ int NimBLEScan::handleGapEvent(ble_gap_event* event, void* arg) {
|
||||
NIMBLE_LOGI(LOG_TAG, "New advertiser: %s", advertisedAddress.toString().c_str());
|
||||
} else {
|
||||
advertisedDevice->update(event, event_type);
|
||||
if (isLegacyAdv) {
|
||||
if (event_type == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP) {
|
||||
NIMBLE_LOGI(LOG_TAG, "Scan response from: %s", advertisedAddress.toString().c_str());
|
||||
} else {
|
||||
NIMBLE_LOGI(LOG_TAG, "Duplicate; updated: %s", advertisedAddress.toString().c_str());
|
||||
}
|
||||
if (isLegacyAdv && event_type == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP) {
|
||||
NIMBLE_LOGI(LOG_TAG, "Scan response from: %s", advertisedAddress.toString().c_str());
|
||||
} else {
|
||||
NIMBLE_LOGI(LOG_TAG, "Duplicate; updated: %s", advertisedAddress.toString().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
# if MYNEWT_VAL(BLE_EXT_ADV)
|
||||
if (advertisedDevice->getDataStatus() == BLE_GAP_EXT_ADV_DATA_STATUS_INCOMPLETE) {
|
||||
NIMBLE_LOGD(LOG_TAG, "EXT ADV data incomplete, waiting for more");
|
||||
return 0;
|
||||
}
|
||||
# endif
|
||||
|
||||
if (!advertisedDevice->m_callbackSent) {
|
||||
advertisedDevice->m_callbackSent++;
|
||||
pScan->m_pScanCallbacks->onDiscovered(advertisedDevice);
|
||||
@@ -293,7 +266,7 @@ bool NimBLEScan::isScanning() {
|
||||
return ble_gap_disc_active();
|
||||
}
|
||||
|
||||
# if MYNEWT_VAL(BLE_EXT_ADV)
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
/**
|
||||
* @brief Set the PHYs to scan.
|
||||
* @param [in] phyMask The PHYs to scan, a bit mask of:
|
||||
@@ -345,7 +318,7 @@ bool NimBLEScan::start(uint32_t duration, bool isContinue, bool restart) {
|
||||
|
||||
// If scanning is already active, call the functions anyway as the parameters can be changed.
|
||||
|
||||
# if MYNEWT_VAL(BLE_EXT_ADV)
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
ble_gap_ext_disc_params scan_params;
|
||||
scan_params.passive = m_scanParams.passive;
|
||||
scan_params.itvl = m_scanParams.itvl;
|
||||
@@ -510,11 +483,11 @@ void NimBLEScan::clearResults() {
|
||||
* @brief Dump the scan results to the log.
|
||||
*/
|
||||
void NimBLEScanResults::dump() const {
|
||||
# if MYNEWT_VAL(NIMBLE_CPP_LOG_LEVEL) >= 3
|
||||
#if CONFIG_NIMBLE_CPP_LOG_LEVEL >=3
|
||||
for (const auto& dev : m_deviceVec) {
|
||||
NIMBLE_LOGI(LOG_TAG, "- %s", dev->toString().c_str());
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
} // dump
|
||||
|
||||
/**
|
||||
@@ -581,4 +554,4 @@ void NimBLEScanCallbacks::onScanEnd(const NimBLEScanResults& results, int reason
|
||||
NIMBLE_LOGD(CB_TAG, "Scan ended; reason %d, num results: %d", reason, results.getCount());
|
||||
}
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_OBSERVER)
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_OBSERVER */
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
#ifndef NIMBLE_CPP_SCAN_H_
|
||||
#define NIMBLE_CPP_SCAN_H_
|
||||
|
||||
#include "syscfg/syscfg.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_OBSERVER)
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||
|
||||
# include "NimBLEAdvertisedDevice.h"
|
||||
# include "NimBLEUtils.h"
|
||||
@@ -83,7 +83,7 @@ class NimBLEScan {
|
||||
void erase(const NimBLEAddress& address);
|
||||
void erase(const NimBLEAdvertisedDevice* device);
|
||||
|
||||
# if MYNEWT_VAL(BLE_EXT_ADV)
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
enum Phy { SCAN_1M = 0x01, SCAN_CODED = 0x02, SCAN_ALL = 0x03 };
|
||||
void setPhy(Phy phyMask);
|
||||
void setPeriod(uint32_t periodMs);
|
||||
@@ -103,7 +103,7 @@ class NimBLEScan {
|
||||
NimBLETaskData* m_pTaskData;
|
||||
uint8_t m_maxResults;
|
||||
|
||||
# if MYNEWT_VAL(BLE_EXT_ADV)
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
uint8_t m_phy{SCAN_ALL};
|
||||
uint16_t m_period{0};
|
||||
# endif
|
||||
@@ -136,5 +136,5 @@ class NimBLEScanCallbacks {
|
||||
virtual void onScanEnd(const NimBLEScanResults& scanResults, int reason);
|
||||
};
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_ENABLED MYNEWT_VAL(BLE_ROLE_OBSERVER)
|
||||
#endif // CONFIG_BT_ENABLED CONFIG_BT_NIMBLE_ROLE_OBSERVER
|
||||
#endif // NIMBLE_CPP_SCAN_H_
|
||||
|
||||
@@ -15,13 +15,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "NimBLEServer.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
|
||||
# include "NimBLEServer.h"
|
||||
# include "NimBLEDevice.h"
|
||||
# include "NimBLELog.h"
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_CENTRAL)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
# include "NimBLEClient.h"
|
||||
# endif
|
||||
|
||||
@@ -39,11 +40,6 @@
|
||||
static const char* LOG_TAG = "NimBLEServer";
|
||||
static NimBLEServerCallbacks defaultCallbacks;
|
||||
|
||||
struct gattRegisterCallbackArgs {
|
||||
NimBLEService* pSvc{nullptr};
|
||||
NimBLECharacteristic* pChar{nullptr};
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Construct a BLE Server
|
||||
*
|
||||
@@ -54,7 +50,7 @@ NimBLEServer::NimBLEServer()
|
||||
: m_gattsStarted{false},
|
||||
m_svcChanged{false},
|
||||
m_deleteCallbacks{false},
|
||||
# if !MYNEWT_VAL(BLE_EXT_ADV)
|
||||
# if !CONFIG_BT_NIMBLE_EXT_ADV
|
||||
m_advertiseOnDisconnect{false},
|
||||
# endif
|
||||
m_pServerCallbacks{&defaultCallbacks},
|
||||
@@ -74,7 +70,7 @@ NimBLEServer::~NimBLEServer() {
|
||||
delete m_pServerCallbacks;
|
||||
}
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_CENTRAL)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
if (m_pClient != nullptr) {
|
||||
delete m_pClient;
|
||||
}
|
||||
@@ -148,32 +144,17 @@ NimBLEService* NimBLEServer::getServiceByHandle(uint16_t handle) const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a BLE Characteristic by its handle
|
||||
* @param handle The handle of the characteristic.
|
||||
* @return A pointer to the characteristic object or nullptr if not found.
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEServer::getCharacteristicByHandle(uint16_t handle) const {
|
||||
for (const auto& svc : m_svcVec) {
|
||||
NimBLECharacteristic* pChr = svc->getCharacteristicByHandle(handle);
|
||||
if (pChr != nullptr) {
|
||||
return pChr;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
} // getCharacteristicByHandle
|
||||
|
||||
# if MYNEWT_VAL(BLE_EXT_ADV)
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
/**
|
||||
* @brief Retrieve the advertising object that can be used to advertise the existence of the server.
|
||||
* @return A pointer to an advertising object.
|
||||
* @return A pinter to an advertising object.
|
||||
*/
|
||||
NimBLEExtAdvertising* NimBLEServer::getAdvertising() const {
|
||||
return NimBLEDevice::getAdvertising();
|
||||
} // getAdvertising
|
||||
# endif
|
||||
|
||||
# if (!MYNEWT_VAL(BLE_EXT_ADV) && MYNEWT_VAL(BLE_ROLE_BROADCASTER)) || defined(_DOXYGEN_)
|
||||
# if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_)
|
||||
/**
|
||||
* @brief Retrieve the advertising object that can be used to advertise the existence of the server.
|
||||
* @return A pointer to an advertising object.
|
||||
@@ -193,122 +174,47 @@ void NimBLEServer::serviceChanged() {
|
||||
}
|
||||
} // serviceChanged
|
||||
|
||||
/**
|
||||
* @brief Callback for GATT registration events,
|
||||
* used to obtain the assigned handles for services, characteristics, and descriptors.
|
||||
* @param [in] ctxt The context of the registration event.
|
||||
* @param [in] arg A pointer to the gattRegisterCallbackArgs struct used to track the
|
||||
* service and characteristic being registered.
|
||||
*/
|
||||
void NimBLEServer::gattRegisterCallback(ble_gatt_register_ctxt* ctxt, void* arg) {
|
||||
gattRegisterCallbackArgs* args = static_cast<gattRegisterCallbackArgs*>(arg);
|
||||
|
||||
if (ctxt->op == BLE_GATT_REGISTER_OP_SVC) {
|
||||
NimBLEUUID uuid(ctxt->svc.svc_def->uuid);
|
||||
args->pSvc = nullptr;
|
||||
for (auto pSvc : NimBLEDevice::getServer()->m_svcVec) {
|
||||
if (!pSvc->getRemoved() && pSvc->m_handle == 0 && pSvc->getUUID() == uuid) {
|
||||
pSvc->m_handle = ctxt->svc.handle;
|
||||
NIMBLE_LOGD(LOG_TAG, "Service registered: %s, handle=%d", uuid.toString().c_str(), ctxt->svc.handle);
|
||||
// Set the arg to the service so we know that the following
|
||||
// characteristics and descriptors belong to this service
|
||||
args->pSvc = pSvc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (args->pSvc == nullptr) {
|
||||
// If the service is not found then this is likely a characteristic or descriptor that was registered as
|
||||
// part of the GATT server setup and not found in the service vector
|
||||
NIMBLE_LOGD(LOG_TAG, "Skipping characteristic or descriptor registered with unknown service");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctxt->op == BLE_GATT_REGISTER_OP_CHR) {
|
||||
NimBLEUUID uuid(ctxt->chr.chr_def->uuid);
|
||||
args->pChar = nullptr;
|
||||
for (auto pChr : args->pSvc->m_vChars) {
|
||||
if (!pChr->getRemoved() && pChr->m_handle == 0 && pChr->getUUID() == uuid) {
|
||||
pChr->m_handle = ctxt->chr.val_handle;
|
||||
// Set the arg to the characteristic so we know that the following descriptors belong to this characteristic
|
||||
args->pChar = pChr;
|
||||
NIMBLE_LOGD(LOG_TAG,
|
||||
"Characteristic registered: %s, def_handle=%d, val_handle=%d",
|
||||
uuid.toString().c_str(),
|
||||
ctxt->chr.def_handle,
|
||||
ctxt->chr.val_handle);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctxt->op == BLE_GATT_REGISTER_OP_DSC) {
|
||||
if (args->pChar == nullptr) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Descriptor registered with unknown characteristic, skipping");
|
||||
return;
|
||||
}
|
||||
|
||||
NimBLEUUID uuid(ctxt->dsc.dsc_def->uuid);
|
||||
for (auto pDsc : args->pChar->m_vDescriptors) {
|
||||
if (!pDsc->getRemoved() && pDsc->m_handle == 0 && pDsc->getUUID() == uuid) {
|
||||
pDsc->m_handle = ctxt->dsc.handle;
|
||||
NIMBLE_LOGD(LOG_TAG, "Descriptor registered: %s, handle=%d", uuid.toString().c_str(), ctxt->dsc.handle);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start the GATT server.
|
||||
* @details Required to be called after setup of all services and characteristics / descriptors
|
||||
* for the NimBLE host to register them.
|
||||
*/
|
||||
bool NimBLEServer::start() {
|
||||
if (m_svcChanged && !getConnectedCount()) {
|
||||
NIMBLE_LOGD(LOG_TAG, "Services have changed since last start, resetting GATT server");
|
||||
m_gattsStarted = false;
|
||||
}
|
||||
|
||||
void NimBLEServer::start() {
|
||||
if (m_gattsStarted) {
|
||||
return true; // already started
|
||||
return; // already started
|
||||
}
|
||||
|
||||
if (!resetGATT()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ble_hs_cfg.gatts_register_cb = NimBLEServer::gattRegisterCallback;
|
||||
gattRegisterCallbackArgs args{};
|
||||
ble_hs_cfg.gatts_register_arg = &args;
|
||||
|
||||
int rc = ble_gatts_start();
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "ble_gatts_start; rc=%d, %s", rc, NimBLEUtils::returnCodeToString(rc));
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
# if MYNEWT_VAL(NIMBLE_CPP_LOG_LEVEL) >= 4
|
||||
# if CONFIG_NIMBLE_CPP_LOG_LEVEL >= 4
|
||||
ble_gatts_show_local();
|
||||
# endif
|
||||
|
||||
// Check that all services were registered and log if any are missing.
|
||||
// Get the assigned service handles and build a vector of characteristics
|
||||
// with Notify / Indicate capabilities for event handling
|
||||
for (const auto& svc : m_svcVec) {
|
||||
if (svc->getRemoved() == 0) {
|
||||
rc = ble_gatts_find_svc(svc->getUUID().getBase(), NULL);
|
||||
rc = ble_gatts_find_svc(svc->getUUID().getBase(), &svc->m_handle);
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGD(LOG_TAG,
|
||||
NIMBLE_LOGW(LOG_TAG,
|
||||
"GATT Server started without service: %s, Service %s",
|
||||
svc->getUUID().toString().c_str(),
|
||||
svc->isStarted() ? "missing" : "not started");
|
||||
continue; // Skip this service as it was not started
|
||||
}
|
||||
}
|
||||
|
||||
// Set the descriptor handles now as the stack does not set these when the service is started
|
||||
for (const auto& chr : svc->m_vChars) {
|
||||
for (auto& desc : chr->m_vDescriptors) {
|
||||
ble_gatts_find_dsc(svc->getUUID().getBase(), chr->getUUID().getBase(), desc->getUUID().getBase(), &desc->m_handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
# endif
|
||||
|
||||
// If the services have changed indicate it now
|
||||
if (m_svcChanged) {
|
||||
@@ -317,7 +223,6 @@ bool NimBLEServer::start() {
|
||||
}
|
||||
|
||||
m_gattsStarted = true;
|
||||
return true;
|
||||
} // start
|
||||
|
||||
/**
|
||||
@@ -340,13 +245,13 @@ bool NimBLEServer::disconnect(uint16_t connHandle, uint8_t reason) const {
|
||||
* @brief Disconnect the specified client with optional reason.
|
||||
* @param [in] connInfo Connection of the client to disconnect.
|
||||
* @param [in] reason code for disconnecting.
|
||||
* @return True if successful.
|
||||
* @return NimBLE host return code.
|
||||
*/
|
||||
bool NimBLEServer::disconnect(const NimBLEConnInfo& connInfo, uint8_t reason) const {
|
||||
return disconnect(connInfo.getConnHandle(), reason);
|
||||
} // disconnect
|
||||
|
||||
# if !MYNEWT_VAL(BLE_EXT_ADV) || defined(_DOXYGEN_)
|
||||
# if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_)
|
||||
/**
|
||||
* @brief Set the server to automatically start advertising when a client disconnects.
|
||||
* @param [in] enable true == advertise, false == don't advertise.
|
||||
@@ -401,7 +306,7 @@ NimBLEConnInfo NimBLEServer::getPeerInfo(uint8_t index) const {
|
||||
for (const auto& peer : m_connectedPeers) {
|
||||
if (peer != BLE_HS_CONN_HANDLE_NONE) {
|
||||
if (count == index) {
|
||||
return getPeerInfoByHandle(peer);
|
||||
return getPeerInfoByHandle(m_connectedPeers[count]);
|
||||
}
|
||||
count++;
|
||||
}
|
||||
@@ -450,14 +355,9 @@ int NimBLEServer::handleGapEvent(ble_gap_event* event, void* arg) {
|
||||
|
||||
switch (event->type) {
|
||||
case BLE_GAP_EVENT_CONNECT: {
|
||||
rc = event->connect.status;
|
||||
if (rc == BLE_ERR_UNSUPP_REM_FEATURE) {
|
||||
rc = 0; // Workaround: Ignore unsupported remote feature error as it is not a real error.
|
||||
}
|
||||
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Connection failed rc = %d %s", rc, NimBLEUtils::returnCodeToString(rc));
|
||||
# if !MYNEWT_VAL(BLE_EXT_ADV) && MYNEWT_VAL(BLE_ROLE_BROADCASTER)
|
||||
if (event->connect.status != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Connection failed");
|
||||
# if !CONFIG_BT_NIMBLE_EXT_ADV
|
||||
NimBLEDevice::startAdvertising();
|
||||
# endif
|
||||
} else {
|
||||
@@ -501,16 +401,20 @@ int NimBLEServer::handleGapEvent(ble_gap_event* event, void* arg) {
|
||||
}
|
||||
}
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_CENTRAL)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
if (pServer->m_pClient && pServer->m_pClient->m_connHandle == event->disconnect.conn.conn_handle) {
|
||||
// If this was also the client make sure it's flagged as disconnected.
|
||||
pServer->m_pClient->m_connHandle = BLE_HS_CONN_HANDLE_NONE;
|
||||
}
|
||||
# endif
|
||||
|
||||
if (pServer->m_svcChanged) {
|
||||
pServer->resetGATT();
|
||||
}
|
||||
|
||||
peerInfo.m_desc = event->disconnect.conn;
|
||||
pServer->m_pServerCallbacks->onDisconnect(pServer, peerInfo, event->disconnect.reason);
|
||||
# if !MYNEWT_VAL(BLE_EXT_ADV) && MYNEWT_VAL(BLE_ROLE_BROADCASTER)
|
||||
# if !CONFIG_BT_NIMBLE_EXT_ADV
|
||||
if (pServer->m_advertiseOnDisconnect) {
|
||||
pServer->startAdvertising();
|
||||
}
|
||||
@@ -519,21 +423,33 @@ int NimBLEServer::handleGapEvent(ble_gap_event* event, void* arg) {
|
||||
} // BLE_GAP_EVENT_DISCONNECT
|
||||
|
||||
case BLE_GAP_EVENT_SUBSCRIBE: {
|
||||
rc = ble_gap_conn_find(event->subscribe.conn_handle, &peerInfo.m_desc);
|
||||
if (rc != 0) {
|
||||
break;
|
||||
NIMBLE_LOGI(LOG_TAG,
|
||||
"subscribe event; attr_handle=%d, subscribed: %s",
|
||||
event->subscribe.attr_handle,
|
||||
((event->subscribe.cur_notify || event->subscribe.cur_indicate) ? "true" : "false"));
|
||||
|
||||
for (const auto& svc : pServer->m_svcVec) {
|
||||
for (const auto& chr : svc->m_vChars) {
|
||||
if (chr->getHandle() == event->subscribe.attr_handle) {
|
||||
rc = ble_gap_conn_find(event->subscribe.conn_handle, &peerInfo.m_desc);
|
||||
if (rc != 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
auto chrProps = chr->getProperties();
|
||||
if (!peerInfo.isEncrypted() &&
|
||||
(chrProps & BLE_GATT_CHR_F_READ_AUTHEN || chrProps & BLE_GATT_CHR_F_READ_AUTHOR ||
|
||||
chrProps & BLE_GATT_CHR_F_READ_ENC)) {
|
||||
NimBLEDevice::startSecurity(event->subscribe.conn_handle);
|
||||
}
|
||||
|
||||
chr->m_pCallbacks->onSubscribe(chr,
|
||||
peerInfo,
|
||||
event->subscribe.cur_notify + event->subscribe.cur_indicate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t subVal = event->subscribe.cur_notify + (event->subscribe.cur_indicate << 1);
|
||||
NIMBLE_LOGI(LOG_TAG, "subscribe event; attr_handle=%d, subscribed: %d", event->subscribe.attr_handle, subVal);
|
||||
|
||||
auto pChar = pServer->getCharacteristicByHandle(event->subscribe.attr_handle);
|
||||
if (!pChar) {
|
||||
NIMBLE_LOGE(LOG_TAG, "subscribe event; attr_handle=%d, not found", event->subscribe.attr_handle);
|
||||
break;
|
||||
}
|
||||
|
||||
pChar->processSubRequest(peerInfo, subVal);
|
||||
break;
|
||||
} // BLE_GAP_EVENT_SUBSCRIBE
|
||||
|
||||
@@ -547,14 +463,18 @@ int NimBLEServer::handleGapEvent(ble_gap_event* event, void* arg) {
|
||||
} // BLE_GAP_EVENT_MTU
|
||||
|
||||
case BLE_GAP_EVENT_NOTIFY_TX: {
|
||||
rc = ble_gap_conn_find(event->notify_tx.conn_handle, &peerInfo.m_desc);
|
||||
if (rc != 0) {
|
||||
break;
|
||||
NimBLECharacteristic* pChar = nullptr;
|
||||
|
||||
for (const auto& svc : pServer->m_svcVec) {
|
||||
for (auto& chr : svc->m_vChars) {
|
||||
if (chr->getHandle() == event->notify_tx.attr_handle) {
|
||||
pChar = chr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto pChar = pServer->getCharacteristicByHandle(event->notify_tx.attr_handle);
|
||||
if (pChar == nullptr) {
|
||||
break;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (event->notify_tx.indication) {
|
||||
@@ -564,24 +484,14 @@ int NimBLEServer::handleGapEvent(ble_gap_event* event, void* arg) {
|
||||
}
|
||||
|
||||
pChar->m_pCallbacks->onStatus(pChar, event->notify_tx.status);
|
||||
pChar->m_pCallbacks->onStatus(pChar, peerInfo, event->notify_tx.status);
|
||||
break;
|
||||
} // BLE_GAP_EVENT_NOTIFY_TX
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_CENTRAL)
|
||||
case BLE_GAP_EVENT_NOTIFY_RX: {
|
||||
if (pServer->m_pClient && pServer->m_pClient->m_connHandle == event->notify_rx.conn_handle) {
|
||||
NimBLEClient::handleGapEvent(event, pServer->m_pClient);
|
||||
}
|
||||
break;
|
||||
} // BLE_GAP_EVENT_NOTIFY_RX
|
||||
# endif
|
||||
|
||||
case BLE_GAP_EVENT_ADV_COMPLETE: {
|
||||
# if MYNEWT_VAL(BLE_EXT_ADV) && MYNEWT_VAL(BLE_ROLE_BROADCASTER)
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
case BLE_GAP_EVENT_SCAN_REQ_RCVD:
|
||||
return NimBLEExtAdvertising::handleGapEvent(event, arg);
|
||||
# elif MYNEWT_VAL(BLE_ROLE_BROADCASTER)
|
||||
# else
|
||||
return NimBLEAdvertising::handleGapEvent(event, arg);
|
||||
# endif
|
||||
} // BLE_GAP_EVENT_ADV_COMPLETE | BLE_GAP_EVENT_SCAN_REQ_RCVD
|
||||
@@ -621,18 +531,6 @@ int NimBLEServer::handleGapEvent(ble_gap_event* event, void* arg) {
|
||||
}
|
||||
|
||||
pServer->m_pServerCallbacks->onAuthenticationComplete(peerInfo);
|
||||
# if MYNEWT_VAL(BLE_ROLE_CENTRAL)
|
||||
if (pServer->m_pClient && pServer->m_pClient->m_connHandle == event->enc_change.conn_handle) {
|
||||
NimBLEClient::handleGapEvent(event, pServer->m_pClient);
|
||||
}
|
||||
# endif
|
||||
// update the secured status of the peer in each characteristic's subscribed peers list
|
||||
for (const auto& svc : pServer->m_svcVec) {
|
||||
for (const auto& chr : svc->m_vChars) {
|
||||
chr->updatePeerStatus(peerInfo);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
} // BLE_GAP_EVENT_ENC_CHANGE
|
||||
|
||||
@@ -646,6 +544,7 @@ int NimBLEServer::handleGapEvent(ble_gap_event* event, void* arg) {
|
||||
break;
|
||||
} // BLE_GAP_EVENT_IDENTITY_RESOLVED
|
||||
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
case BLE_GAP_EVENT_PHY_UPDATE_COMPLETE: {
|
||||
rc = ble_gap_conn_find(event->phy_updated.conn_handle, &peerInfo.m_desc);
|
||||
if (rc != 0) {
|
||||
@@ -655,6 +554,7 @@ int NimBLEServer::handleGapEvent(ble_gap_event* event, void* arg) {
|
||||
pServer->m_pServerCallbacks->onPhyUpdate(peerInfo, event->phy_updated.tx_phy, event->phy_updated.rx_phy);
|
||||
return 0;
|
||||
} // BLE_GAP_EVENT_PHY_UPDATE_COMPLETE
|
||||
# endif
|
||||
|
||||
case BLE_GAP_EVENT_PASSKEY_ACTION: {
|
||||
struct ble_sm_io pkey = {0, 0};
|
||||
@@ -689,15 +589,6 @@ int NimBLEServer::handleGapEvent(ble_gap_event* event, void* arg) {
|
||||
// }
|
||||
// rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
|
||||
// NIMBLE_LOGD(LOG_TAG, "BLE_SM_IOACT_OOB; ble_sm_inject_io result: %d", rc);
|
||||
} else if (event->passkey.params.action == BLE_SM_IOACT_INPUT) {
|
||||
NIMBLE_LOGD(LOG_TAG, "Enter the passkey");
|
||||
|
||||
rc = ble_gap_conn_find(event->passkey.conn_handle, &peerInfo.m_desc);
|
||||
if (rc != 0) {
|
||||
return BLE_ATT_ERR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
pServer->m_pServerCallbacks->onPassKeyEntry(peerInfo);
|
||||
} else if (event->passkey.params.action == BLE_SM_IOACT_NONE) {
|
||||
NIMBLE_LOGD(LOG_TAG, "No passkey action required");
|
||||
}
|
||||
@@ -729,10 +620,13 @@ int NimBLEServer::handleGattEvent(uint16_t connHandle, uint16_t attrHandle, ble_
|
||||
switch (ctxt->op) {
|
||||
case BLE_GATT_ACCESS_OP_READ_DSC:
|
||||
case BLE_GATT_ACCESS_OP_READ_CHR: {
|
||||
// Don't call readEvent if the buffer len is 0 (this is a follow up to a previous read),
|
||||
// or if this is an internal read (handle is NONE)
|
||||
if (ctxt->om->om_len > 0 && connHandle != BLE_HS_CONN_HANDLE_NONE) {
|
||||
pAtt->readEvent(peerInfo);
|
||||
// Don't call readEvent if this is an internal read (handle is NONE)
|
||||
if (connHandle != BLE_HS_CONN_HANDLE_NONE) {
|
||||
// If the packet header is only 8 bytes then 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 || val.size() <= (ble_att_mtu(connHandle) - 3)) {
|
||||
pAtt->readEvent(peerInfo);
|
||||
}
|
||||
}
|
||||
|
||||
ble_npl_hw_enter_critical();
|
||||
@@ -744,12 +638,12 @@ int NimBLEServer::handleGattEvent(uint16_t connHandle, uint16_t attrHandle, ble_
|
||||
case BLE_GATT_ACCESS_OP_WRITE_DSC:
|
||||
case BLE_GATT_ACCESS_OP_WRITE_CHR: {
|
||||
uint16_t maxLen = val.max_size();
|
||||
uint16_t len = ctxt->om->om_len;
|
||||
if (len > maxLen) {
|
||||
if (ctxt->om->om_len > maxLen) {
|
||||
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||
}
|
||||
|
||||
uint8_t buf[maxLen];
|
||||
uint8_t buf[maxLen];
|
||||
uint16_t len = ctxt->om->om_len;
|
||||
memcpy(buf, ctxt->om->om_data, len);
|
||||
|
||||
os_mbuf* next;
|
||||
@@ -837,7 +731,7 @@ void NimBLEServer::removeService(NimBLEService* service, bool deleteSvc) {
|
||||
|
||||
service->setRemoved(deleteSvc ? NIMBLE_ATT_REMOVE_DELETE : NIMBLE_ATT_REMOVE_HIDE);
|
||||
serviceChanged();
|
||||
# if !MYNEWT_VAL(BLE_EXT_ADV) && MYNEWT_VAL(BLE_ROLE_BROADCASTER)
|
||||
# if !CONFIG_BT_NIMBLE_EXT_ADV
|
||||
NimBLEDevice::getAdvertising()->removeServiceUUID(service->getUUID());
|
||||
# endif
|
||||
} // removeService
|
||||
@@ -868,67 +762,58 @@ void NimBLEServer::addService(NimBLEService* service) {
|
||||
|
||||
/**
|
||||
* @brief Resets the GATT server, used when services are added/removed after initialization.
|
||||
* @return True if successful.
|
||||
* @details This will reset the GATT server and re-register all services, characteristics, and
|
||||
* descriptors that have not been removed. Services, characteristics, and descriptors that have been
|
||||
* removed but not deleted will be skipped and have their handles cleared, and those that have been
|
||||
* deleted will be removed from the server's service vector.
|
||||
*/
|
||||
bool NimBLEServer::resetGATT() {
|
||||
# if MYNEWT_VAL(BLE_ROLE_BROADCASTER)
|
||||
NimBLEDevice::stopAdvertising();
|
||||
# endif
|
||||
void NimBLEServer::resetGATT() {
|
||||
if (getConnectedCount() > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
NimBLEDevice::stopAdvertising();
|
||||
ble_gatts_reset();
|
||||
ble_svc_gap_init();
|
||||
ble_svc_gatt_init();
|
||||
|
||||
for (auto svcIt = m_svcVec.begin(); svcIt != m_svcVec.end();) {
|
||||
auto* pSvc = *svcIt;
|
||||
if (pSvc->getRemoved() == NIMBLE_ATT_REMOVE_DELETE) {
|
||||
delete pSvc;
|
||||
svcIt = m_svcVec.erase(svcIt);
|
||||
for (auto it = m_svcVec.begin(); it != m_svcVec.end();) {
|
||||
if ((*it)->getRemoved() > 0) {
|
||||
if ((*it)->getRemoved() == NIMBLE_ATT_REMOVE_DELETE) {
|
||||
delete *it;
|
||||
it = m_svcVec.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto chrIt = pSvc->m_vChars.begin(); chrIt != pSvc->m_vChars.end();) {
|
||||
auto* pChr = *chrIt;
|
||||
if (pChr->getRemoved() == NIMBLE_ATT_REMOVE_DELETE) {
|
||||
delete pChr;
|
||||
chrIt = pSvc->m_vChars.erase(chrIt);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto dscIt = pChr->m_vDescriptors.begin(); dscIt != pChr->m_vDescriptors.end();) {
|
||||
auto* pDsc = *dscIt;
|
||||
if (pDsc->getRemoved() == NIMBLE_ATT_REMOVE_DELETE) {
|
||||
delete pDsc;
|
||||
dscIt = pChr->m_vDescriptors.erase(dscIt);
|
||||
continue;
|
||||
}
|
||||
|
||||
pDsc->m_handle = 0;
|
||||
++dscIt;
|
||||
}
|
||||
|
||||
pChr->m_handle = 0;
|
||||
++chrIt;
|
||||
}
|
||||
|
||||
if (pSvc->getRemoved() == 0) {
|
||||
if (!pSvc->start_internal()) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Failed to start service: %s", pSvc->getUUID().toString().c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
pSvc->m_handle = 0;
|
||||
++svcIt;
|
||||
(*it)->start();
|
||||
++it;
|
||||
}
|
||||
|
||||
return true;
|
||||
m_gattsStarted = false;
|
||||
} // resetGATT
|
||||
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
/**
|
||||
* @brief Start advertising.
|
||||
* @param [in] instId The extended advertisement instance ID to start.
|
||||
* @param [in] duration How long to advertise for in milliseconds, 0 = forever (default).
|
||||
* @param [in] maxEvents Maximum number of advertisement events to send, 0 = no limit (default).
|
||||
* @return True if advertising started successfully.
|
||||
* @details Start the server advertising its existence. This is a convenience function and is equivalent to
|
||||
* retrieving the advertising object and invoking start upon it.
|
||||
*/
|
||||
bool NimBLEServer::startAdvertising(uint8_t instId, int duration, int maxEvents) const {
|
||||
return getAdvertising()->start(instId, duration, maxEvents);
|
||||
} // startAdvertising
|
||||
|
||||
/**
|
||||
* @brief Convenience function to stop advertising a data set.
|
||||
* @param [in] instId The extended advertisement instance ID to stop advertising.
|
||||
* @return True if advertising stopped successfully.
|
||||
*/
|
||||
bool NimBLEServer::stopAdvertising(uint8_t instId) const {
|
||||
return getAdvertising()->stop(instId);
|
||||
} // stopAdvertising
|
||||
|
||||
/**
|
||||
* @brief Request an update to the PHY used for a peer connection.
|
||||
* @param [in] connHandle the connection handle to the update the PHY for.
|
||||
@@ -972,33 +857,9 @@ bool NimBLEServer::getPhy(uint16_t connHandle, uint8_t* txPhy, uint8_t* rxPhy) {
|
||||
|
||||
return rc == 0;
|
||||
} // getPhy
|
||||
|
||||
# if MYNEWT_VAL(BLE_EXT_ADV)
|
||||
/**
|
||||
* @brief Start advertising.
|
||||
* @param [in] instId The extended advertisement instance ID to start.
|
||||
* @param [in] duration How long to advertise for in milliseconds, 0 = forever (default).
|
||||
* @param [in] maxEvents Maximum number of advertisement events to send, 0 = no limit (default).
|
||||
* @return True if advertising started successfully.
|
||||
* @details Start the server advertising its existence. This is a convenience function and is equivalent to
|
||||
* retrieving the advertising object and invoking start upon it.
|
||||
*/
|
||||
bool NimBLEServer::startAdvertising(uint8_t instId, int duration, int maxEvents) const {
|
||||
return getAdvertising()->start(instId, duration, maxEvents);
|
||||
} // startAdvertising
|
||||
|
||||
/**
|
||||
* @brief Convenience function to stop advertising a data set.
|
||||
* @param [in] instId The extended advertisement instance ID to stop advertising.
|
||||
* @return True if advertising stopped successfully.
|
||||
*/
|
||||
bool NimBLEServer::stopAdvertising(uint8_t instId) const {
|
||||
return getAdvertising()->stop(instId);
|
||||
} // stopAdvertising
|
||||
|
||||
# endif
|
||||
|
||||
# if (!MYNEWT_VAL(BLE_EXT_ADV) && MYNEWT_VAL(BLE_ROLE_BROADCASTER)) || defined(_DOXYGEN_)
|
||||
# if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_)
|
||||
/**
|
||||
* @brief Start advertising.
|
||||
* @param [in] duration The duration in milliseconds to advertise for, default = forever.
|
||||
@@ -1075,7 +936,7 @@ void NimBLEServer::setDataLen(uint16_t connHandle, uint16_t octets) const {
|
||||
# endif
|
||||
} // setDataLen
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_CENTRAL)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
/**
|
||||
* @brief Create a client instance from the connection handle.
|
||||
* @param [in] connHandle The connection handle to create a client instance from.
|
||||
@@ -1141,11 +1002,6 @@ uint32_t NimBLEServerCallbacks::onPassKeyDisplay() {
|
||||
return 123456;
|
||||
} // onPassKeyDisplay
|
||||
|
||||
void NimBLEServerCallbacks::onPassKeyEntry(NimBLEConnInfo& connInfo) {
|
||||
NIMBLE_LOGD("NimBLEServerCallbacks", "onPassKeyEntry: default: 123456");
|
||||
NimBLEDevice::injectPassKey(connInfo, 123456);
|
||||
} // onPassKeyEntry
|
||||
|
||||
void NimBLEServerCallbacks::onConfirmPassKey(NimBLEConnInfo& connInfo, uint32_t pin) {
|
||||
NIMBLE_LOGD("NimBLEServerCallbacks", "onConfirmPasskey: default: true");
|
||||
NimBLEDevice::injectConfirmPasskey(connInfo, true);
|
||||
@@ -1163,8 +1019,10 @@ void NimBLEServerCallbacks::onConnParamsUpdate(NimBLEConnInfo& connInfo) {
|
||||
NIMBLE_LOGD("NimBLEServerCallbacks", "onConnParamsUpdate: default");
|
||||
} // onConnParamsUpdate
|
||||
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
void NimBLEServerCallbacks::onPhyUpdate(NimBLEConnInfo& connInfo, uint8_t txPhy, uint8_t rxPhy) {
|
||||
NIMBLE_LOGD("NimBLEServerCallbacks", "onPhyUpdate: default, txPhy: %d, rxPhy: %d", txPhy, rxPhy);
|
||||
} // onPhyUpdate
|
||||
# endif
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
#ifndef NIMBLE_CPP_SERVER_H_
|
||||
#define NIMBLE_CPP_SERVER_H_
|
||||
|
||||
#include "syscfg/syscfg.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
|
||||
# if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
# include "host/ble_gap.h"
|
||||
@@ -45,14 +45,12 @@ class NimBLEConnInfo;
|
||||
class NimBLEAddress;
|
||||
class NimBLEService;
|
||||
class NimBLECharacteristic;
|
||||
# if MYNEWT_VAL(BLE_ROLE_BROADCASTER)
|
||||
# if MYNEWT_VAL(BLE_EXT_ADV)
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
class NimBLEExtAdvertising;
|
||||
# else
|
||||
# else
|
||||
class NimBLEAdvertising;
|
||||
# endif
|
||||
# endif
|
||||
# if MYNEWT_VAL(BLE_ROLE_CENTRAL)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
class NimBLEClient;
|
||||
# endif
|
||||
|
||||
@@ -61,7 +59,7 @@ class NimBLEClient;
|
||||
*/
|
||||
class NimBLEServer {
|
||||
public:
|
||||
bool start();
|
||||
void start();
|
||||
uint8_t getConnectedCount() const;
|
||||
bool disconnect(uint16_t connHandle, uint8_t reason = BLE_ERR_REM_USER_CONN_TERM) const;
|
||||
bool disconnect(const NimBLEConnInfo& connInfo, uint8_t reason = BLE_ERR_REM_USER_CONN_TERM) const;
|
||||
@@ -72,7 +70,6 @@ class NimBLEServer {
|
||||
NimBLEService* getServiceByUUID(const char* uuid, uint16_t instanceId = 0) const;
|
||||
NimBLEService* getServiceByUUID(const NimBLEUUID& uuid, uint16_t instanceId = 0) const;
|
||||
NimBLEService* getServiceByHandle(uint16_t handle) const;
|
||||
NimBLECharacteristic* getCharacteristicByHandle(uint16_t handle) const;
|
||||
void removeService(NimBLEService* service, bool deleteSvc = false);
|
||||
void addService(NimBLEService* service);
|
||||
uint16_t getPeerMTU(uint16_t connHandle) const;
|
||||
@@ -82,62 +79,59 @@ class NimBLEServer {
|
||||
NimBLEConnInfo getPeerInfoByHandle(uint16_t connHandle) const;
|
||||
void advertiseOnDisconnect(bool enable);
|
||||
void setDataLen(uint16_t connHandle, uint16_t tx_octets) const;
|
||||
bool updatePhy(uint16_t connHandle, uint8_t txPhysMask, uint8_t rxPhysMask, uint16_t phyOptions);
|
||||
bool getPhy(uint16_t connHandle, uint8_t* txPhy, uint8_t* rxPhy);
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_CENTRAL)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
NimBLEClient* getClient(uint16_t connHandle);
|
||||
NimBLEClient* getClient(const NimBLEConnInfo& connInfo);
|
||||
void deleteClient();
|
||||
# endif
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_BROADCASTER)
|
||||
# if MYNEWT_VAL(BLE_EXT_ADV)
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
NimBLEExtAdvertising* getAdvertising() const;
|
||||
bool startAdvertising(uint8_t instanceId, int duration = 0, int maxEvents = 0) const;
|
||||
bool stopAdvertising(uint8_t instanceId) const;
|
||||
# endif
|
||||
bool updatePhy(uint16_t connHandle, uint8_t txPhysMask, uint8_t rxPhysMask, uint16_t phyOptions);
|
||||
bool getPhy(uint16_t connHandle, uint8_t* txPhy, uint8_t* rxPhy);
|
||||
# endif
|
||||
|
||||
# if !MYNEWT_VAL(BLE_EXT_ADV) || defined(_DOXYGEN_)
|
||||
# if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_)
|
||||
NimBLEAdvertising* getAdvertising() const;
|
||||
bool startAdvertising(uint32_t duration = 0) const;
|
||||
bool stopAdvertising() const;
|
||||
# endif
|
||||
# endif
|
||||
|
||||
private:
|
||||
friend class NimBLEDevice;
|
||||
friend class NimBLEService;
|
||||
friend class NimBLECharacteristic;
|
||||
# if MYNEWT_VAL(BLE_ROLE_BROADCASTER)
|
||||
# if MYNEWT_VAL(BLE_EXT_ADV)
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
friend class NimBLEExtAdvertising;
|
||||
# else
|
||||
# else
|
||||
friend class NimBLEAdvertising;
|
||||
# endif
|
||||
# endif
|
||||
|
||||
NimBLEServer();
|
||||
~NimBLEServer();
|
||||
static int handleGapEvent(struct ble_gap_event* event, void* arg);
|
||||
static int handleGattEvent(uint16_t connHandle, uint16_t attrHandle, ble_gatt_access_ctxt* ctxt, void* arg);
|
||||
static void gattRegisterCallback(struct ble_gatt_register_ctxt* ctxt, void* arg);
|
||||
void serviceChanged();
|
||||
bool resetGATT();
|
||||
|
||||
bool m_gattsStarted : 1;
|
||||
bool m_svcChanged : 1;
|
||||
bool m_deleteCallbacks : 1;
|
||||
# if !MYNEWT_VAL(BLE_EXT_ADV) && MYNEWT_VAL(BLE_ROLE_BROADCASTER)
|
||||
# if !CONFIG_BT_NIMBLE_EXT_ADV
|
||||
bool m_advertiseOnDisconnect : 1;
|
||||
# endif
|
||||
NimBLEServerCallbacks* m_pServerCallbacks;
|
||||
std::vector<NimBLEService*> m_svcVec;
|
||||
std::array<uint16_t, MYNEWT_VAL(BLE_MAX_CONNECTIONS)> m_connectedPeers;
|
||||
NimBLEServerCallbacks* m_pServerCallbacks;
|
||||
std::vector<NimBLEService*> m_svcVec;
|
||||
std::array<uint16_t, CONFIG_BT_NIMBLE_MAX_CONNECTIONS> m_connectedPeers;
|
||||
|
||||
# if MYNEWT_VAL(BLE_ROLE_CENTRAL)
|
||||
# if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
NimBLEClient* m_pClient{nullptr};
|
||||
# endif
|
||||
|
||||
static int handleGapEvent(struct ble_gap_event* event, void* arg);
|
||||
static int handleGattEvent(uint16_t connHandle, uint16_t attrHandle, ble_gatt_access_ctxt* ctxt, void* arg);
|
||||
void serviceChanged();
|
||||
void resetGATT();
|
||||
|
||||
}; // NimBLEServer
|
||||
|
||||
/**
|
||||
@@ -180,15 +174,6 @@ class NimBLEServerCallbacks {
|
||||
*/
|
||||
virtual uint32_t onPassKeyDisplay();
|
||||
|
||||
/**
|
||||
* @brief Called when using passkey entry pairing and the peer requires the passkey to be entered.
|
||||
* @param [in] connInfo A reference to a NimBLEConnInfo instance with information
|
||||
* about the peer connection parameters.
|
||||
* @details The application should call NimBLEDevice::injectPassKey with the passkey
|
||||
* displayed on the peer device to complete the pairing process.
|
||||
*/
|
||||
virtual void onPassKeyEntry(NimBLEConnInfo& connInfo);
|
||||
|
||||
/**
|
||||
* @brief Called when using numeric comparision for pairing.
|
||||
* @param [in] connInfo A reference to a NimBLEConnInfo instance with information
|
||||
@@ -218,6 +203,7 @@ class NimBLEServerCallbacks {
|
||||
*/
|
||||
virtual void onConnParamsUpdate(NimBLEConnInfo& connInfo);
|
||||
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
/**
|
||||
* @brief Called when the PHY update procedure is complete.
|
||||
* @param [in] connInfo A reference to a NimBLEConnInfo instance with information
|
||||
@@ -230,7 +216,8 @@ class NimBLEServerCallbacks {
|
||||
* * BLE_GAP_LE_PHY_CODED
|
||||
*/
|
||||
virtual void onPhyUpdate(NimBLEConnInfo& connInfo, uint8_t txPhy, uint8_t rxPhy);
|
||||
# endif
|
||||
}; // NimBLEServerCallbacks
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
#endif // CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL
|
||||
#endif // NIMBLE_CPP_SERVER_H_
|
||||
|
||||
@@ -15,10 +15,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "NimBLEService.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
|
||||
# if MYNEWT_VAL(BLE_EXT_ADV)
|
||||
# include "NimBLEService.h"
|
||||
# if CONFIG_BT_NIMBLE_EXT_ADV
|
||||
# include "NimBLEExtAdvertising.h"
|
||||
# else
|
||||
# include "NimBLEAdvertising.h"
|
||||
@@ -48,7 +49,12 @@ NimBLEService::NimBLEService(const NimBLEUUID& uuid)
|
||||
* @brief Destructor, make sure we release the resources allocated for the service.
|
||||
*/
|
||||
NimBLEService::~NimBLEService() {
|
||||
clearServiceDefinitions();
|
||||
if (m_pSvcDef->characteristics) {
|
||||
if (m_pSvcDef->characteristics->descriptors) {
|
||||
delete[] m_pSvcDef->characteristics->descriptors;
|
||||
}
|
||||
delete[] m_pSvcDef->characteristics;
|
||||
}
|
||||
|
||||
for (const auto& it : m_vChars) {
|
||||
delete it;
|
||||
@@ -83,10 +89,22 @@ void NimBLEService::dump() const {
|
||||
* and registers it with the NimBLE stack.
|
||||
* @return bool success/failure .
|
||||
*/
|
||||
bool NimBLEService::start_internal() {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> start(): Starting service: UUID: %s", getUUID().toString().c_str());
|
||||
// Make sure the definitions are cleared first
|
||||
clearServiceDefinitions();
|
||||
bool NimBLEService::start() {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> start(): Starting service: %s", toString().c_str());
|
||||
|
||||
// If started previously and no characteristics have been added or removed,
|
||||
// then we can skip the service registration process.
|
||||
if (m_pSvcDef->characteristics && !getServer()->m_svcChanged) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If started previously, clear everything and start over
|
||||
if (m_pSvcDef->characteristics) {
|
||||
if (m_pSvcDef->characteristics->descriptors) {
|
||||
delete[] m_pSvcDef->characteristics->descriptors;
|
||||
}
|
||||
delete[] m_pSvcDef->characteristics;
|
||||
}
|
||||
|
||||
size_t numChrs = 0;
|
||||
for (const auto& chr : m_vChars) {
|
||||
@@ -96,7 +114,7 @@ bool NimBLEService::start_internal() {
|
||||
++numChrs;
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "Adding %zu characteristics for service %s", numChrs, getUUID().toString().c_str());
|
||||
NIMBLE_LOGD(LOG_TAG, "Adding %d characteristics for service %s", numChrs, toString().c_str());
|
||||
if (numChrs) {
|
||||
int i = 0;
|
||||
|
||||
@@ -143,7 +161,7 @@ bool NimBLEService::start_internal() {
|
||||
pChrs[i].arg = chr;
|
||||
pChrs[i].flags = chr->getProperties();
|
||||
pChrs[i].min_key_size = 0;
|
||||
pChrs[i].val_handle = nullptr;
|
||||
pChrs[i].val_handle = &chr->m_handle;
|
||||
++i;
|
||||
}
|
||||
|
||||
@@ -151,18 +169,15 @@ bool NimBLEService::start_internal() {
|
||||
}
|
||||
|
||||
m_pSvcDef->type = BLE_GATT_SVC_TYPE_PRIMARY;
|
||||
|
||||
int rc = ble_gatts_count_cfg(m_pSvcDef);
|
||||
int rc = ble_gatts_count_cfg(m_pSvcDef);
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "ble_gatts_count_cfg failed, rc= %d, %s", rc, NimBLEUtils::returnCodeToString(rc));
|
||||
clearServiceDefinitions(); // Clear the definitions to free memory and reset the service for re-registration.
|
||||
return false;
|
||||
}
|
||||
|
||||
rc = ble_gatts_add_svcs(m_pSvcDef);
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "ble_gatts_add_svcs, rc= %d, %s", rc, NimBLEUtils::returnCodeToString(rc));
|
||||
clearServiceDefinitions(); // Clear the definitions to free memory and reset the service for re-registration.
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -170,25 +185,6 @@ bool NimBLEService::start_internal() {
|
||||
return true;
|
||||
} // start
|
||||
|
||||
/**
|
||||
* @brief Clear the service definitions to free memory and reset the service for re-registration.
|
||||
*/
|
||||
void NimBLEService::clearServiceDefinitions() {
|
||||
if (m_pSvcDef->characteristics) {
|
||||
const ble_gatt_chr_def* chrDef = m_pSvcDef->characteristics;
|
||||
while (chrDef->uuid != nullptr) {
|
||||
if (chrDef->descriptors) {
|
||||
delete[] chrDef->descriptors;
|
||||
}
|
||||
++chrDef;
|
||||
}
|
||||
delete[] m_pSvcDef->characteristics;
|
||||
m_pSvcDef->characteristics = nullptr;
|
||||
}
|
||||
|
||||
m_pSvcDef->type = 0; // Clear the type to indicate the service is not started/registered.
|
||||
} // clearServiceDefinitions
|
||||
|
||||
/**
|
||||
* @brief Create a new BLE Characteristic associated with this service.
|
||||
* @param [in] uuid - The UUID of the characteristic.
|
||||
@@ -380,4 +376,4 @@ bool NimBLEService::isStarted() const {
|
||||
return m_pSvcDef->type > 0;
|
||||
} // isStarted
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
#ifndef NIMBLE_CPP_SERVICE_H_
|
||||
#define NIMBLE_CPP_SERVICE_H_
|
||||
|
||||
#include "syscfg/syscfg.h"
|
||||
#if CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
|
||||
class NimBLEService;
|
||||
|
||||
@@ -37,19 +37,11 @@ class NimBLEService : public NimBLELocalAttribute {
|
||||
NimBLEService(const NimBLEUUID& uuid);
|
||||
~NimBLEService();
|
||||
|
||||
NimBLEServer* getServer() const;
|
||||
std::string toString() const;
|
||||
void dump() const;
|
||||
bool isStarted() const;
|
||||
|
||||
/**
|
||||
* @brief Dummy function to start the service. Services are started when the server is started.
|
||||
* This will be removed in a future release. Use `NimBLEServer::start()` to start the server and all associated services.
|
||||
*/
|
||||
__attribute__((deprecated("NimBLEService::start() has no effect. "
|
||||
"Services are started when the server is started.")))
|
||||
bool start() { return true; }
|
||||
|
||||
NimBLEServer* getServer() const;
|
||||
std::string toString() const;
|
||||
void dump() const;
|
||||
bool isStarted() const;
|
||||
bool start();
|
||||
NimBLECharacteristic* createCharacteristic(const char* uuid,
|
||||
uint32_t properties = NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE,
|
||||
uint16_t max_len = BLE_ATT_ATTR_MAX_LEN);
|
||||
@@ -69,8 +61,6 @@ class NimBLEService : public NimBLELocalAttribute {
|
||||
|
||||
private:
|
||||
friend class NimBLEServer;
|
||||
bool start_internal();
|
||||
void clearServiceDefinitions();
|
||||
|
||||
std::vector<NimBLECharacteristic*> m_vChars{};
|
||||
// Nimble requires an array of services to be sent to the api
|
||||
@@ -79,5 +69,5 @@ class NimBLEService : public NimBLELocalAttribute {
|
||||
ble_gatt_svc_def m_pSvcDef[2]{};
|
||||
}; // NimBLEService
|
||||
|
||||
#endif // CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
|
||||
#endif // NIMBLE_CPP_SERVICE_H_
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||
#endif /* NIMBLE_CPP_SERVICE_H_ */
|
||||
|
||||
1067
src/NimBLEStream.cpp
1067
src/NimBLEStream.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