mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-02 11:10:54 +03:00
feat(bt): add shared ble_uart component and update ble_uart_service/docs
This commit is contained in:
@@ -2,6 +2,10 @@
|
|||||||
# CMakeLists in this exact order for cmake to work correctly.
|
# CMakeLists in this exact order for cmake to work correctly.
|
||||||
cmake_minimum_required(VERSION 3.22)
|
cmake_minimum_required(VERSION 3.22)
|
||||||
|
|
||||||
|
# Shared `ble_uart` component (must be visible before `project()` so
|
||||||
|
# `main` can `REQUIRES ble_uart`; path is relative to this example root).
|
||||||
|
list(APPEND EXTRA_COMPONENT_DIRS "${CMAKE_CURRENT_LIST_DIR}/../common/ble_uart")
|
||||||
|
|
||||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
idf_build_set_property(MINIMAL_BUILD ON)
|
idf_build_set_property(MINIMAL_BUILD ON)
|
||||||
project(ble_uart_service)
|
project(ble_uart_service)
|
||||||
|
|||||||
@@ -4,9 +4,10 @@
|
|||||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- |
|
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- |
|
||||||
|
|
||||||
A turnkey serial-over-BLE peripheral that implements the de-facto
|
A turnkey serial-over-BLE peripheral that implements the de-facto
|
||||||
**Nordic UART Service** GATT layout (RX write, TX notify), so any
|
**BLE UART-over-GATT** layout (RX write, TX notify; fixed 128-bit UUIDs
|
||||||
standard BLE-serial central (nRF Connect, Web Bluetooth examples, your
|
below), so any widely used BLE-serial central (mobile GATT client apps,
|
||||||
own iOS / Android / Linux / Python scripts) can talk to it unchanged.
|
Web Bluetooth examples, your own iOS / Android / Linux / Python scripts)
|
||||||
|
can talk to it unchanged.
|
||||||
|
|
||||||
The example ships with **two interchangeable backends** — NimBLE and
|
The example ships with **two interchangeable backends** — NimBLE and
|
||||||
Bluedroid — both implementing the same stack-agnostic
|
Bluedroid — both implementing the same stack-agnostic
|
||||||
@@ -19,7 +20,7 @@ manager, advertising, pairing, GAP event handling — is wrapped behind
|
|||||||
**two function calls** in `app_main`:
|
**two function calls** in `app_main`:
|
||||||
|
|
||||||
```c
|
```c
|
||||||
ble_uart_install(&cfg); // NimBLE host + NUS GATT service
|
ble_uart_install(&cfg); // NimBLE host + BLE UART GATT service
|
||||||
ble_uart_open(); // start advertising + auto-encrypt
|
ble_uart_open(); // start advertising + auto-encrypt
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -53,12 +54,14 @@ The `_ENC | _AUTHEN` flags are turned on only when `cfg.encrypted = true`
|
|||||||
| File | Lines | Role |
|
| File | Lines | Role |
|
||||||
| --- | ---: | --- |
|
| --- | ---: | --- |
|
||||||
| `main/main.c` | ~70 | NVS init, MAC-derived device name, install + open, RX echo handler. Identical for both backends. |
|
| `main/main.c` | ~70 | NVS init, MAC-derived device name, install + open, RX echo handler. Identical for both backends. |
|
||||||
| `main/ble_uart.h` | ~260 | Stack-agnostic public API: 3-field config + 4 lifecycle functions + TX/status + UUID + `BLE_UART_E*` return codes. No NimBLE / Bluedroid types leak through. |
|
| `CMakeLists.txt` (root) | ~15 | `list(APPEND EXTRA_COMPONENT_DIRS .../common/ble_uart)` before `project()` so `main` can `REQUIRES ble_uart`. |
|
||||||
| `main/ble_uart_nimble.c` | ~670 | NimBLE backend: host bring-up, NUS GATT service via `ble_gatts_add_svcs`, advertising, pairing, install/open/close/uninstall. Active when `CONFIG_BT_NIMBLE_ENABLED=y`. |
|
| `../common/ble_uart/ble_uart.h` | ~155 | Stack-agnostic public API: 3-field config + 4 lifecycle functions + TX/status + UUID + `BLE_UART_E*` return codes. No NimBLE / Bluedroid types leak through. |
|
||||||
| `main/ble_uart_bluedroid.c` | ~900 | Bluedroid backend: controller + host enable, NUS GATT service via `esp_ble_gatts_create_attr_tab` (service-table API), advertising, pairing, full PREP/EXEC long-write reassembly, install/open/close/uninstall. Active when `CONFIG_BT_BLUEDROID_ENABLED=y`. |
|
| `../common/ble_uart/ble_uart_nimble.c` | ~650 | NimBLE backend: host bring-up, BLE UART GATT service via `ble_gatts_add_svcs`, advertising, pairing, install/open/close/uninstall. Active when `CONFIG_BT_NIMBLE_ENABLED=y`. |
|
||||||
| `main/Kconfig.projbuild` | ~40 | Device-name prefix + RX scratch buffer size knobs. |
|
| `../common/ble_uart/ble_uart_bluedroid.c` | ~1020 | Bluedroid backend: controller + host enable, BLE UART GATT service via `esp_ble_gatts_create_attr_tab` (service-table API), advertising, pairing, full PREP/EXEC long-write reassembly, install/open/close/uninstall. Active when `CONFIG_BT_BLUEDROID_ENABLED=y`. |
|
||||||
|
| `../common/ble_uart/Kconfig` | ~30 | Device-name prefix + RX scratch size (`menuconfig → Component configuration → BLE UART library`). |
|
||||||
|
| `../common/ble_uart/PORTING.md` | ~724 | Porting and API guide (integration, CMake, sdkconfig, thread safety). |
|
||||||
| `sdkconfig.defaults` | — | Default: NimBLE backend, MTU 512, SC + bonding + persistent NVS. |
|
| `sdkconfig.defaults` | — | Default: NimBLE backend, MTU 512, SC + bonding + persistent NVS. |
|
||||||
| `sdkconfig.ci.bluedroid` | — | Overlay: switch to Bluedroid backend (used via `-D SDKCONFIG_DEFAULTS=...`, see "Choosing the host stack" below). |
|
| `sdkconfig.bluedroid` | — | Overlay: switch to Bluedroid backend (used via `-D SDKCONFIG_DEFAULTS=...`, see "Choosing the host stack" below). |
|
||||||
|
|
||||||
## Public API
|
## Public API
|
||||||
|
|
||||||
@@ -91,10 +94,10 @@ extern const ble_uart_uuid128_t ble_uart_service_uuid;
|
|||||||
|
|
||||||
The same `ble_uart.h` API is implemented twice — once on top of NimBLE
|
The same `ble_uart.h` API is implemented twice — once on top of NimBLE
|
||||||
(`ble_uart_nimble.c`) and once on top of Bluedroid
|
(`ble_uart_nimble.c`) and once on top of Bluedroid
|
||||||
(`ble_uart_bluedroid.c`). `main/CMakeLists.txt` registers both files;
|
(`ble_uart_bluedroid.c`). The shared `ble_uart` component's
|
||||||
each guards its body with `#if CONFIG_BT_NIMBLE_ENABLED` / `#if
|
`CMakeLists.txt` registers both files; each guards its body with
|
||||||
CONFIG_BT_BLUEDROID_ENABLED`, so exactly one becomes live at compile
|
`#if CONFIG_BT_NIMBLE_ENABLED` / `#if CONFIG_BT_BLUEDROID_ENABLED`, so
|
||||||
time.
|
exactly one becomes live at compile time.
|
||||||
|
|
||||||
Two ways to switch:
|
Two ways to switch:
|
||||||
|
|
||||||
@@ -103,9 +106,9 @@ Two ways to switch:
|
|||||||
idf.py menuconfig
|
idf.py menuconfig
|
||||||
# Component config -> Bluetooth -> Host -> NimBLE / Bluedroid
|
# Component config -> Bluetooth -> Host -> NimBLE / Bluedroid
|
||||||
|
|
||||||
# B. Apply the Bluedroid overlay non-interactively (great for CI)
|
# B. Apply the Bluedroid overlay non-interactively (scripts / reproducible builds)
|
||||||
idf.py -B build_bd \
|
idf.py -B build_bd \
|
||||||
-D SDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.ci.bluedroid" \
|
-D SDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.bluedroid" \
|
||||||
reconfigure
|
reconfigure
|
||||||
idf.py -B build_bd build flash monitor
|
idf.py -B build_bd build flash monitor
|
||||||
```
|
```
|
||||||
@@ -130,10 +133,16 @@ When neither is enabled the build fails up-front with a clear error.
|
|||||||
```bash
|
```bash
|
||||||
idf.py set-target esp32c3 # or esp32, esp32s3, esp32c6, esp32h2 ...
|
idf.py set-target esp32c3 # or esp32, esp32s3, esp32c6, esp32h2 ...
|
||||||
idf.py menuconfig # optional
|
idf.py menuconfig # optional
|
||||||
# Component config -> BLE UART Example
|
# Component configuration -> BLE UART library
|
||||||
# - BLE device name prefix (default: BleUart)
|
# - BLE device name prefix (default: BleUart)
|
||||||
|
# - RX scratch buffer size (default: 1024 bytes)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Those `BLE_UART_*` options are defined in **`../common/ble_uart/Kconfig`**
|
||||||
|
(the `ble_uart` component); they appear whenever `ble_uart` is part of the
|
||||||
|
build (this example pulls it in via `EXTRA_COMPONENT_DIRS` in the root
|
||||||
|
`CMakeLists.txt`).
|
||||||
|
|
||||||
The two security knobs are set in `sdkconfig.defaults`:
|
The two security knobs are set in `sdkconfig.defaults`:
|
||||||
|
|
||||||
```ini
|
```ini
|
||||||
@@ -152,7 +161,7 @@ idf.py build flash monitor
|
|||||||
```
|
```
|
||||||
|
|
||||||
Expected boot log (NimBLE backend — the per-characteristic register
|
Expected boot log (NimBLE backend — the per-characteristic register
|
||||||
lines are NimBLE-specific; Bluedroid prints the four NUS handles in a
|
lines are NimBLE-specific; Bluedroid prints the four UART-service handles in a
|
||||||
single line, see below):
|
single line, see below):
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -174,7 +183,9 @@ I (xxx) ble_uart: advertising started
|
|||||||
|
|
||||||
## Pairing & demo
|
## Pairing & demo
|
||||||
|
|
||||||
1. On a phone, install **nRF Connect for Mobile**.
|
1. On a phone, install **a BLE GATT client app** that supports scanning,
|
||||||
|
pairing, characteristic write, and notify/CCCD (many mobile “BLE tools”
|
||||||
|
or serial-over-BLE utilities qualify).
|
||||||
2. Scan, tap **Connect** on `BleUart-XXXX`. The phone prompts for a
|
2. Scan, tap **Connect** on `BleUart-XXXX`. The phone prompts for a
|
||||||
6-digit code.
|
6-digit code.
|
||||||
3. The device prints a fresh code in a banner on UART:
|
3. The device prints a fresh code in a banner on UART:
|
||||||
@@ -187,7 +198,7 @@ I (xxx) ble_uart: advertising started
|
|||||||
```
|
```
|
||||||
4. Type that code on the phone; pairing completes. The link is now
|
4. Type that code on the phone; pairing completes. The link is now
|
||||||
AES-CCM-encrypted and the LTK is stored to NVS.
|
AES-CCM-encrypted and the LTK is stored to NVS.
|
||||||
5. Open the *Nordic UART Service*, subscribe to TX (the down-arrow
|
5. Open the **UART service** (UUID `6e400001-…`), subscribe to TX (the down-arrow
|
||||||
icon), then write any bytes to RX (the up-arrow icon). The device
|
icon), then write any bytes to RX (the up-arrow icon). The device
|
||||||
logs them to UART and **echoes them right back** through TX.
|
logs them to UART and **echoes them right back** through TX.
|
||||||
6. Disconnect and reconnect: no passkey prompt — the bond resumes
|
6. Disconnect and reconnect: no passkey prompt — the bond resumes
|
||||||
@@ -204,9 +215,26 @@ bytes with no framing assumptions). Send replies with `ble_uart_tx()`.
|
|||||||
|
|
||||||
## Reusing `ble_uart` in your own project
|
## Reusing `ble_uart` in your own project
|
||||||
|
|
||||||
Copy `main/ble_uart.h` plus the backend(s) you want — `main/ble_uart_nimble.c`
|
**Recommended (no copy):** register the shared component directory **before**
|
||||||
and/or `main/ble_uart_bluedroid.c` — into your project, add `bt nvs_flash`
|
`project()` so CMake can resolve `REQUIRES ble_uart` from `main/` (same pattern
|
||||||
to your component's `REQUIRES`, then in your `app_main`:
|
as this example's root `CMakeLists.txt`):
|
||||||
|
|
||||||
|
```cmake
|
||||||
|
cmake_minimum_required(VERSION 3.22)
|
||||||
|
list(APPEND EXTRA_COMPONENT_DIRS "${CMAKE_CURRENT_LIST_DIR}/../path/to/common/ble_uart")
|
||||||
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
|
project(my_app)
|
||||||
|
```
|
||||||
|
|
||||||
|
Then in `main/CMakeLists.txt` use `REQUIRES ble_uart nvs_flash` and
|
||||||
|
`#include "ble_uart.h"`.
|
||||||
|
|
||||||
|
Adjust the `EXTRA_COMPONENT_DIRS` path if you vendor `common/ble_uart` elsewhere
|
||||||
|
(e.g. `${CMAKE_CURRENT_LIST_DIR}/components/ble_uart`).
|
||||||
|
|
||||||
|
**Alternative:** copy the whole `examples/bluetooth/common/ble_uart/` directory
|
||||||
|
into your tree (or only the `.h` / `.c` files into `main/`) and add `bt nvs_flash`
|
||||||
|
to that component's `REQUIRES`, then in your `app_main`:
|
||||||
|
|
||||||
```c
|
```c
|
||||||
nvs_flash_init();
|
nvs_flash_init();
|
||||||
|
|||||||
@@ -1,10 +1,3 @@
|
|||||||
# Both backends are listed; each .c file body is wrapped in
|
|
||||||
# #if CONFIG_BT_NIMBLE_ENABLED / CONFIG_BT_BLUEDROID_ENABLED so only
|
|
||||||
# the matching backend produces code. This is the standard IDF
|
|
||||||
# pattern for conditional sources, because sdkconfig isn't loaded
|
|
||||||
# during the early CMake component-requirement scan.
|
|
||||||
idf_component_register(SRCS "main.c"
|
idf_component_register(SRCS "main.c"
|
||||||
"ble_uart_nimble.c"
|
|
||||||
"ble_uart_bluedroid.c"
|
|
||||||
INCLUDE_DIRS "."
|
INCLUDE_DIRS "."
|
||||||
REQUIRES bt nvs_flash)
|
REQUIRES ble_uart nvs_flash)
|
||||||
|
|||||||
+4
-3
@@ -2,12 +2,13 @@
|
|||||||
# from the default NimBLE backend to Bluedroid. Use it like:
|
# from the default NimBLE backend to Bluedroid. Use it like:
|
||||||
#
|
#
|
||||||
# idf.py -B build_bd \
|
# idf.py -B build_bd \
|
||||||
# -D SDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.ci.bluedroid" \
|
# -D SDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.bluedroid" \
|
||||||
# reconfigure
|
# reconfigure
|
||||||
# idf.py -B build_bd build flash monitor
|
# idf.py -B build_bd build flash monitor
|
||||||
#
|
#
|
||||||
# When this overlay wins, main/CMakeLists.txt links ble_uart_bluedroid.c
|
# When this overlay wins, the ble_uart component compiles
|
||||||
# instead of ble_uart_nimble.c. The public ble_uart.h API is identical
|
# ble_uart_bluedroid.c instead of ble_uart_nimble.c (each backend is
|
||||||
|
# gated on CONFIG_BT_*_ENABLED). The public ble_uart.h API is identical
|
||||||
# either way.
|
# either way.
|
||||||
|
|
||||||
CONFIG_BT_ENABLED=y
|
CONFIG_BT_ENABLED=y
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# Both backends are listed; each .c file body is wrapped in
|
||||||
|
# #if CONFIG_BT_NIMBLE_ENABLED / #if CONFIG_BT_BLUEDROID_ENABLED so only
|
||||||
|
# the matching backend produces code. This is the standard IDF
|
||||||
|
# pattern for conditional sources, because sdkconfig isn't loaded
|
||||||
|
# during the early CMake component-requirement scan.
|
||||||
|
idf_component_register(SRCS "ble_uart_nimble.c"
|
||||||
|
"ble_uart_bluedroid.c"
|
||||||
|
INCLUDE_DIRS "."
|
||||||
|
REQUIRES bt nvs_flash)
|
||||||
+5
-3
@@ -1,11 +1,13 @@
|
|||||||
menu "BLE UART Example"
|
menu "BLE UART library"
|
||||||
|
|
||||||
config BLE_UART_DEVICE_NAME_PREFIX
|
config BLE_UART_DEVICE_NAME_PREFIX
|
||||||
string "BLE device name prefix"
|
string "BLE device name prefix"
|
||||||
default "BleUart"
|
default "BleUart"
|
||||||
help
|
help
|
||||||
The firmware advertises as `<prefix>-XXXX` where XXXX is
|
Default prefix for examples that advertise as `<prefix>-XXXX`
|
||||||
the last two bytes of the BT MAC in hex.
|
where XXXX is the last two bytes of the BT MAC in hex.
|
||||||
|
Application code may ignore this and set an explicit name in
|
||||||
|
ble_uart_config_t.
|
||||||
|
|
||||||
config BLE_UART_RX_SCRATCH_SIZE
|
config BLE_UART_RX_SCRATCH_SIZE
|
||||||
int "RX scratch buffer size (bytes)"
|
int "RX scratch buffer size (bytes)"
|
||||||
+117
-38
@@ -1,7 +1,20 @@
|
|||||||
# BLE UART Porting & API Guide
|
# BLE UART Porting & API Guide
|
||||||
|
|
||||||
|
This document lives in **`examples/bluetooth/common/ble_uart/`** next to the
|
||||||
|
`ble_uart` component sources (`ble_uart.h`, backend `.c` files).
|
||||||
|
|
||||||
|
**Reference application:** use the **`examples/bluetooth/ble_uart_service`**
|
||||||
|
example as the working template. Its root `CMakeLists.txt` appends this
|
||||||
|
directory to **`EXTRA_COMPONENT_DIRS`** so `main` can `REQUIRES ble_uart`;
|
||||||
|
`main/main.c` initializes NVS and a MAC-derived GAP name, calls
|
||||||
|
`ble_uart_install()` / `ble_uart_open()` with the default encrypted UART-over-BLE echo
|
||||||
|
path, and the tree ships `sdkconfig.defaults` plus the Bluedroid overlay
|
||||||
|
(`sdkconfig.bluedroid`). Clone or diff that project when adapting to a new
|
||||||
|
target or host stack.
|
||||||
|
|
||||||
A complete guide to integrating `ble_uart` into any ESP-IDF project.
|
A complete guide to integrating `ble_uart` into any ESP-IDF project.
|
||||||
**Two or three files plus 5 steps of glue code** are enough to bring an
|
**Either** `EXTRA_COMPONENT_DIRS` pointing at this component **or** a few
|
||||||
|
copied source files **plus** the glue steps below are enough to bring an
|
||||||
encrypted BLE serial peripheral up in a fresh project — the same
|
encrypted BLE serial peripheral up in a fresh project — the same
|
||||||
`ble_uart.h` API works on top of either NimBLE or Bluedroid; pick the
|
`ble_uart.h` API works on top of either NimBLE or Bluedroid; pick the
|
||||||
host with a Kconfig knob.
|
host with a Kconfig knob.
|
||||||
@@ -18,7 +31,7 @@ flagged inline.
|
|||||||
|
|
||||||
| Capability | Description |
|
| Capability | Description |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| Standard Nordic UART Service GATT (RX/TX) | Interoperates with every generic BLE-serial tool (nRF Connect, Web Bluetooth, custom scripts) |
|
| Widely used BLE UART-over-GATT (RX/TX) | Interoperates with every generic BLE-serial tool (mobile GATT clients, Web Bluetooth, custom scripts) |
|
||||||
| LE Secure Connections + Bonding pairing | Single switch; when enabled, a fresh 6-digit passkey is printed to UART |
|
| LE Secure Connections + Bonding pairing | Single switch; when enabled, a fresh 6-digit passkey is printed to UART |
|
||||||
| Auto-reconnect | After a bonded central disconnects, advertising restarts immediately and the LTK is reused — no passkey prompt |
|
| Auto-reconnect | After a bonded central disconnects, advertising restarts immediately and the LTK is reused — no passkey prompt |
|
||||||
| Raw byte pass-through | RX is delivered via a callback; TX is exposed as `ble_uart_tx` |
|
| Raw byte pass-through | RX is delivered via a callback; TX is exposed as `ble_uart_tx` |
|
||||||
@@ -44,26 +57,45 @@ is entirely up to you**.
|
|||||||
|
|
||||||
## 3. File Inventory
|
## 3. File Inventory
|
||||||
|
|
||||||
Files to copy into the target project — pick the backend you want and
|
Canonical sources live under **`$IDF_PATH/examples/bluetooth/common/ble_uart/`**
|
||||||
copy that pair plus the public header:
|
(component name `ble_uart`): `ble_uart.h`, `ble_uart_nimble.c`,
|
||||||
|
`ble_uart_bluedroid.c`, `CMakeLists.txt`, and `Kconfig` (prefix + RX scratch;
|
||||||
|
`menuconfig → Component configuration → BLE UART library`). When reusing
|
||||||
|
outside this tree, copy the whole `common/ble_uart/` directory or at least
|
||||||
|
merge `Kconfig` into your component so the same `CONFIG_BLE_UART_*` symbols
|
||||||
|
exist.
|
||||||
|
|
||||||
|
**Option A — depend on the in-tree component (no copy):** add the component
|
||||||
|
directory to **`EXTRA_COMPONENT_DIRS` in the project root `CMakeLists.txt`
|
||||||
|
before `include($ENV{IDF_PATH}/tools/cmake/project.cmake)` / `project()`**,
|
||||||
|
then use `REQUIRES ble_uart` from `main/CMakeLists.txt` (see
|
||||||
|
`examples/bluetooth/ble_uart_service/CMakeLists.txt`). This ensures the
|
||||||
|
`ble_uart` target exists when CMake expands `main`'s requirements.
|
||||||
|
|
||||||
|
Kconfig options appear under
|
||||||
|
`menuconfig → Component configuration → BLE UART library`.
|
||||||
|
|
||||||
|
> A `main/idf_component.yml` path dependency alone is **not** sufficient if
|
||||||
|
> `main/CMakeLists.txt` lists `REQUIRES ble_uart`: the early requirement scan
|
||||||
|
> runs before the component manager injects that dependency, so CMake fails
|
||||||
|
> with *unknown component `ble_uart`*. Prefer `EXTRA_COMPONENT_DIRS` (as in the
|
||||||
|
> reference example) or copy the sources into a normal project component.
|
||||||
|
|
||||||
|
**Option B — copy into your project:** pick the backend you want and
|
||||||
|
copy that pair plus the public header (or copy both backends; each `.c`
|
||||||
|
gates on its Kconfig symbol):
|
||||||
|
|
||||||
```
|
```
|
||||||
your_project/main/
|
your_project/main/
|
||||||
├── ble_uart.h ← copy this (stack-agnostic public API, ~260 lines)
|
├── ble_uart.h ← copy from .../common/ble_uart/
|
||||||
├── ble_uart_nimble.c ← if you'll set CONFIG_BT_NIMBLE_ENABLED=y (~670 lines)
|
├── ble_uart_nimble.c ← if you'll set CONFIG_BT_NIMBLE_ENABLED=y
|
||||||
└── ble_uart_bluedroid.c ← if you'll set CONFIG_BT_BLUEDROID_ENABLED=y (~900 lines)
|
└── ble_uart_bluedroid.c ← if you'll set CONFIG_BT_BLUEDROID_ENABLED=y
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also copy *both* `ble_uart_nimble.c` and `ble_uart_bluedroid.c`
|
Optional: copy `Kconfig` from `common/ble_uart/` into your component (or merge
|
||||||
unchanged — each `.c` file gates its body on the matching Kconfig
|
its symbols into your own `Kconfig`) if you want `BLE_UART_*` in `menuconfig`;
|
||||||
symbol, so the inactive one compiles to nothing. This is what the
|
otherwise hard-code the device name and rely on the 1024-byte fallback for RX
|
||||||
example itself does, and it lets you flip stacks without changing the
|
scratch.
|
||||||
source list.
|
|
||||||
|
|
||||||
Optional: `Kconfig.projbuild` defines `BLE_UART_DEVICE_NAME_PREFIX`
|
|
||||||
and `BLE_UART_RX_SCRATCH_SIZE`. Copy it too if you want either to be
|
|
||||||
tunable from `menuconfig`; otherwise hard-code the name in your
|
|
||||||
source and rely on the 1024-byte fallback for RX scratch.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -75,11 +107,12 @@ Assume you already have an ESP-IDF project (`my_project/`).
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd my_project/main
|
cd my_project/main
|
||||||
|
BLE_UART_SRC="$IDF_PATH/examples/bluetooth/common/ble_uart"
|
||||||
# Stack-agnostic public header — always.
|
# Stack-agnostic public header — always.
|
||||||
cp /path/to/ble_uart_service/main/ble_uart.h .
|
cp "$BLE_UART_SRC/ble_uart.h" .
|
||||||
# Pick one (or copy both — the inactive one compiles to nothing).
|
# Pick one (or copy both — the inactive one compiles to nothing).
|
||||||
cp /path/to/ble_uart_service/main/ble_uart_nimble.c .
|
cp "$BLE_UART_SRC/ble_uart_nimble.c" .
|
||||||
cp /path/to/ble_uart_service/main/ble_uart_bluedroid.c .
|
cp "$BLE_UART_SRC/ble_uart_bluedroid.c" .
|
||||||
```
|
```
|
||||||
|
|
||||||
### 4.2 Edit `main/CMakeLists.txt`
|
### 4.2 Edit `main/CMakeLists.txt`
|
||||||
@@ -116,6 +149,22 @@ the central must support it.
|
|||||||
|
|
||||||
**Bluedroid backend (drop-in alternative):**
|
**Bluedroid backend (drop-in alternative):**
|
||||||
|
|
||||||
|
Use the **`examples/bluetooth/ble_uart_service/sdkconfig.bluedroid`** file as
|
||||||
|
the authoritative Kconfig overlay: it enables the host stack, SMP, GATTS
|
||||||
|
(service-table API), and the BLE-only advertising knobs that
|
||||||
|
`ble_uart_bluedroid.c` expects. Either merge those lines into your own
|
||||||
|
`sdkconfig.defaults`, or pass them as a second defaults file:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
idf.py -D SDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.bluedroid" reconfigure
|
||||||
|
```
|
||||||
|
|
||||||
|
(Paths are relative to the example project root; copy `sdkconfig.bluedroid`
|
||||||
|
into your tree if you are not starting from `ble_uart_service`.)
|
||||||
|
|
||||||
|
A minimal inline sketch (may drift from IDF defaults — **diff against
|
||||||
|
`sdkconfig.bluedroid` after each IDF upgrade**):
|
||||||
|
|
||||||
```ini
|
```ini
|
||||||
CONFIG_BT_ENABLED=y
|
CONFIG_BT_ENABLED=y
|
||||||
CONFIG_BT_NIMBLE_ENABLED=n
|
CONFIG_BT_NIMBLE_ENABLED=n
|
||||||
@@ -124,8 +173,8 @@ CONFIG_BT_BLUEDROID_ENABLED=y
|
|||||||
# LE Secure Connections + bonding (Bluedroid persists LTKs by default)
|
# LE Secure Connections + bonding (Bluedroid persists LTKs by default)
|
||||||
CONFIG_BT_BLE_SMP_ENABLE=y
|
CONFIG_BT_BLE_SMP_ENABLE=y
|
||||||
|
|
||||||
# Optional: bigger MTU
|
# Optional: bigger MTU (when supported by your IDF target / menuconfig)
|
||||||
CONFIG_BT_GATT_MAX_MTU_SIZE=512
|
# CONFIG_BT_GATT_MAX_MTU_SIZE=512
|
||||||
|
|
||||||
# BLE-only feature set (saves flash on classic-BT-capable parts)
|
# BLE-only feature set (saves flash on classic-BT-capable parts)
|
||||||
CONFIG_BT_BLE_42_FEATURES_SUPPORTED=y
|
CONFIG_BT_BLE_42_FEATURES_SUPPORTED=y
|
||||||
@@ -201,7 +250,7 @@ I (xxx) ble_uart: registered service svc_handle=40 rx=42 tx=44 cccd=45
|
|||||||
I (xxx) ble_uart: advertising started
|
I (xxx) ble_uart: advertising started
|
||||||
```
|
```
|
||||||
|
|
||||||
nRF Connect on a phone discovers `MyDevice`; connect, enter the
|
A phone GATT client app discovers `MyDevice`; connect, enter the
|
||||||
passkey, subscribe to TX, write to RX, and you will see the echo come
|
passkey, subscribe to TX, write to RX, and you will see the echo come
|
||||||
back.
|
back.
|
||||||
|
|
||||||
@@ -337,7 +386,7 @@ returns `ENOTCONN` to tell you.
|
|||||||
extern const ble_uart_uuid128_t ble_uart_service_uuid;
|
extern const ble_uart_uuid128_t ble_uart_service_uuid;
|
||||||
```
|
```
|
||||||
|
|
||||||
Always `6e400001-b5a3-f393-e0a9-e50e24dcca9e` (the NUS standard). It is
|
Always `6e400001-b5a3-f393-e0a9-e50e24dcca9e` (the de-facto BLE UART service UUID). It is
|
||||||
already inserted into the scan response, so the **application normally
|
already inserted into the scan response, so the **application normally
|
||||||
does not touch it**. You only need it if you take over advertising
|
does not touch it**. You only need it if you take over advertising
|
||||||
yourself (see 6.3).
|
yourself (see 6.3).
|
||||||
@@ -403,7 +452,7 @@ Effect:
|
|||||||
- GATT characteristics drop the `_ENC | _AUTHEN` flags.
|
- GATT characteristics drop the `_ENC | _AUTHEN` flags.
|
||||||
- Any central can read/write — no pairing required.
|
- Any central can read/write — no pairing required.
|
||||||
- No passkey prompt.
|
- No passkey prompt.
|
||||||
- Data is sniffable by any nearby nRF dongle.
|
- Data is sniffable by any nearby BLE sniffer or compromised radio in range.
|
||||||
|
|
||||||
**Do not ship this in production firmware.**
|
**Do not ship this in production firmware.**
|
||||||
|
|
||||||
@@ -439,7 +488,10 @@ ble_uart_open();
|
|||||||
|
|
||||||
### 6.4 Configuring the device-name prefix via Kconfig
|
### 6.4 Configuring the device-name prefix via Kconfig
|
||||||
|
|
||||||
Copy `Kconfig.projbuild` into `main/`, then:
|
If you use the shared `ble_uart` component, options are already in
|
||||||
|
`menuconfig → Component configuration → BLE UART library`. If you copied only
|
||||||
|
the `.c` / `.h` files into `main/`, copy `Kconfig` from `common/ble_uart/` as
|
||||||
|
well (or merge its symbols into your own `Kconfig.projbuild`), then:
|
||||||
|
|
||||||
```c
|
```c
|
||||||
char name[24];
|
char name[24];
|
||||||
@@ -453,8 +505,8 @@ ble_uart_install(&(ble_uart_config_t){
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
Edit the default through `menuconfig → BLE UART Example → BLE device
|
Edit the default through `menuconfig → Component configuration → BLE UART
|
||||||
name prefix`.
|
library → BLE device name prefix`.
|
||||||
|
|
||||||
### 6.5 Pushing data proactively
|
### 6.5 Pushing data proactively
|
||||||
|
|
||||||
@@ -538,16 +590,17 @@ If you **build directly on top of this example**:
|
|||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `main.c` echo template | Replace with your own `on_rx` body |
|
| `main.c` echo template | Replace with your own `on_rx` body |
|
||||||
| `sdkconfig.defaults` | Reuse as-is |
|
| `sdkconfig.defaults` | Reuse as-is |
|
||||||
| `Kconfig.projbuild` | Reuse as-is |
|
| `sdkconfig.bluedroid` | Only if you switch to Bluedroid host — reuse as-is (see §4.3); omit for default NimBLE |
|
||||||
|
| Root `CMakeLists.txt` (`EXTRA_COMPONENT_DIRS` → `../common/ble_uart`) | Reuse as-is (or follow §3 option B) |
|
||||||
| `CMakeLists.txt` (root + main) | Reuse as-is |
|
| `CMakeLists.txt` (root + main) | Reuse as-is |
|
||||||
|
|
||||||
If you **start from an empty project**:
|
If you **start from an empty project**:
|
||||||
|
|
||||||
| What you need to do | Source |
|
| What you need to do | Source |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| Copy `ble_uart.h` + at least one of `ble_uart_nimble.c` / `ble_uart_bluedroid.c` into `main/` | This example |
|
| Add `EXTRA_COMPONENT_DIRS` for `examples/bluetooth/common/ble_uart` in root `CMakeLists.txt`, **or** copy `ble_uart.h` + at least one of `ble_uart_nimble.c` / `ble_uart_bluedroid.c` into `main/` | §3 of this guide |
|
||||||
| Copy the key lines of `sdkconfig.defaults` | §4.3 of this guide |
|
| Copy the key lines of `sdkconfig.defaults` | §4.3 of this guide |
|
||||||
| Add SRC + REQUIRES to `main/CMakeLists.txt` | §4.2 of this guide |
|
| Add `REQUIRES ble_uart nvs_flash` (after `EXTRA_COMPONENT_DIRS`) **or** SRC + `REQUIRES bt nvs_flash` (copied sources) to `main/CMakeLists.txt` | §4.2 of this guide |
|
||||||
| Write `install` + `open` in `app_main` | §4.4 of this guide |
|
| Write `install` + `open` in `app_main` | §4.4 of this guide |
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -591,8 +644,21 @@ extern const ble_uart_uuid128_t ble_uart_service_uuid;
|
|||||||
|
|
||||||
## 12. Minimal Project Template (ready to flash)
|
## 12. Minimal Project Template (ready to flash)
|
||||||
|
|
||||||
A complete flashable project takes 7 files (the inactive backend `.c`
|
A complete flashable project takes a handful of files. The inactive
|
||||||
compiles to nothing, so it costs you nothing to ship both):
|
backend `.c` compiles to nothing if you ship both.
|
||||||
|
|
||||||
|
**Using the shared component (fewer copies):**
|
||||||
|
|
||||||
|
```
|
||||||
|
my_ble_uart_project/
|
||||||
|
├── CMakeLists.txt ← EXTRA_COMPONENT_DIRS → …/common/ble_uart (before project())
|
||||||
|
├── sdkconfig.defaults
|
||||||
|
└── main/
|
||||||
|
├── CMakeLists.txt ← REQUIRES ble_uart nvs_flash; SRCS main.c only
|
||||||
|
└── main.c
|
||||||
|
```
|
||||||
|
|
||||||
|
**Copying sources into `main/` (classic layout):**
|
||||||
|
|
||||||
```
|
```
|
||||||
my_ble_uart_project/
|
my_ble_uart_project/
|
||||||
@@ -600,20 +666,28 @@ my_ble_uart_project/
|
|||||||
├── sdkconfig.defaults
|
├── sdkconfig.defaults
|
||||||
└── main/
|
└── main/
|
||||||
├── CMakeLists.txt
|
├── CMakeLists.txt
|
||||||
├── ble_uart.h ← copied from this example
|
├── ble_uart.h ← from $IDF_PATH/examples/bluetooth/common/ble_uart/
|
||||||
├── ble_uart_nimble.c ← copied from this example
|
├── ble_uart_nimble.c
|
||||||
├── ble_uart_bluedroid.c ← copied from this example (optional)
|
├── ble_uart_bluedroid.c ← optional second backend
|
||||||
└── main.c
|
└── main.c
|
||||||
```
|
```
|
||||||
|
|
||||||
**Root `CMakeLists.txt`**:
|
**Root `CMakeLists.txt`** (shared `ble_uart` via `EXTRA_COMPONENT_DIRS`):
|
||||||
```cmake
|
```cmake
|
||||||
cmake_minimum_required(VERSION 3.16)
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
list(APPEND EXTRA_COMPONENT_DIRS "${CMAKE_CURRENT_LIST_DIR}/../path/to/common/ble_uart")
|
||||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
project(my_ble_uart)
|
project(my_ble_uart)
|
||||||
```
|
```
|
||||||
|
|
||||||
**`main/CMakeLists.txt`**:
|
**`main/CMakeLists.txt`** (shared component — no `.c` copies in `main/`):
|
||||||
|
```cmake
|
||||||
|
idf_component_register(SRCS "main.c"
|
||||||
|
INCLUDE_DIRS "."
|
||||||
|
REQUIRES ble_uart nvs_flash)
|
||||||
|
```
|
||||||
|
|
||||||
|
**`main/CMakeLists.txt`** (classic copy layout — both backends in `main/`):
|
||||||
```cmake
|
```cmake
|
||||||
idf_component_register(SRCS "main.c"
|
idf_component_register(SRCS "main.c"
|
||||||
"ble_uart_nimble.c"
|
"ble_uart_nimble.c"
|
||||||
@@ -633,6 +707,11 @@ CONFIG_BT_NIMBLE_NVS_PERSIST=y
|
|||||||
CONFIG_BT_NIMBLE_ATT_PREFERRED_MTU=512
|
CONFIG_BT_NIMBLE_ATT_PREFERRED_MTU=512
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Bluedroid host instead of NimBLE:** copy
|
||||||
|
`examples/bluetooth/ble_uart_service/sdkconfig.bluedroid` next to your
|
||||||
|
`sdkconfig.defaults` and pass
|
||||||
|
`-D SDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.bluedroid"` (see §4.3).
|
||||||
|
|
||||||
**`main/main.c`** — copy the §4.4 template verbatim.
|
**`main/main.c`** — copy the §4.4 template verbatim.
|
||||||
|
|
||||||
Flash:
|
Flash:
|
||||||
+6
-6
@@ -5,8 +5,8 @@
|
|||||||
*
|
*
|
||||||
* BLE UART — turnkey serial-over-BLE peripheral.
|
* BLE UART — turnkey serial-over-BLE peripheral.
|
||||||
*
|
*
|
||||||
* Implements the de-facto Nordic UART Service (NUS) GATT layout
|
* Implements the de-facto BLE UART-over-GATT layout (RX write, TX notify;
|
||||||
* (RX write, TX notify) on top of either NimBLE or Bluedroid; the
|
* fixed 128-bit UUIDs below) on top of either NimBLE or Bluedroid; the
|
||||||
* backend is picked at compile time via CONFIG_BT_NIMBLE_ENABLED /
|
* backend is picked at compile time via CONFIG_BT_NIMBLE_ENABLED /
|
||||||
* CONFIG_BT_BLUEDROID_ENABLED.
|
* CONFIG_BT_BLUEDROID_ENABLED.
|
||||||
*
|
*
|
||||||
@@ -21,13 +21,13 @@
|
|||||||
* Run-forever apps only need install + open. close / uninstall is
|
* Run-forever apps only need install + open. close / uninstall is
|
||||||
* for apps that need to power BLE off at runtime.
|
* for apps that need to power BLE off at runtime.
|
||||||
*
|
*
|
||||||
* GATT layout (UUIDs fixed by the NUS spec):
|
* GATT layout (UUIDs are the widely used fixed 128-bit values):
|
||||||
*
|
*
|
||||||
* Service: 6e400001-b5a3-f393-e0a9-e50e24dcca9e
|
* Service: 6e400001-b5a3-f393-e0a9-e50e24dcca9e
|
||||||
* RX : 6e400002-b5a3-f393-e0a9-e50e24dcca9e write
|
* RX : 6e400002-b5a3-f393-e0a9-e50e24dcca9e write
|
||||||
* TX : 6e400003-b5a3-f393-e0a9-e50e24dcca9e notify
|
* TX : 6e400003-b5a3-f393-e0a9-e50e24dcca9e notify
|
||||||
*
|
*
|
||||||
* See PORTING.md for the integration guide.
|
* See PORTING.md in this component directory for the integration guide.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@@ -89,7 +89,7 @@ typedef struct {
|
|||||||
|
|
||||||
/* ----- Lifecycle ------------------------------------------------------ */
|
/* ----- Lifecycle ------------------------------------------------------ */
|
||||||
|
|
||||||
/** Bring up host stack + Security Manager + SIG services + NUS GATT
|
/** Bring up host stack + Security Manager + SIG services + BLE UART GATT
|
||||||
* service. Caller must have already called nvs_flash_init().
|
* service. Caller must have already called nvs_flash_init().
|
||||||
* cfg->device_name is copied; doesn't need to outlive the call.
|
* cfg->device_name is copied; doesn't need to outlive the call.
|
||||||
* Single-shot until ble_uart_uninstall(); a second call returns
|
* Single-shot until ble_uart_uninstall(); a second call returns
|
||||||
@@ -145,7 +145,7 @@ bool ble_uart_is_subscribed(void);
|
|||||||
|
|
||||||
/* ----- Service UUID -------------------------------------------------- */
|
/* ----- Service UUID -------------------------------------------------- */
|
||||||
|
|
||||||
/** The NUS service UUID, exposed for custom advertising payloads.
|
/** The BLE UART service UUID, exposed for custom advertising payloads.
|
||||||
* The two characteristic UUIDs are private to the backend. */
|
* The two characteristic UUIDs are private to the backend. */
|
||||||
extern const ble_uart_uuid128_t ble_uart_service_uuid;
|
extern const ble_uart_uuid128_t ble_uart_service_uuid;
|
||||||
|
|
||||||
+2
-2
@@ -204,7 +204,7 @@ static void build_attr_table(bool encrypted)
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/* [TX value] — NUS spec is notify-only, so the prop above doesn't
|
/* [TX value] — TX characteristic is notify-only, so the prop above doesn't
|
||||||
* advertise READ; perm only matters if a client tries READ anyway. */
|
* advertise READ; perm only matters if a client tries READ anyway. */
|
||||||
s_nus_db[NUS_IDX_TX_VAL] = (esp_gatts_attr_db_t){
|
s_nus_db[NUS_IDX_TX_VAL] = (esp_gatts_attr_db_t){
|
||||||
.attr_control = {ESP_GATT_AUTO_RSP},
|
.attr_control = {ESP_GATT_AUTO_RSP},
|
||||||
@@ -251,7 +251,7 @@ static esp_ble_adv_data_t s_adv_data = {
|
|||||||
.flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT),
|
.flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT),
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Scan response = NUS UUID. Splitting it off the primary payload
|
/* Scan response = 128-bit UART service UUID. Splitting it off the primary payload
|
||||||
* leaves room for name + tx_pwr in the 31-byte primary. */
|
* leaves room for name + tx_pwr in the 31-byte primary. */
|
||||||
static esp_ble_adv_data_t s_scan_rsp_data = {
|
static esp_ble_adv_data_t s_scan_rsp_data = {
|
||||||
.set_scan_rsp = true,
|
.set_scan_rsp = true,
|
||||||
+7
-6
@@ -64,7 +64,7 @@ extern void ble_store_config_init(void);
|
|||||||
|
|
||||||
/* ===== UUIDs =========================================================== */
|
/* ===== UUIDs =========================================================== */
|
||||||
|
|
||||||
/* NUS UUIDs in little-endian byte order. */
|
/* BLE UART profile UUIDs in little-endian byte order. */
|
||||||
#define NUS_SVC_BYTES 0x9e, 0xca, 0xdc, 0x24, 0x0e, 0xe5, 0xa9, 0xe0, \
|
#define NUS_SVC_BYTES 0x9e, 0xca, 0xdc, 0x24, 0x0e, 0xe5, 0xa9, 0xe0, \
|
||||||
0x93, 0xf3, 0xa3, 0xb5, 0x01, 0x00, 0x40, 0x6e
|
0x93, 0xf3, 0xa3, 0xb5, 0x01, 0x00, 0x40, 0x6e
|
||||||
#define NUS_RX_BYTES 0x9e, 0xca, 0xdc, 0x24, 0x0e, 0xe5, 0xa9, 0xe0, \
|
#define NUS_RX_BYTES 0x9e, 0xca, 0xdc, 0x24, 0x0e, 0xe5, 0xa9, 0xe0, \
|
||||||
@@ -80,8 +80,9 @@ static const ble_uuid128_t s_chr_tx_uuid = BLE_UUID128_INIT(NUS_TX_BYTES);
|
|||||||
|
|
||||||
/* ===== State =========================================================== */
|
/* ===== State =========================================================== */
|
||||||
|
|
||||||
/* RX scratch capacity. Tunable via menuconfig; fall back to 1024 if
|
/* RX scratch capacity. Tunable via menuconfig (Component config → BLE UART
|
||||||
* Kconfig.projbuild isn't carried along when reusing this file. */
|
* library); fall
|
||||||
|
* back to 1024 if CONFIG_BLE_UART_RX_SCRATCH_SIZE is absent. */
|
||||||
#ifndef CONFIG_BLE_UART_RX_SCRATCH_SIZE
|
#ifndef CONFIG_BLE_UART_RX_SCRATCH_SIZE
|
||||||
#define CONFIG_BLE_UART_RX_SCRATCH_SIZE 1024
|
#define CONFIG_BLE_UART_RX_SCRATCH_SIZE 1024
|
||||||
#endif
|
#endif
|
||||||
@@ -106,7 +107,7 @@ static uint8_t s_own_addr_type;
|
|||||||
static int gap_event(struct ble_gap_event *event, void *arg);
|
static int gap_event(struct ble_gap_event *event, void *arg);
|
||||||
static int start_advertising(void);
|
static int start_advertising(void);
|
||||||
|
|
||||||
/* ===== GATT (NUS) ====================================================== */
|
/* ===== GATT (BLE UART service) ========================================= */
|
||||||
|
|
||||||
static int chr_access(uint16_t conn_handle, uint16_t attr_handle,
|
static int chr_access(uint16_t conn_handle, uint16_t attr_handle,
|
||||||
struct ble_gatt_access_ctxt *ctxt, void *arg)
|
struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||||
@@ -253,7 +254,7 @@ static int start_advertising(void)
|
|||||||
{
|
{
|
||||||
/* 31-byte primary adv can't hold flags + tx_pwr + name + 128-bit
|
/* 31-byte primary adv can't hold flags + tx_pwr + name + 128-bit
|
||||||
* UUID together, so split: primary = flags+tx_pwr+name,
|
* UUID together, so split: primary = flags+tx_pwr+name,
|
||||||
* scan rsp = NUS UUID. */
|
* scan rsp = 128-bit service UUID. */
|
||||||
const char *name = s_dev_name;
|
const char *name = s_dev_name;
|
||||||
size_t name_len = strlen(name);
|
size_t name_len = strlen(name);
|
||||||
|
|
||||||
@@ -262,7 +263,7 @@ static int start_advertising(void)
|
|||||||
.tx_pwr_lvl_is_present = 1,
|
.tx_pwr_lvl_is_present = 1,
|
||||||
.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO,
|
.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO,
|
||||||
/* If no name was set, advertise without one (NimBLE accepts
|
/* If no name was set, advertise without one (NimBLE accepts
|
||||||
* NULL+0); the NUS UUID in scan rsp still identifies us. */
|
* NULL+0); the service UUID in scan rsp still identifies us. */
|
||||||
.name = name_len > 0 ? (uint8_t *)name : NULL,
|
.name = name_len > 0 ? (uint8_t *)name : NULL,
|
||||||
.name_len = name_len,
|
.name_len = name_len,
|
||||||
.name_is_complete = name_len > 0 ? 1 : 0,
|
.name_is_complete = name_len > 0 ? 1 : 0,
|
||||||
@@ -62,7 +62,7 @@ Open an interactive BLE UART Console:
|
|||||||
python main.py console DEVICE_ID
|
python main.py console DEVICE_ID
|
||||||
```
|
```
|
||||||
|
|
||||||
For Console options such as line endings, hex mode, and write-with-response, see [Quick-Start-BLE-UART-Console.md](docs/Quick-Start-BLE-UART-Console.md). If you need firmware to test against, use the [BLE UART Service example](../../../examples/bluetooth/ble_uart_service) as an Echo Server: it advertises the default Nordic UART Service profile and echoes RX writes back through TX notifications.
|
For Console options such as line endings, hex mode, and write-with-response, see [Quick-Start-BLE-UART-Console.md](docs/Quick-Start-BLE-UART-Console.md). If you need firmware to test against, use the [BLE UART Service example](../../../examples/bluetooth/ble_uart_service) as an Echo Server: it advertises the default BLE UART-over-GATT UUIDs and echoes RX writes back through TX notifications.
|
||||||
|
|
||||||
Run the BLE UART Daemon:
|
Run the BLE UART Daemon:
|
||||||
|
|
||||||
@@ -194,7 +194,7 @@ Main responsibilities:
|
|||||||
- Connect and disconnect with a BLE UART GATT profile.
|
- Connect and disconnect with a BLE UART GATT profile.
|
||||||
- Subscribe to device-to-host notifications.
|
- Subscribe to device-to-host notifications.
|
||||||
- Send host-to-device data as `str`, `bytes`, or `bytearray`.
|
- Send host-to-device data as `str`, `bytes`, or `bytearray`.
|
||||||
- Support a default NUS profile and user-defined BLE UART profiles.
|
- Support a default BLE-UART UUID profile and user-defined BLE UART profiles.
|
||||||
|
|
||||||
Important APIs:
|
Important APIs:
|
||||||
|
|
||||||
@@ -262,7 +262,7 @@ Use Core when your business logic lives in Python. Use Console when you only nee
|
|||||||
|
|
||||||
## Profile compatibility
|
## Profile compatibility
|
||||||
|
|
||||||
The default profile is compatible with the Nordic UART Service (NUS):
|
The default profile uses the widely deployed BLE UART-over-GATT UUID set:
|
||||||
|
|
||||||
- Service UUID: `6E400001-B5A3-F393-E0A9-E50E24DCCA9E`
|
- Service UUID: `6E400001-B5A3-F393-E0A9-E50E24DCCA9E`
|
||||||
- RX characteristic UUID, host to device: `6E400002-B5A3-F393-E0A9-E50E24DCCA9E`
|
- RX characteristic UUID, host to device: `6E400002-B5A3-F393-E0A9-E50E24DCCA9E`
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ flowchart LR
|
|||||||
OC -->|permission.asked| Plugin
|
OC -->|permission.asked| Plugin
|
||||||
Plugin -->|POST /notify| Daemon[ble_uart_bridge daemon]
|
Plugin -->|POST /notify| Daemon[ble_uart_bridge daemon]
|
||||||
Plugin -->|POST /request| Daemon
|
Plugin -->|POST /request| Daemon
|
||||||
Daemon -->|BLE NUS JSONL| Device[BLE device UI]
|
Daemon -->|BLE UART JSONL| Device[BLE device UI]
|
||||||
Device -->|once / reject| Daemon
|
Device -->|once / reject| Daemon
|
||||||
Daemon -->|HTTP response| Plugin
|
Daemon -->|HTTP response| Plugin
|
||||||
Plugin -->|SDK permission reply| OC
|
Plugin -->|SDK permission reply| OC
|
||||||
@@ -54,7 +54,7 @@ flowchart LR
|
|||||||
|
|
||||||
The intended firmware companion is an `esp-vocat` example for the MiaoBan
|
The intended firmware companion is an `esp-vocat` example for the MiaoBan
|
||||||
(喵伴) device, planned for the `esp-iot-solution` repository. Until that
|
(喵伴) device, planned for the `esp-iot-solution` repository. Until that
|
||||||
example is available, use any device that implements Nordic UART Service and
|
example is available, use any device that implements the default BLE UART-over-GATT UUIDs and
|
||||||
the JSONL request/response envelope described in
|
the JSONL request/response envelope described in
|
||||||
[Firmware protocol reference](#firmware-protocol-reference).
|
[Firmware protocol reference](#firmware-protocol-reference).
|
||||||
|
|
||||||
@@ -235,7 +235,7 @@ permission requests can be approved once with `once` or denied with `reject`.
|
|||||||
- The BLE daemon endpoint is configured by `OPENCODE_BLE_DAEMON_URL`, defaulting
|
- The BLE daemon endpoint is configured by `OPENCODE_BLE_DAEMON_URL`, defaulting
|
||||||
to `http://127.0.0.1:8888`.
|
to `http://127.0.0.1:8888`.
|
||||||
- The BLE daemon supports both `POST /notify` and `POST /request`.
|
- The BLE daemon supports both `POST /notify` and `POST /request`.
|
||||||
- The BLE device implements Nordic UART Service.
|
- The BLE device implements the default BLE UART-over-GATT UUID layout.
|
||||||
- The BLE device understands JSON messages described in
|
- The BLE device understands JSON messages described in
|
||||||
[Firmware protocol reference](#firmware-protocol-reference).
|
[Firmware protocol reference](#firmware-protocol-reference).
|
||||||
- Permission decisions from the current single-key device are: `once`, `reject`.
|
- Permission decisions from the current single-key device are: `once`, `reject`.
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ await bridge.send(b"\x01\x02", with_response=True)
|
|||||||
|
|
||||||
## Use a custom BLE UART profile
|
## Use a custom BLE UART profile
|
||||||
|
|
||||||
The default profile uses Nordic UART Service UUIDs. For custom firmware, create a `BLEUARTProfile`:
|
The default profile uses the de-facto BLE UART-over-GATT UUIDs. For custom firmware, create a `BLEUARTProfile`:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from src.core import BLEUARTBridge
|
from src.core import BLEUARTBridge
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ BLE UART Bridge works with BLE GATT profiles that provide a UART-like data path:
|
|||||||
- one characteristic that the host writes to
|
- one characteristic that the host writes to
|
||||||
- one characteristic that the device uses to notify data back to the host
|
- one characteristic that the device uses to notify data back to the host
|
||||||
|
|
||||||
The default profile is compatible with the Nordic UART Service (NUS), but NUS is not the only possible BLE UART-style profile.
|
The default profile matches the widely used BLE UART-over-GATT UUID set (service `6E400001-…`, RX/TX characteristics), but that layout is not the only possible BLE UART-style profile.
|
||||||
|
|
||||||
## Default NUS-compatible profile
|
## Default BLE-UART-compatible profile
|
||||||
|
|
||||||
The built-in default profile uses these UUIDs:
|
The built-in default profile uses these UUIDs:
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@ The built-in default profile uses these UUIDs:
|
|||||||
| RX, host to device | `6E400002-B5A3-F393-E0A9-E50E24DCCA9E` |
|
| RX, host to device | `6E400002-B5A3-F393-E0A9-E50E24DCCA9E` |
|
||||||
| TX, device to host | `6E400003-B5A3-F393-E0A9-E50E24DCCA9E` |
|
| TX, device to host | `6E400003-B5A3-F393-E0A9-E50E24DCCA9E` |
|
||||||
|
|
||||||
Use the default profile when the device advertises a NUS-compatible service.
|
Use the default profile when the device advertises a service using those UUIDs.
|
||||||
|
|
||||||
## ESP-IDF BLE SPP examples
|
## ESP-IDF BLE SPP examples
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ ESP-IDF includes BLE SPP examples that implement Espressif BLE UART-like vendor-
|
|||||||
- `examples/bluetooth/bluedroid/ble/ble_spp_server`
|
- `examples/bluetooth/bluedroid/ble/ble_spp_server`
|
||||||
- `examples/bluetooth/bluedroid/ble/ble_spp_client`
|
- `examples/bluetooth/bluedroid/ble/ble_spp_client`
|
||||||
|
|
||||||
BLE SPP over BLE is not a Bluetooth SIG standard profile. It is a vendor-specific GATT design that emulates a serial link, similar in purpose to NUS.
|
BLE SPP over BLE is not a Bluetooth SIG standard profile. It is a vendor-specific GATT design that emulates a serial link, similar in purpose to the default BLE UART layout above.
|
||||||
|
|
||||||
ESP-IDF BLE SPP examples may define more characteristics than BLE UART Bridge needs, such as data, command, and status characteristics. To use BLE UART Bridge with such a profile, map only the UART-like data path into `BLEUARTProfile`.
|
ESP-IDF BLE SPP examples may define more characteristics than BLE UART Bridge needs, such as data, command, and status characteristics. To use BLE UART Bridge with such a profile, map only the UART-like data path into `BLEUARTProfile`.
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ The Console is useful when you want to type data into a BLE UART device and insp
|
|||||||
|
|
||||||
On Windows, run `export.bat` or `export.ps1` from the ESP-IDF root directory before installing `requirements.txt`. If you use your own Python virtual environment instead, activate it before installing `requirements.txt`.
|
On Windows, run `export.bat` or `export.ps1` from the ESP-IDF root directory before installing `requirements.txt`. If you use your own Python virtual environment instead, activate it before installing `requirements.txt`.
|
||||||
|
|
||||||
3. A BLE device advertising the BLE UART service. By default the tool scans for Nordic UART Service UUIDs. For a known-compatible test target, build and flash the [BLE UART Service example](../../../../examples/bluetooth/ble_uart_service), which acts as an Echo Server by echoing RX writes back through TX notifications.
|
3. A BLE device advertising the BLE UART service. By default the tool scans for the de-facto BLE UART-over-GATT UUIDs (`6E400001-…` / `…02` / `…03`). For a known-compatible test target, build and flash the [BLE UART Service example](../../../../examples/bluetooth/ble_uart_service), which acts as an Echo Server by echoing RX writes back through TX notifications.
|
||||||
|
|
||||||
## Find a device
|
## Find a device
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user