component/ble_mesh: Add user manuals for ESP BLE Mesh examples
11
.project
@@ -1,11 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>esp-idf(1)</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
@@ -1,124 +0,0 @@
|
||||
# Espressif IoT Development Framework
|
||||
|
||||
[](https://docs.espressif.com/projects/esp-idf/en/latest/?badge=latest)
|
||||
|
||||
ESP-IDF is the official development framework for the [ESP32](https://espressif.com/en/products/hardware/esp32/overview) chip.
|
||||
|
||||
# Developing With ESP-IDF
|
||||
|
||||
## Setting Up ESP-IDF
|
||||
|
||||
See setup guides for detailed instructions to set up the ESP-IDF:
|
||||
|
||||
* [Getting Started Guide for the stable ESP-IDF version](https://docs.espressif.com/projects/esp-idf/en/stable/get-started/)
|
||||
* [Getting Started Guide for the latest (master branch) ESP-IDF version](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/)
|
||||
|
||||
## Finding a Project
|
||||
|
||||
As well as the [esp-idf-template](https://github.com/espressif/esp-idf-template) project mentioned in Getting Started, ESP-IDF comes with some example projects in the [examples](examples) directory.
|
||||
|
||||
Once you've found the project you want to work with, change to its directory and you can configure and build it.
|
||||
|
||||
To start your own project based on an example, copy the example project directory outside of the ESP-IDF directory.
|
||||
|
||||
# Quick Reference
|
||||
|
||||
See the Getting Started guide links above for a detailed setup guide. This is a quick reference for common commands when working with ESP-IDF projects:
|
||||
|
||||
## Configuring the Project
|
||||
|
||||
`make menuconfig`
|
||||
|
||||
* Opens a text-based configuration menu for the project.
|
||||
* Use up & down arrow keys to navigate the menu.
|
||||
* Use Enter key to go into a submenu, Escape key to go out or to exit.
|
||||
* Type `?` to see a help screen. Enter key exits the help screen.
|
||||
* Use Space key, or `Y` and `N` keys to enable (Yes) and disable (No) configuration items with checkboxes "`[*]`"
|
||||
* Pressing `?` while highlighting a configuration item displays help about that item.
|
||||
* Type `/` to search the configuration items.
|
||||
|
||||
Once done configuring, press Escape multiple times to exit and say "Yes" to save the new configuration when prompted.
|
||||
|
||||
## Compiling the Project
|
||||
|
||||
`make -j4 all`
|
||||
|
||||
... will compile app, bootloader and generate a partition table based on the config.
|
||||
|
||||
NOTE: The `-j4` option causes `make` to run 4 parallel jobs. This is much faster than the default single job. The recommended number to pass to this option is `-j(number of CPUs + 1)`.
|
||||
|
||||
## Flashing the Project
|
||||
|
||||
When `make all` finishes, it will print a command line to use esptool.py to flash the chip. However you can also do this from make by running:
|
||||
|
||||
`make -j4 flash`
|
||||
|
||||
This will flash the entire project (app, bootloader and partition table) to a new chip. The settings for serial port flashing can be configured with `make menuconfig`.
|
||||
|
||||
You don't need to run `make all` before running `make flash`, `make flash` will automatically rebuild anything which needs it.
|
||||
|
||||
## Viewing Serial Output
|
||||
|
||||
The `make monitor` target uses the [idf_monitor tool](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/idf-monitor.html) to display serial output from the ESP32. idf_monitor also has a range of features to decode crash output and interact with the device. [Check the documentation page for details](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/idf-monitor.html).
|
||||
|
||||
Exit the monitor by typing Ctrl-].
|
||||
|
||||
To build, flash and monitor output in one pass, you can run:
|
||||
|
||||
`make -j4 flash monitor`
|
||||
|
||||
## Compiling & Flashing Only the App
|
||||
|
||||
After the initial flash, you may just want to build and flash just your app, not the bootloader and partition table:
|
||||
|
||||
* `make app` - build just the app.
|
||||
* `make app-flash` - flash just the app.
|
||||
|
||||
`make app-flash` will automatically rebuild the app if any source files have changed.
|
||||
|
||||
(In normal development there's no downside to reflashing the bootloader and partition table each time, if they haven't changed.)
|
||||
|
||||
## Parallel Builds
|
||||
|
||||
ESP-IDF supports compiling multiple files in parallel, so all of the above commands can be run as `make -jN` where `N` is the number of parallel make processes to run (generally N should be equal to the number of CPU cores in your system, plus one.)
|
||||
|
||||
Multiple make functions can be combined into one. For example: to build the app & bootloader using 5 jobs in parallel, then flash everything, and then display serial output from the ESP32 run:
|
||||
|
||||
```
|
||||
make -j5 flash monitor
|
||||
```
|
||||
|
||||
## The Partition Table
|
||||
|
||||
Once you've compiled your project, the "build" directory will contain a binary file with a name like "my_app.bin". This is an ESP32 image binary that can be loaded by the bootloader.
|
||||
|
||||
A single ESP32's flash can contain multiple apps, as well as many different kinds of data (calibration data, filesystems, parameter storage, etc). For this reason a partition table is flashed to offset 0x8000 in the flash.
|
||||
|
||||
Each entry in the partition table has a name (label), type (app, data, or something else), subtype and the offset in flash where the partition is loaded.
|
||||
|
||||
The simplest way to use the partition table is to `make menuconfig` and choose one of the simple predefined partition tables:
|
||||
|
||||
* "Single factory app, no OTA"
|
||||
* "Factory app, two OTA definitions"
|
||||
|
||||
In both cases the factory app is flashed at offset 0x10000. If you `make partition_table` then it will print a summary of the partition table.
|
||||
|
||||
For more details about partition tables and how to create custom variations, view the [`docs/en/api-guides/partition-tables.rst`](docs/en/api-guides/partition-tables.rst) file.
|
||||
|
||||
## Erasing Flash
|
||||
|
||||
The `make flash` target does not erase the entire flash contents. However it is sometimes useful to set the device back to a totally erased state, particularly when making partition table changes or OTA app updates. To erase the entire flash, run `make erase_flash`.
|
||||
|
||||
This can be combined with other targets, ie `make erase_flash flash` will erase everything and then re-flash the new app, bootloader and partition table.
|
||||
|
||||
# Resources
|
||||
|
||||
* Documentation for the latest version: https://docs.espressif.com/projects/esp-idf/. This documentation is built from the [docs directory](docs) of this repository.
|
||||
|
||||
* The [esp32.com forum](https://esp32.com/) is a place to ask questions and find community resources.
|
||||
|
||||
* [Check the Issues section on github](https://github.com/espressif/esp-idf/issues) if you find a bug or have a feature request. Please check existing Issues before opening a new one.
|
||||
|
||||
* If you're interested in contributing to ESP-IDF, please check the [Contributions Guide](https://docs.espressif.com/projects/esp-idf/en/latest/contribute/index.html).
|
||||
|
||||
|
||||
@@ -72,19 +72,31 @@ $ tree examples/bluetooth/ble_mesh/
|
||||
│ ├── sdkconfig.defaults
|
||||
│ └── tutorial
|
||||
│ └── Ble_Mesh_Node_Example_Walkthrough.md
|
||||
└── ble_mesh_provisioner
|
||||
├── ble_mesh_provisioner
|
||||
│ ├── main
|
||||
│ │ ├── ble_mesh_demo_main.c
|
||||
│ │ ├── board.c
|
||||
│ │ ├── board.h
|
||||
│ │ ├── component.mk
|
||||
│ │ └── Kconfig.projbuild
|
||||
│ ├── Makefile
|
||||
│ ├── README.md
|
||||
│ ├── sdkconfig.defaults
|
||||
│ └── tutorial
|
||||
│ └── Ble_Mesh_Provisioner_Example_Walkthrough.md
|
||||
├──ble_mesh_console
|
||||
│ ├── ble_mesh_node
|
||||
│ └── ble_mesh_provisioner
|
||||
├──ble_mesh_fast_provision
|
||||
│ ├── ble_mesh_fast_prov_client
|
||||
│ └── ble_mesh_fast_prov_server
|
||||
├──ble_mesh_vendor_models
|
||||
│ ├── fast_prov_vendor_model
|
||||
└──ble_mesh_wifi_coexist
|
||||
├── main
|
||||
│ ├── ble_mesh_demo_main.c
|
||||
│ ├── board.c
|
||||
│ ├── board.h
|
||||
│ ├── component.mk
|
||||
│ └── Kconfig.projbuild
|
||||
├── Makefile
|
||||
├── README.md
|
||||
├── sdkconfig.defaults
|
||||
├── components
|
||||
└── tutorial
|
||||
└── Ble_Mesh_Provisioner_Example_Walkthrough.md
|
||||
|
||||
└── ble_mesh_wifi_coexist.md
|
||||
8 directories, 26 files
|
||||
```
|
||||
|
||||
@@ -115,7 +127,7 @@ This example shows how a device can act as a BLE Mesh provisioner to provision d
|
||||
|
||||
## Mobile Apps
|
||||
|
||||
ESP BLE Mesh implementation is compatible with a few phone apps, including Silicon Labs BLE Mesh and nRF Mesh. These apps are available on Google Play and App Store. In addition, Espressif offers its own Android app which is currently being actively developed. You can find the latest APK file [here](http://download.espressif.com/BLE_MESH/BLE_Mesh_Tools/BLE_Mesh_App/EspBleMesh-v0.9.2).
|
||||
ESP BLE Mesh implementation is compatible with a few phone apps, including Silicon Labs BLE Mesh and nRF Mesh. These apps are available on Google Play and App Store. In addition, Espressif offers its own Android app which is currently being actively developed. You can find the latest APK file [here](http://download.espressif.com/BLE_MESH/BLE_Mesh_Tools/BLE_Mesh_App/EspBleMesh-0.9.4.apk).
|
||||
|
||||
Note: The most recent tested version 1.1.0 of Silicon Labs App has a bug, which has been fixed by a workaround on the SDK side. The fix is implemented through a configuration option enabled by default. For other Android/iOS apps, this option needs to be disabled from menuconfig:
|
||||
`make menuconfig -> Example Configuration -> This option fixes the bug of Silicon Lab Android App 1.1.0 when reconnection will cause the sequence number to recount from 0`
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
* [Provisioning of BLE Mesh nodes using Smartphone App](http://download.espressif.com/BLE_MESH/Docs4Customers/esp-ble-mesh-demo.mp4)
|
||||
* [Espressif Fast Provisioning using ESP BLE Mesh App](http://download.espressif.com/BLE_MESH/BLE_Mesh_Demo/V0.4_Demo_Fast_Provision/ESP32_BLE_Mesh_Fast_Provision.mp4)
|
||||
* [Espressif BLE Mesh and Wi-Fi Coexistence](http://download.espressif.com/BLE_MESH/BLE_Mesh_Demo/V0.5_Demo_Coexistence/ESP_BLE_MESH_%26_WIFI_Coexistence.mp4)
|
||||
|
||||
## Examples
|
||||
|
||||
@@ -12,7 +13,14 @@
|
||||
* [BLE Mesh Provisioner Example Code](../../../../examples/bluetooth/ble_mesh/ble_mesh_provisioner)
|
||||
* [BLE_Mesh_Provisioner_Example_Walkthrough](../../../../examples/bluetooth/ble_mesh/ble_mesh_provisioner/tutorial/Ble_Mesh_Provisioner_Example_Walkthrough.md)
|
||||
* [BLE Mesh Client Model Example Code](../../../../examples/bluetooth/ble_mesh/ble_mesh_client_model)
|
||||
|
||||
* [BLE_Mesh_Client_Model_Example_Walkthrough](../../../../examples/bluetooth/ble_mesh/ble_mesh_client_model/tutorial/ble_mesh_client_model.md)
|
||||
* [BLE Mesh Console Example Code](../../../../examples/bluetooth/ble_mesh/ble_mesh_console)
|
||||
* [BLE Mesh Fast Prov Client Example Code](../../../../examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client)
|
||||
* [BLE_Mesh_Fast_Prov_Client_Example_Walkthrough](../../../../examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/tutorial/ble_mesh_fast_provision_client.md)
|
||||
* [BLE Mesh Fast Prov Server Example Code](../../../../examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server)
|
||||
* [BLE_Mesh_Fast_Prov_Server_Example_Walkthrough](../../../../examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/ble_mesh_fast_provision_server.md)
|
||||
* [BLE Mesh Wifi Coexist Example Code](../../../../examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist)
|
||||
* [BLE_Mesh_Wifi_Coexist_Example_Walkthrough](../../../../examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/tutorial%20%20%20%20%20%20/ble_mesh_wifi_coexist.md)
|
||||
## Documentation
|
||||
|
||||
### ESP BLE Mesh Development Documentation
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
|
||||
@@ -0,0 +1,260 @@
|
||||
# 1. Introduction
|
||||
## 1.1 Demo Function
|
||||
|
||||
1. This demo forwards the message sent by the nRF Mesh app.
|
||||
2. The user enters the address of the destination node and use it to forwarded packet.
|
||||
3. The types of the forwarded message include:
|
||||
* `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET`,
|
||||
* `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET`,
|
||||
* `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK`.
|
||||
4. The destination node reports its Onoff state with the `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS` message.
|
||||
|
||||
Example: The nRF Mesh app sends a `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET` message to the node that runs the `ble_mesh_client_model` project. Then this node sends a `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET` message to the destination node that runs the `ble_mesh_node` project. The address of the destination node is entered by the user via the serial port.
|
||||
|
||||
## 1.1.1 What You Need
|
||||
|
||||
* 1 x Device that runs the `ble_mesh_client_model` project.
|
||||
* 1 x Device that runs the `ble_mesh_node` project.
|
||||
* 1 x Phone that installs the nRF Mesh app for controlling these two devices
|
||||
|
||||
## 1.2 Node Composition
|
||||
|
||||
This demo has only one element, in which the following three Models are implemented:
|
||||
|
||||
- **Configuration Server Model** is mainly to represent a mesh network configuration, such as its AppKey, Relay State, TTL State, Subscription List State, etc.
|
||||
- **Generic OnOff Client Model** controls a Generic OnOff Server via messages defined by the Generic OnOff Model, that is, turning on and off the lights.
|
||||
- **Generic OnOff Server Model** implements the nodes' Onoff state.
|
||||
|
||||
## 1.3 Message Sequence
|
||||
|
||||
You can choose from the 4 message sequences described below:
|
||||
|
||||
1. Acknowledged Get
|
||||
2. Acknowledged Set
|
||||
3. Unacknowledged Set
|
||||
4. Acknowledged Set with Periodic Publishing
|
||||
|
||||

|
||||
|
||||
## 2. Code Analysis
|
||||
|
||||
Code initialization part reference [Initializing the Bluetooth and Initializing the BLE Mesh](../../ble_mesh_wifi_coexist/tutorial%20%20%20%20%20%20/ble_mesh_wifi_coexist.md)
|
||||
|
||||
### 2.1 Model Definition
|
||||
|
||||
#### 2.1.1 Generic OnOff Server Model
|
||||
|
||||
```c
|
||||
//Allocating memory for publishing messages.
|
||||
static esp_ble_mesh_model_pub_t onoff_srv_pub = {
|
||||
.msg = NET_BUF_SIMPLE(2 + 1),
|
||||
.update = NULL,
|
||||
.dev_role = MSG_ROLE,
|
||||
};
|
||||
//Registering the minimum length of messages. For example, the minimum length of the ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET message is registered as 2 octets.
|
||||
static esp_ble_mesh_model_op_t onoff_op[] = {
|
||||
{ ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET, 0, 0},
|
||||
{ ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET, 2, 0},
|
||||
{ ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK, 2, 0},
|
||||
ESP_BLE_MESH_MODEL_OP_END,
|
||||
};
|
||||
//Registering the Generic Onoff Server Model.
|
||||
static esp_ble_mesh_model_t root_models[] = {
|
||||
//onoff server's onoff state init
|
||||
ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV, onoff_op,
|
||||
&onoff_srv_pub, &led_state[0]),
|
||||
};
|
||||
```
|
||||
#### 2.1.2 Generic OnOff Client Model
|
||||
|
||||
```c
|
||||
//Allocating memory for publishing messages.
|
||||
static esp_ble_mesh_model_pub_t onoff_cli_pub = {
|
||||
.msg = NET_BUF_SIMPLE(2 + 1),
|
||||
.update = NULL,
|
||||
.dev_role = MSG_ROLE,
|
||||
};
|
||||
//Registering the Generic Onoff Client Model.
|
||||
static esp_ble_mesh_model_t root_models[] = {
|
||||
ESP_BLE_MESH_MODEL_GEN_ONOFF_CLI(&onoff_cli_pub, &onoff_client),
|
||||
};
|
||||
```
|
||||
|
||||
### 2.2 Model Callback Function
|
||||
|
||||
#### 2.2.1 The Callback function for the Generic Onoff Client Model
|
||||
|
||||
```c
|
||||
esp_ble_mesh_register_generic_client_callback(esp_ble_mesh_generic_cb);
|
||||
|
||||
```
|
||||
1. The callback function will be triggered when the Client Model:
|
||||
|
||||
* Receives a message that indicates the Onoff state of the Sever Model; Or
|
||||
* Calls any APIs that the Server Model send messages.
|
||||
|
||||
2. The events that the callback function handle:
|
||||
|
||||
| Event name | Opcode |Description |
|
||||
| ------------- | ------------|------------------------------------------- |
|
||||
| ESP_BLE_MESH_GENERIC_CLIENT_GET_STATE_EVT | ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET |The event triggered when the Generic Onoff Client Model receives acknowledgment after sending the `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET` message |
|
||||
| ESP_BLE_MESH_GENERIC_CLIENT_SET_STATE_EVT | ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET | The event triggered when the Generic Onoff Client Model receives acknowledgment after sending the `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET` message |
|
||||
| ESP_BLE_MESH_GENERIC_CLIENT_PUBLISH_EVT | NA | The event triggered when the Generic Onoff Client Model receives publishing messages. |
|
||||
| ESP_BLE_MESH_GENERIC_CLIENT_TIMEOUT_EVT | ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET | The event triggered when API (that send messages) calling times out |
|
||||
|
||||
|
||||
#### 2.2.2 The Callback function for the Generic Onoff Server Model
|
||||
|
||||
```c
|
||||
esp_ble_mesh_register_custom_model_callback(esp_ble_mesh_model_cb);
|
||||
|
||||
```
|
||||
1. The callback function will be triggered when the Server Model:
|
||||
|
||||
* Receives a message that indicates operating the Onoff state of the Server Model from the Generic Onoff Client Model; Or
|
||||
* Calls any APIs that the Server Model send messages.
|
||||
|
||||
2. The events of the callback function:
|
||||
|
||||
| Event Name | Opcode | Description |
|
||||
|-------------------------------------|-------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| ESP_BLE_MESH_MODEL_OPERATION_EVT | ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET | The event triggered when the Generic Onoff Server Model receives the ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET message that **gets** the Onoff state of the server from the Client Model |
|
||||
| ESP_BLE_MESH_MODEL_OPERATION_EVT | ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET | The event triggered when the Generic Onoff Server Model receives the ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET message that **sets** the Onoff state of the server from the Client Model |
|
||||
| ESP_BLE_MESH_MODEL_OPERATION_EVT | ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK | The event triggered when the Generic Onoff Server Model receives the ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK message that **sets** the Onoff state of the server from the Client Model |
|
||||
| ESP_BLE_MESH_MODEL_SEND_COMP_EVT | NA | The event triggered when the `esp_ble_mesh_server_model_send_msg` API calling completes |
|
||||
| ESP_BLE_MESH_MODEL_PUBLISH_COMP_EVT | NA | The event triggered when the `esp_ble_mesh_model_publish` API calling completes |
|
||||
|
||||
|
||||
### 2.3 Model that Sends Message
|
||||
#### 2.3.1 Message Control
|
||||
|
||||
The `esp_ble_mesh_set_msg_common` function is used to set the message controlling parameters.
|
||||
|
||||
| Parameter Name |Description |
|
||||
| ----------------------|------------------------- |
|
||||
| `opcode` | The message opcode |
|
||||
| `model` | The pointer to the client Model struct |
|
||||
| `ctx.net_idx` | The NetKey Index of the subnet through which the message is sent |
|
||||
| `ctx.app_idx` | The AppKey Index for message encryption |
|
||||
| `ctx.addr` | The address of the destination nodes |
|
||||
| `ctx.send_ttl`| The TTL State, which determines how many times a message will be relayed |
|
||||
| `ctx.send_rel`| This parameter determines if the Model will wait for an acknowledgement after sending a message |
|
||||
| `msg_timeout` | The maximum time the Model will wait for an acknowledgement |
|
||||
| `msg_role` | The role of message (node/provisioner) |
|
||||
|
||||
> Note:
|
||||
>
|
||||
> Please check the `ESP_BLE_MESH_MODEL_SEND_COMP_EVT` event to see if the message is sent successfully.
|
||||
> This event is just for sending sig Model and vendor Model messages, not for all Models.
|
||||
|
||||
#### 2.3.2 The Generic Onoff Client sends message
|
||||
|
||||
The Generic Onoff Client Model calls the `esp_ble_mesh_generic_client_get_state` API to get the state of the server Model, such as the Onoff state.
|
||||
|
||||
```c
|
||||
esp_ble_mesh_generic_client_get_state_t get_state = {0};
|
||||
esp_ble_mesh_set_msg_common(&common, node, onoff_client.model, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET);
|
||||
err = esp_ble_mesh_generic_client_get_state(&common, &get_state);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "%s: Generic OnOff Get failed", __func__);
|
||||
return;
|
||||
}
|
||||
```
|
||||
|
||||
The Generic Onoff Client Model calls the `esp_ble_mesh_generic_client_set_state` API to set the state of the server Model, such as the Onoff state.
|
||||
|
||||
```c
|
||||
esp_ble_mesh_generic_client_set_state_t set_state = {0};
|
||||
esp_ble_mesh_set_msg_common(&common, &set_state, onoff_client.model,
|
||||
ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET, remote_onoff);
|
||||
err = esp_ble_mesh_generic_client_set_state(&common, &set_state);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "%s: Generic OnOff Set failed", __func__);
|
||||
return;
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.3.3 The Generic Onoff Server sends message
|
||||
|
||||
The Generic Onoff Server Model has to bind its Appkey before calling the `esp_ble_mesh_server_model_send_msg` API to send a message.
|
||||
|
||||
```c
|
||||
err = esp_ble_mesh_server_model_send_msg(model, ctx, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS,
|
||||
sizeof(send_data), &send_data);
|
||||
```
|
||||
The Generic Onoff Server Model calls the `esp_ble_mesh_model_publish` API to publish messages. Only the Models that have subscribed to this destination address receive the published messages.
|
||||
|
||||
```c
|
||||
err = esp_ble_mesh_model_publish(model, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS,
|
||||
sizeof(led->current), &led->current, ROLE_NODE);
|
||||
```
|
||||
|
||||
### 2.4 Users Enter the Address of the Destination Node via Serial Port
|
||||
|
||||
Please connect your devices and enters the address of the destination node via the serial port.
|
||||
|
||||
Users can adjust the address of the destination node.
|
||||
|
||||
|
||||
> Note:
|
||||
> Please connect the pin 16 and pin 17 of the device that runs the `ble_mesh_client_model` project to the USB-to-UART tool.
|
||||
|
||||
```c
|
||||
#define UART1_TX_PIN GPIO_NUM_16
|
||||
#define UART1_RX_PIN GPIO_NUM_17
|
||||
```
|
||||
|
||||
The `board_uart_task` task is used to receive commands sent via the serial port, among which, the`remote_addr` represents the address of destination node that the message is forwarded to. Please enters hexadecimal string, such as 5, for this parameter. The address will be converted to 0x05 automatically.
|
||||
|
||||
```c
|
||||
static void board_uart_task(void *p)
|
||||
{
|
||||
uint8_t *data = calloc(1, UART_BUF_SIZE);
|
||||
uint32_t input;
|
||||
|
||||
while (1) {
|
||||
int len = uart_read_bytes(MESH_UART_NUM, data, UART_BUF_SIZE, 100 / portTICK_RATE_MS);
|
||||
if (len > 0) {
|
||||
input = strtoul((const char *)data, NULL, 16);
|
||||
remote_addr = input & 0xFFFF;
|
||||
ESP_LOGI(TAG, "%s: input 0x%08x, remote_addr 0x%04x", __func__, input, remote_addr);
|
||||
memset(data, 0, UART_BUF_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
# 3. Timing Sequence Diagram
|
||||
|
||||
The steps for this demo:
|
||||
|
||||
1. The nRF Mesh App provisionings the unprovisioned devices into nodes;
|
||||
2. The nRF Mesh App adds a Appkey to these nodes, and bind the Models of these nodes to this Appkey.
|
||||
3. The nRF Mesh App sends a controlling message to the Generic Onoff Client Model. Then the Client Model forwards this message to the server Model of the other node.
|
||||
|
||||
The timing sequence diagram of this demo is shown below:
|
||||
|
||||
 <div align=center></div>
|
||||
|
||||
>Note:
|
||||
>
|
||||
>The node **only forwards the message after it receives the controlling message sent by the app**. That is said, the node will **not** forwards messages to the other nodes every time the user enters the address of the destination node through the serial port.
|
||||
|
||||
|
||||
# 4. The nRF Mesh App
|
||||
|
||||

|
||||
|
||||
1. Scan the unprovisioned devices.
|
||||
2. Identity the the capability of the unprovisioned devices.
|
||||
3. Provisioning the unprovisioned devices.
|
||||
4. Check if the Mesh node has been configured successful.
|
||||
5. Configure the Models of the nodes.
|
||||
6. Click on the Generic On Off Client option.
|
||||
7. Bind the Generic On Off Client Model to the Appkey.
|
||||
8. Check if the binding is successfully.
|
||||
9. Bind the Generic On Off Server Model to the Appkey.
|
||||
10. Send controlling messages.
|
||||
|
After Width: | Height: | Size: 433 KiB |
|
After Width: | Height: | Size: 66 KiB |
|
After Width: | Height: | Size: 26 KiB |
@@ -0,0 +1,218 @@
|
||||
# 1. Introduction
|
||||
## 1.1 Demo Function
|
||||
|
||||
This demo completes the following functions:
|
||||
|
||||
1. Provisioning an unprovisioned device and change it to a node.
|
||||
2. Binding the provisioner's Appkey to its own models.
|
||||
3. Sending messages to the node about the Appkey and the fast provisioning information.
|
||||
4. Getting the addresses of all the nodes in the fast provisioning network.
|
||||
5. Controlling the nodes by their group address.
|
||||
|
||||
**Note: The demo's functionality is similar to that of the EspBleMesh app.**
|
||||
|
||||
## 1.2 Node Composition
|
||||
|
||||
This demo has only one element, in which the following four models are implemented:
|
||||
|
||||
- The **Configuration Server** model is used to represent a mesh network configuration of a device.
|
||||
- The **Configuration Client** model is used to represent an element that can control and monitor the configuration of a node.
|
||||
- The **Generic OnOff Client** model controls a Generic OnOff Server via messages defined by the **Generic OnOff** model (turning on and off the lights in this demo).
|
||||
- The **Vendor Client** model is used to control the `fast_prov_server` state, which defines the fast provisioning behavior of a node.
|
||||
|
||||
**Note: For detailed information about these models, please refer to other BLE Mesh demos.**
|
||||
|
||||
## 2. Code Analysis
|
||||
|
||||
Code initialization part reference [Initializing the Bluetooth and Initializing the BLE Mesh](../../../ble_mesh_wifi_coexist/tutorial%20%20%20%20%20%20/ble_mesh_wifi_coexist.md)
|
||||
|
||||
### 2.1 Data Structure
|
||||
|
||||
`example_prov_info_t` is used to define the keys, the address range can be assigned by a node, and the maximum number of nodes supported by the mesh network.
|
||||
|
||||
| Name |Description |
|
||||
| ----------------------|------------------------- |
|
||||
| `net_idx` | Netkey index value |
|
||||
| `app_idx` | AppKey index value |
|
||||
| `app_key[16]` | Appkey, which is used throughout the network |
|
||||
| `node_addr_cnt`| The maximum number of nodes supported in the mesh network,which serves the same purpose of the `Fast provisioning count` parameter in the EspBleMesh app|
|
||||
| `unicast_min` | Minimum unicast address to be assigned to the nodes in the mesh network |
|
||||
| `unicast_max` | Maximum unicast address to be assigned to the nodes in the mesh network |
|
||||
| `group_addr`| The group address, which is used to control the on/off state of all nodes in the mesh network, that is said, turning on and off the lights in this demo|
|
||||
| `match_val[16]`| The value used by the Fast Provisioning Provisioner to filter the devices to be provisioned |
|
||||
| `match_len` | The maximum length of `match_val[16]` |
|
||||
| `max_node_num` | The maximum number of nodes can be provisioned by the client |
|
||||
|
||||
### 2.2 Code Flow
|
||||
|
||||
The events and APIs in this section are presented in the same order with code execution.
|
||||
|
||||
### 2.2.1 Initialization
|
||||
|
||||
#### 2.2.1.1 Set the UUID Filter
|
||||
|
||||
The `esp_ble_mesh_provisioner_set_dev_uuid_match` API is called by the provisioner to set the part of the device UUID to be compared before starting to provision.
|
||||
|
||||
```
|
||||
/**
|
||||
* @brief This function is called by Provisioner to set the part of the device UUID
|
||||
* to be compared before starting to provision.
|
||||
*
|
||||
* @param[in] match_val: Value to be compared with the part of the device UUID.
|
||||
* @param[in] match_len: Length of the compared match value.
|
||||
* @param[in] offset: Offset of the device UUID to be compared (based on zero).
|
||||
* @param[in] prov_after_match: Flag used to indicate whether provisioner should start to provision
|
||||
* the device immediately if the part of the UUID matches.
|
||||
*
|
||||
* @return ESP_OK on success or error code otherwise.
|
||||
*
|
||||
*/
|
||||
esp_err_t esp_ble_mesh_provisioner_set_dev_uuid_match(const uint8_t *match_val, uint8_t match_len,
|
||||
uint8_t offset, bool prov_after_match);
|
||||
```
|
||||
|
||||
```c
|
||||
err = esp_ble_mesh_provisioner_set_dev_uuid_match(match, 0x02, 0x00, false);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "%s: Failed to set matching device UUID", __func__);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### 2.2.1.2 Add local Appkey
|
||||
|
||||
The provisioner has no Appkey right after it has been initialized. Therefore, you have to add a local Appkey for the provisioner by calling the `esp_ble_mesh_provisioner_add_local_app_key`.
|
||||
|
||||
```c
|
||||
err = esp_ble_mesh_provisioner_add_local_app_key(prov_info.app_key, prov_info.net_idx, prov_info.app_idx);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "%s: Failed to add local application key", __func__);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
```
|
||||
Please check the return value of the API calling and the return value of `ESP_BLE_MESH_PROVISIONER_ADD_LOCAL_APP_KEY_COMP_EVT`, and make sure that the Appkey has been added to this provisioner.
|
||||
|
||||
#### 2.2.1.3 Bind Appkey to local model
|
||||
|
||||
To control the server model, the client model uses messages to control the server model and these message must be encrypted by the Appkey. To that end, users must bind the Appkey of the provisioner to its local models, which are the **Generic OnOff Client** model and the **Vendor Client** model, by calling the `esp_ble_mesh_provisioner_add_local_app_key` api.
|
||||
|
||||
```c
|
||||
prov_info.app_idx = param->provisioner_add_app_key_comp.app_idx;
|
||||
err = esp_ble_mesh_provisioner_bind_app_key_to_local_model(PROV_OWN_ADDR, prov_info.app_idx,
|
||||
ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_CLI, CID_NVAL);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "%s: Failed to bind AppKey with OnOff Client Model", __func__);
|
||||
return;
|
||||
}
|
||||
err = esp_ble_mesh_provisioner_bind_app_key_to_local_model(PROV_OWN_ADDR, prov_info.app_idx,
|
||||
ESP_BLE_MESH_VND_MODEL_ID_FAST_PROV_CLI, CID_ESP);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "%s: Failed to bind AppKey with Fast Prov Client Model", __func__);
|
||||
return;
|
||||
}
|
||||
```
|
||||
Please check the return value of the API calling and the return value of the `ESP_BLE_MESH_PROVISIONER_ADD_LOCAL_APP_KEY_COMP_EVT` event, and make sure that the Appkey has been binded to the local models.
|
||||
|
||||
|
||||
### 2.2.2 Provisioning a device
|
||||
|
||||
The unprovisioned devices continuously send the **Unprovisioned Device** beacon, which contains the value of its UUID.
|
||||
|
||||
* If the UUID matched, a `ESP_BLE_MESH_PROVISIONER_RECV_UNPROV_ADV_PKT_EVT` event will be triggered, which will add the unprovisioned device information to the queue of to-be-provisioned devices.
|
||||
|
||||
```c
|
||||
err = esp_ble_mesh_provisioner_add_unprov_dev(&add_dev, flag);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "%s: Failed to start provisioning a device", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!reprov) {
|
||||
if (prov_info.max_node_num) {
|
||||
prov_info.max_node_num--;
|
||||
}
|
||||
}
|
||||
```
|
||||
* If not, this device will be ignored.
|
||||
|
||||
After that, all the devices in the queue will be provisioned automatically.
|
||||
|
||||
### 2.2.3 Sending cache data
|
||||
|
||||
Appkey is among the cache required for this node to become a provisioner.
|
||||
|
||||
When the provisioning completes, an `ESP_BLE_MESH_PROVISIONER_PROV_COMPLETE_EVT` event will be triggered, which will add the Appkey to the node's **Config Server** model by calling the `esp_ble_mesh_config_client_set_state` API:
|
||||
|
||||
```c
|
||||
common.opcode = ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD;
|
||||
common.model = model;
|
||||
common.ctx.net_idx = info->net_idx;
|
||||
common.ctx.app_idx = 0x0000; /* not used for config messages */
|
||||
common.ctx.addr = info->dst;
|
||||
common.ctx.send_rel = false;
|
||||
common.ctx.send_ttl = 0;
|
||||
common.msg_timeout = info->timeout;
|
||||
common.msg_role = info->role;
|
||||
|
||||
return esp_ble_mesh_config_client_set_state(&common, &set);
|
||||
```
|
||||
|
||||
* If API calling succeeds, an `ESP_BLE_MESH_CFG_CLIENT_SET_STATE_EVT` event will be triggered, which sends other cache information (`example_fast_prov_info_set_t`) to the node's **Vendor Server** model by calling the `example_send_fast_prov_info_set` function;
|
||||
* If API calling (`example_send_fast_prov_info_set`) succeeded, a message with an opcode of `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET` will be sent, whose acknowledgement (with an opcode of `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_STATUS`) will further trigger an `ESP_BLE_MESH_MODEL_OPERATION_EVT` event
|
||||
```c
|
||||
err = example_send_fast_prov_info_set(fast_prov_client.model, &info, &set);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "%s: Failed to set Fast Prov Info Set message", __func__);
|
||||
return;
|
||||
}
|
||||
```
|
||||
* If API calling (`example_send_fast_prov_info_set`) times out, an `ESP_BLE_MESH_CLIENT_MODEL_SEND_TIMEOUT_EVT` event will be triggered.
|
||||
* If API calling times out, an `ESP_BLE_MESH_CFG_CLIENT_TIMEOUT_EVT` event is triggered.
|
||||
|
||||
After that, this node has the ability to provisioning other nodes as a provisioner, and further controls other nodes.
|
||||
|
||||
**Note: The message with an opcode of `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET` contains the group address of all the nodes. When a node receives this message, it will automatically subscribe the Onoff Server model of this address.**
|
||||
|
||||
### 2.2.4 Controlling the node
|
||||
|
||||
When the `ESP_BLE_MESH_MODEL_OPERATION_EVT` event is triggered, the provisioner starts a timer.
|
||||
|
||||
```c
|
||||
ESP_LOG_BUFFER_HEX("fast prov info status", data, len);
|
||||
#if !defined(CONFIG_BT_MESH_FAST_PROV)
|
||||
prim_prov_addr = ctx->addr;
|
||||
k_delayed_work_init(&get_all_node_addr_timer, example_get_all_node_addr);
|
||||
k_delayed_work_submit(&get_all_node_addr_timer, GET_ALL_NODE_ADDR_TIMEOUT);
|
||||
#endif
|
||||
break;
|
||||
```
|
||||
After the timers times out, the provisioner starts to get the addresses of all nodes in the mesh network by calling the `example_send_fast_prov_all_node_addr_get` function, which sends a message with an opcode of `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_GET`.
|
||||
|
||||
```c
|
||||
err = example_send_fast_prov_all_node_addr_get(model, &info);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "%s: Failed to send Fast Prov Node Address Get message", __func__);
|
||||
return;
|
||||
}
|
||||
```
|
||||
|
||||
After that, the provisioner will receive an acknowledgement, which is a message with an opcode of `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_STATUS`, which triggers the `ESP_BLE_MESH_MODEL_OPERATION_EVT` event.
|
||||
|
||||
Then, the provisioner is able to turn on all the nodes (which are lights in this demo) by calling the `example_send_generic_onoff_set` function using the group address.
|
||||
|
||||
```c
|
||||
example_msg_common_info_t info = {
|
||||
.net_idx = node->net_idx,
|
||||
.app_idx = node->app_idx,
|
||||
.dst = node->group_addr,
|
||||
.timeout = 0,
|
||||
.role = ROLE_PROVISIONER,
|
||||
};
|
||||
err = example_send_generic_onoff_set(cli_model, &info, LED_ON, 0x00, false);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "%s: Failed to send Generic OnOff Set Unack message", __func__);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,93 @@
|
||||
# Demo Function
|
||||
|
||||
This demo demonstrates the fast provisioning of ESP BLE Mesh network and how to use the EspBleMesh app to control an individual provisioned node or all the provisioned nodes.
|
||||
|
||||
A video of this demo can be seen
|
||||
[here](http://download.espressif.com/BLE_MESH/BLE_Mesh_Demo/V0.4_Demo_Fast_Provision/ESP32_BLE_Mesh_Fast_Provision.mp4)
|
||||
|
||||
# What You Need
|
||||
|
||||
* [EspBleMesh App for Android](http://download.espressif.com/BLE_MESH/BLE_Mesh_Tools/BLE_Mesh_App/EspBleMesh-0.9.4.apk)
|
||||
* [ESP BLE Mesh SDK v0.6(Beta Version)](https://glab.espressif.cn/ble_mesh/esp-ble-mesh-v0.6)
|
||||
* ESP32 Development Boards
|
||||
|
||||
> Note:
|
||||
>
|
||||
> 1. Please flash the [`ble_mesh_fast_prov_server`](https://glab.espressif.cn/ble_mesh/esp-ble-mesh-v0.6/tree/ble_mesh_release/esp-ble-mesh-v0.6/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server) to your boards first;
|
||||
> 2. To have a better understanding of the performance of the BLE Mesh network, we recommend that at least 3 devices should be added in your network.
|
||||
> 3. We recommend that you solder LED indicators if your development board does not come with lights.
|
||||
> 4. Please check the type of board and LED pin definition enabled in `Example BLE Mesh Config` by running `make menuconfig`
|
||||
|
||||

|
||||
|
||||
|
||||
# Flash and Monitor
|
||||
|
||||
1. Enter the directory:
|
||||
examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server
|
||||
2. Make sure that the `IDF_PATH` environment variable was set in accordance with your current IDF path
|
||||
3. Check the version of your toolchain. Version 4.1 or newer should be used.
|
||||
|
||||

|
||||
|
||||
4. Run `make -j4 flash` to compile codes and flash the codes to the device.
|
||||
|
||||

|
||||
|
||||
> Note:
|
||||
>
|
||||
> Please click on the Exit button if you see the following windows.
|
||||
|
||||
|
||||
5. Please establish a connection between your device and PC, using the correct serial number, if you want to monitor the operation of this device on PC.
|
||||
|
||||
# How to Use the App
|
||||
|
||||
Please launch the `EspBleMesh` app, and follow the steps described below to establish a BLE Mesh network and control any individual node or all the nodes.
|
||||
|
||||

|
||||
1. Click on the upper left corner to see more options;
|
||||
2. Click on **Provisioning** to scan nearby unprovisioned devices;
|
||||
3. Choose any unprovisioned devices in the scanned list;
|
||||
4. Enter the number of devices you want to add in your mesh network;
|
||||
> Note:
|
||||
>
|
||||
> If you only want to use the normal provisioning feature,You don't check the option for fast provisioning.
|
||||
5. Wait until all the devices are provisioned;
|
||||
6. Click on the upper left corner to see more options;
|
||||
7. Click on **Fast Provisioned** to see all the provisioned devices;
|
||||
8. Control your devices.
|
||||
|
||||
> Note:
|
||||
>
|
||||
> Please disable your Bluetooth function on your phone, enable it and try again, if you have encountered any connection issues.
|
||||
|
||||
|
||||
# Procedure
|
||||
|
||||
## Role
|
||||
|
||||
* Phone - Top Provisioner
|
||||
* The device that has been provisioned by Phone - Primary Provisioner
|
||||
* Devices that have been provisioned and changed to the role of a provisioner - Temporary Provisioner
|
||||
* Devices that have been provisioned but not changed to the role of a provisioner - Node
|
||||
|
||||
## Interaction
|
||||
|
||||

|
||||
1. The Top Provisioner configures the first device to access the network with the GATT bearer.
|
||||
2. The Top Provisioner sends the `send_config_appkey_add` message to allocate the Appkey to this device.
|
||||
3. The Top Provisioner sends the `send_fast_prov_info_set` message to provide the necessary information so the device can be changed to a Primary Provisioner.
|
||||
4. The device calls the `esp_ble_mesh_set_fast_prov_action` API to change itself into the role of a Primary Provisioner and disconnects with the Top Provisioner.
|
||||
5. The Primary Provisioner sends the `send_config_appkey_add` message to allocate the Appkey to an other device.
|
||||
6. The Primary Provisioner sends the `send_fast_prov_info_set` message to provide the necessary information so the device can be changed to a Temporary Provisioner.
|
||||
7. The device calls the `esp_ble_mesh_set_fast_prov_action` API to change itself into the role of a Temporary Provisioner and starts its address timer.
|
||||
8. The Temporary Provisioner collects the addresses of nodes that it has provisioned and sends these addresses to the Primary Provisioner, when its address timer times out, which indicates the Temporary Provisioner hasn't provisioned any devices for 10s.
|
||||
9. The Primary Provisioner reconnects to the Top Provisioner when its address timer times out, which indicates the Primary Provisioner hasn't received any messages from the Temporary Provisioners for 10s.
|
||||
10. The Top Provisioner sends the `node_adress_Get` message automatically after reconnecting with the Primary Provisioner.
|
||||
11. At this point, the Top Provisioner is able to control any nodes in the BLE Mesh Network.
|
||||
|
||||
> Note:
|
||||
>
|
||||
> The nodes in the BLE Mesh Network only disable its provisioner functionality after it has been controlled by the Top Provisioner for at least one time.
|
||||
|
||||
@@ -0,0 +1,409 @@
|
||||
# 1. Introduction
|
||||
## 1.1 Demo Function
|
||||
|
||||
This demo is used for fast provisioning networks. It takes no more than 60 seconds to provisioning 100 devices in this demo.
|
||||
|
||||
This demo must be used with the EspBleMesh app. For details about how to use the EspBleMesh app, please click [here](EspBleMesh.md).
|
||||
|
||||
## 1.2 Node Composition
|
||||
|
||||
This demo has only one element, where the following five Models are implemented:
|
||||
|
||||
- The **Configuration Server** Model is used to represent a mesh network configuration of a device.
|
||||
- The **Configuration Client** Model is used to represent an element that can control and monitor the configuration of a node.
|
||||
- The **Generic OnOff Server** Model implements the node's Onoff state.
|
||||
- The **Vendor Server** Model implements the node's `fast_prov_server` state.
|
||||
- The **Vendor Client** Model is used to control the `fast_prov_server` state, which defines the fast provisioning behavior of a node.
|
||||
|
||||
|
||||
## 2. Code Analysis
|
||||
|
||||
Code initialization part reference [Initializing the Bluetooth and Initializing the BLE Mesh](../../../ble_mesh_wifi_coexist/tutorial%20%20%20%20%20%20/ble_mesh_wifi_coexist.md)
|
||||
|
||||
### 2.1 Data Structure
|
||||
|
||||
This section introduces the `example_fast_prov_server_t` strut for this demo, and its variables in groups.
|
||||
|
||||
```
|
||||
typedef struct {
|
||||
esp_ble_mesh_model_t *model; /* Fast Prov Server Model pointer */
|
||||
ATOMIC_DEFINE(srv_flags, SRV_MAX_FLAGS);
|
||||
|
||||
bool primary_role; /* Indicate if the device is a Primary Provisioner */
|
||||
uint8_t max_node_num; /* The maximum number of devices can be provisioned by the Provisioner */
|
||||
uint8_t prov_node_cnt; /* Number of self-provisioned nodes */
|
||||
uint16_t app_idx; /* AppKey index of the application key added by other Provisioner */
|
||||
uint16_t top_address; /* Address of the device(e.g. phone) which triggers fast provisioning */
|
||||
|
||||
esp_ble_mesh_msg_ctx_t ctx; /* the context stored for sending fast prov status message */
|
||||
struct fast_prov_info_set *set_info; /* Used to store received fast prov info set context */
|
||||
|
||||
uint16_t node_addr_cnt; /* Number of node address shall be received */
|
||||
uint16_t unicast_min; /* Minimum unicast address can be send to other nodes */
|
||||
uint16_t unicast_max; /* Maximum unicast address can be send to other nodes */
|
||||
uint16_t unicast_cur; /* Current unicast address can be assigned */
|
||||
uint16_t unicast_step; /* Unicast address change step */
|
||||
uint8_t flags; /* Flags state */
|
||||
uint32_t iv_index; /* Iv_index state */
|
||||
uint16_t net_idx; /* Netkey index state */
|
||||
uint16_t group_addr; /* Subscribed group address */
|
||||
uint16_t prim_prov_addr; /* Unicast address of Primary Provisioner */
|
||||
uint8_t match_val[16]; /* Match value to be compared with unprovisioned device UUID */
|
||||
uint8_t match_len; /* Length of match value to be compared */
|
||||
|
||||
uint8_t pend_act; /* Pending action to be performed */
|
||||
uint8_t state; /* Fast prov state -> 0: idle, 1: pend, 2: active */
|
||||
|
||||
struct k_delayed_work disable_fast_prov_timer; /* Used to disable fast provisioning */
|
||||
struct k_delayed_work send_all_node_addr_timer; /* Used to send all node addresses to top provisioner(e.g. phone) */
|
||||
} __attribute__((packed)) example_fast_prov_server_t;
|
||||
```
|
||||
|
||||
|
||||
#### 2.1.1 Provisioner Role and State
|
||||
|
||||
Different provisioners have different behaviors and it’s helpful to understand the concepts of different roles so you can better understand the codes.
|
||||
|
||||
In the struct, there are three variables that are related to roles and states, which are described in the following table:
|
||||
|
||||
| Variable Name |Description |
|
||||
| ---------------------|------------------------- |
|
||||
| `primary_role` | Provisioner identity |
|
||||
| `state` | Fast provisioner state (0: idle, 1: pend, 2: active) |
|
||||
| `srv_flags` | Flags (`DISABLE_FAST_PROV_START`,`SEND_ALL_NODE_ADDR_START`,`RELAY_PROXY_DISABLED`,`SRV_MAX_FLAGS`) |
|
||||
|
||||
Among which, there are four roles in this demo (`primary_role`):
|
||||
|
||||
* Phone - Top Provisioner
|
||||
* The device that has been provisioned by Phone - Primary Provisioner
|
||||
* Devices that have been provisioned and changed to the role of a provisioner - Temporary Provisioner
|
||||
* Devices that have been provisioned but not changed to the role of a provisioner - Node
|
||||
|
||||
|
||||
#### 2.1.2 Provisioner Address Management
|
||||
|
||||
The provisioner address management is used to assign a unicast address to each node, so as to prevent address conflicts by allocating address in an equally manner. Each provisioner has its own address range and a maximum number of the nodes it can provisioned. The provisioner will allocate a subset of its address range to the nodes it has provisioned.
|
||||
|
||||
Example: A top provisioner's address range is 0 to 100 and the maximum number of nodes it can provisioned is 5. The provisioner address management will assign subsets of address range to these 5 nodes, which are 1 to 20, 21 to 40, 41 to 60, 61 to 80 and 81 to 100.
|
||||
|
||||
The variables that are related to the address management are described in the following table:
|
||||
|
||||
| Variable Name |Description |
|
||||
| ----------------------|------------------------- |
|
||||
| `unicast_min` | Minimum unicast address can be allocated to other nodes |
|
||||
| `unicast_max` | Maximum unicast address can be allocated to other nodes |
|
||||
| `unicast_cur` | Current unicast address |
|
||||
| `unicast_step` | Unicast address change step Offset|
|
||||
|
||||
#### 2.1.3 Provisioner Cache Data
|
||||
|
||||
The cache data is required, so a node can change its role to become a provisioner. During this process, the `esp_ble_mesh_set_fast_prov_info` and `esp_ble_mesh_set_fast_prov_action` APIs are called.
|
||||
|
||||
The node's cache data, which are described in the following table, is sent by the provisioner.
|
||||
|
||||
| Variable Name |Description |
|
||||
| ----------------------|------------------------- |
|
||||
| `flags` |Flags state|
|
||||
| `iv_index` |Iv_index state|
|
||||
| `net_idx` |Netkey index state |
|
||||
| `group_addr` |Subscribed group address |
|
||||
| `prim_prov_addr` |Unicast address of Primary Provisioner |
|
||||
| `match_val[16]` |Match value to be compared with unprovisioned device UUID |
|
||||
| `match_len` | Length of match value to be compared |
|
||||
| `max_node_num` | The maximum number of devices can be provisioned by the Provisioner |
|
||||
| `prov_node_cnt` | Number of self-provisioned nodes |
|
||||
| `app_idx` | AppKey index of the application key added by other Provisioner |
|
||||
| `top_address` | Address of the device(e.g. phone) which triggers fast provisioning |
|
||||
|
||||
|
||||
#### 2.1.4 Provisioner Timer
|
||||
|
||||
There are two timers in this demo, which are:
|
||||
|
||||
1. `send_all_node_addr_timer` is used to collect the addresses of all nodes.
|
||||
* The timer starts or resets and starts when a Temporary Provisioner provisions an unprovisioned device.
|
||||
* The Temporary Provisioner will send a message (Address information) to the Primary Provisioner.
|
||||
2. `disable_fast_prov_timer` is used to disable the provisioning capabilities.
|
||||
* The node starts the timer when it receives a **Generic OnOff Get/Set/Set Unack** message sent by the EspBleMesh app. The group address should be used if you want to disable the provisioning capabilities of all nodes.
|
||||
|
||||
The variables that are related to these two timers are described below:
|
||||
|
||||
| Variable Name |Description |
|
||||
| ----------------------|------------------------- |
|
||||
| `disable_fast_prov_timer` |Used to disable fast provisioning|
|
||||
| `send_all_node_addr_timer` |Used to send all node addresses to top provisioner|
|
||||
|
||||
### 2.2 Model Definition
|
||||
|
||||
#### 2.2.1 Vendor Server Model
|
||||
|
||||
The **Vendor Server** Model implements the node's `fast_prov_server` state, which has been covered in the previous section.
|
||||
|
||||
```c
|
||||
example_fast_prov_server_t fast_prov_server = {
|
||||
.primary_role = false,
|
||||
.max_node_num = 6,
|
||||
.prov_node_cnt = 0x0,
|
||||
.unicast_min = ESP_BLE_MESH_ADDR_UNASSIGNED,
|
||||
.unicast_max = ESP_BLE_MESH_ADDR_UNASSIGNED,
|
||||
.unicast_cur = ESP_BLE_MESH_ADDR_UNASSIGNED,
|
||||
.unicast_step = 0x0,
|
||||
.flags = 0x0,
|
||||
.iv_index = 0x0,
|
||||
.net_idx = ESP_BLE_MESH_KEY_UNUSED,
|
||||
.app_idx = ESP_BLE_MESH_KEY_UNUSED,
|
||||
.group_addr = ESP_BLE_MESH_ADDR_UNASSIGNED,
|
||||
.prim_prov_addr = ESP_BLE_MESH_ADDR_UNASSIGNED,
|
||||
.match_len = 0x0,
|
||||
.pend_act = FAST_PROV_ACT_NONE,
|
||||
.state = STATE_IDLE,
|
||||
};
|
||||
```
|
||||
|
||||
The `fast_prov_srv_op` is used to register the minimum length of messages. For example, the minimum length of the `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET` message is registered as 3 octets.
|
||||
|
||||
```c
|
||||
static esp_ble_mesh_model_op_t fast_prov_srv_op[] = {
|
||||
{ ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET, 3, NULL },
|
||||
{ ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_ADD, 16, NULL },
|
||||
{ ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR, 2, NULL },
|
||||
{ ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_GET, 0, NULL },
|
||||
ESP_BLE_MESH_MODEL_OP_END,
|
||||
};
|
||||
|
||||
```
|
||||
The `example_fast_prov_server_init` function is used to register the callback function triggered when the timers timeout, and initializes the Model-related variables in the data struct.
|
||||
|
||||
```c
|
||||
err = example_fast_prov_server_init(&vnd_models[0]);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "%s: Failed to initialize fast prov server model", __func__);
|
||||
return err;
|
||||
}
|
||||
```
|
||||
|
||||
The `fast_prov_server` struct represents the Vendor server's states. The `CID_ESP` and `ESP_BLE_MESH_VND_MODEL_ID_FAST_PROV_SRV` constants, which consist of the vendor server Model's Model id `ESP_BLE_MESH_VND_MODEL_ID_FAST_PROV_SRV`, are used to identity the Vendor server Model.
|
||||
|
||||
|
||||
```c
|
||||
static esp_ble_mesh_model_t vnd_models[] = {
|
||||
ESP_BLE_MESH_VENDOR_MODEL(CID_ESP, ESP_BLE_MESH_VND_MODEL_ID_FAST_PROV_SRV,
|
||||
fast_prov_srv_op, NULL, &fast_prov_server),
|
||||
};
|
||||
static esp_ble_mesh_elem_t elements[] = {
|
||||
ESP_BLE_MESH_ELEMENT(0, root_models, vnd_models),
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
#### 2.2.2 Vendor Client Model
|
||||
|
||||
The **Vendor Client** Model is used to control the `fast_prov_server` state, which defines the fast provisioning behavior of a node.
|
||||
|
||||
The `fast_prov_cli_op_pair` struct is used to register the corresponding message acknowledgements.
|
||||
|
||||
```c
|
||||
static const esp_ble_mesh_client_op_pair_t fast_prov_cli_op_pair[] = {
|
||||
{ ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET, ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_STATUS },
|
||||
{ ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_ADD, ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_STATUS },
|
||||
{ ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR, ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_ACK },
|
||||
{ ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_GET, ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_STATUS },
|
||||
};
|
||||
```
|
||||
|
||||
Example: The **Vendor Client** Model sends message with an opcode of `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET`, which requires the **Vendor Server** Model to respond with a message with an opcode of `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_STATUS`. After that, the **Vendor Client** Model times out if it receives no corresponding acknowledgement.
|
||||
|
||||
```c
|
||||
static const esp_ble_mesh_client_op_pair_t fast_prov_cli_op_pair[] = {
|
||||
{ ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET, ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_STATUS },
|
||||
};
|
||||
```
|
||||
Note that you can also use the code below if you don't want the **Vendor Client** Model to wait for acknowledgement from the server Model, which means the client Model will never time out.
|
||||
|
||||
```c
|
||||
static const esp_ble_mesh_client_op_pair_t fast_prov_cli_op_pair[] = {
|
||||
{ ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET, NULL },
|
||||
};
|
||||
```
|
||||
|
||||
The `esp_ble_mesh_client_model_init` API is used to register the callback function triggered when the timers timeout, and initializes the Model-related variables in the data struct.
|
||||
|
||||
```c
|
||||
err = esp_ble_mesh_client_model_init(&vnd_models[1]);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "%s: Failed to initialize fast prov client Model", __func__);
|
||||
return err;
|
||||
}
|
||||
```
|
||||
|
||||
The `CID_ESP` and `ESP_BLE_MESH_VND_MODEL_ID_FAST_PROV_CLI` constants, which consist of the vendor client Model's Model id `ESP_BLE_MESH_VND_MODEL_ID_FAST_PROV_CLI`, are used to identity the Vendor client Model.
|
||||
|
||||
```c
|
||||
|
||||
esp_ble_mesh_client_t fast_prov_client = {
|
||||
.op_pair_size = ARRAY_SIZE(fast_prov_cli_op_pair),
|
||||
.op_pair = fast_prov_cli_op_pair,
|
||||
};
|
||||
|
||||
static esp_ble_mesh_model_op_t fast_prov_cli_op[] = {
|
||||
{ ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_STATUS, 1, NULL },
|
||||
{ ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_STATUS, 2, NULL },
|
||||
{ ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_ACK, 0, NULL },
|
||||
ESP_BLE_MESH_MODEL_OP_END,
|
||||
};
|
||||
|
||||
static esp_ble_mesh_model_t vnd_models[] = {
|
||||
ESP_BLE_MESH_VENDOR_MODEL(CID_ESP, ESP_BLE_MESH_VND_MODEL_ID_FAST_PROV_CLI,
|
||||
fast_prov_cli_op, NULL, &fast_prov_client),
|
||||
};
|
||||
static esp_ble_mesh_elem_t elements[] = {
|
||||
ESP_BLE_MESH_ELEMENT(0, root_models, vnd_models),
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## 2.3 Message Opcode
|
||||
|
||||
"Opcode-send" represents the message that the client sends to the server.
|
||||
|
||||
"Opcode-ack" represents the message that the server sends to the client.
|
||||
|
||||
* INFO_SET
|
||||
|
||||
|Meaning | Opcode-send | Opcode-ack |
|
||||
| -----| ------------- | -------------|
|
||||
|Opcode| `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET` | `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_STATUS` |
|
||||
|Function| This message contains all the information as a Provisioner |Checks each field of the Provisioner information and set the corresponding flag bit. The returned status is variable.|
|
||||
|Parameter|structfast_prov_info_set|status_bit_mask, status_ctx_flag, status_unicast, status_net_idx, status_group, status_pri_prov, status_match, status_action|
|
||||
|
||||
|
||||
* NODE_ADDR
|
||||
|
||||
|Meaning | Opcode-send | Opcode-ack |
|
||||
| -----| ------------- | -------------|
|
||||
|Opcode| `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR` | `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_ACK` |
|
||||
|Function| Temporary Provisioner reports the address of the node it has provisioned. |Used to check if the message was sent successfully. |
|
||||
|Parameter| Address array |NA |
|
||||
|
||||
* ADDR_GET
|
||||
|
||||
|Meaning | Opcode-send | Opcode-ack |
|
||||
| -----| ------------- | -------------|
|
||||
|Opcode| `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_GET` | `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_STATUS` |
|
||||
|Function|Top Provisioner gets the address of all nodes obtained from Primary Provisioner. | Returns the address of all nodes, but does not contain its own. |
|
||||
|Parameter|NA |Address array |
|
||||
|
||||
* NET_KEY_ADD
|
||||
|
||||
|Meaning | Opcode-send | Opcode-ack |
|
||||
| -----| ------------- | -------------|
|
||||
|Opcode | `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_ADD` | `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_STATUS` |
|
||||
|Function| Reserved for later use | Reserved for later use |
|
||||
|Parameter| NA | NA |
|
||||
|
||||
|
||||
### 2.4 Callback Function
|
||||
#### 2.4.1 The Callback function for the Vendor Server Model
|
||||
|
||||
```c
|
||||
esp_ble_mesh_register_custom_model_callback(example_ble_mesh_custom_model_cb);
|
||||
esp_ble_mesh_register_prov_callback(example_ble_mesh_provisioning_cb);
|
||||
```
|
||||
|
||||
1. The callback function will be triggered when the **Vendor Server** Model:
|
||||
* Receives a message that indicates the Onoff state of the client Model; or
|
||||
* Calls any APIs that send messages.
|
||||
|
||||
2. The events that this callback function handle:
|
||||
|
||||
* Generic Onoff Server Model
|
||||
|
||||
| Event Name | Opcode |Description |
|
||||
| ------------- | ------------|------------------------------------------- |
|
||||
| ESP_BLE_MESH_MODEL_OPERATION_EVT|ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET | This event is triggered when the **Generic Onoff Server** model receives the `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET` message |
|
||||
| ESP_BLE_MESH_MODEL_OPERATION_EVT|ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK| This event is triggered when the **Generic Onoff Server** model receives the `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK` message. |
|
||||
|
||||
* Vendor Server Model
|
||||
|
||||
| Event Name | Opcode |Description |
|
||||
| ------------- | ------------|------------------------------------------- |
|
||||
| ESP_BLE_MESH_MODEL_OPERATION_EVT | ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET | This event is triggered when the **Vendor Server** model receives the `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET` message.|
|
||||
| ESP_BLE_MESH_MODEL_OPERATION_EVT | ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR | This event is triggered when the **Vendor Server** model receives the `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR` message.|
|
||||
| ESP_BLE_MESH_MODEL_OPERATION_EVT | ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_GET | This event is triggered when the **Vendor Server** model receives the `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_GET` message.|
|
||||
|
||||
* The **Configuration Client** Model
|
||||
|
||||
| Event Name | Opcode |Description |
|
||||
| ------------- | ------------|------------------------------------------- |
|
||||
|ESP_BLE_MESH_SET_FAST_PROV_INFO_COMP_EVT| NA| This event is triggered when the `esp_ble_mesh_set_fast_prov_info` API is called. |
|
||||
|ESP_BLE_MESH_SET_FAST_PROV_ACTION_COMP_EVT| NA| This event is triggered when the `esp_ble_mesh_set_fast_prov_action` API is called. |
|
||||
|ESP_BLE_MESH_CFG_CLIENT_SET_STATE_EVT|ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD|This event is triggered when the **Configuration Server** model receives and further triggers an API calling to send `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET` message. |
|
||||
|ESP_BLE_MESH_CFG_CLIENT_TIMEOUT_EVT|ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD|This event is triggered when the API `example_send_config_appkey_add` times out.|
|
||||
|
||||
#### 2.4.2 The Vendor Client Model
|
||||
|
||||
```c
|
||||
esp_ble_mesh_register_custom_model_callback(example_ble_mesh_custom_model_cb);
|
||||
```
|
||||
|
||||
1. The callback function will be triggered when the **Vendor Client** model:
|
||||
* Receives any message sent by the vendor server Model; or
|
||||
* Calls any APIs that send messages.
|
||||
|
||||
2. The events that this callback function handle:
|
||||
|
||||
| Event Name | Opcode |Description |
|
||||
| ------------- | ------------|------------------------------------------- |
|
||||
| ESP_BLE_MESH_MODEL_OPERATION_EVT | ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_STATUS | This event is triggered when the **Vendor Client** model receives the `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_STATUS` message.|
|
||||
| ESP_BLE_MESH_MODEL_OPERATION_EVT | ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_STATUS | This event is triggered when the **Vendor Client** model receives the `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_STATUS` message.|
|
||||
| ESP_BLE_MESH_MODEL_OPERATION_EVT | ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_ACK | This event is triggered when the **Vendor Client** model receives the `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_ACK` message |
|
||||
| ESP_BLE_MESH_CLIENT_MODEL_SEND_TIMEOUT_EVT | client_send_timeout.opcode | This event is triggered when the API `esp_ble_mesh_client_model_send_msg` times out.|
|
||||
|
||||
### 2.5 Message Sending
|
||||
#### 2.5.1 The Vendor Client sends messages
|
||||
|
||||
The Vendor Client Model calls the `esp_ble_mesh_client_model_send_msg` API to send messages to the Vendor Server Model.
|
||||
|
||||
| Parameter Name |Description |
|
||||
| ----------------------|------------------------- |
|
||||
| `model` | The pointer to the client Model struct |
|
||||
| `ctx.net_idx` | The NetKey Index of the subnet through which the message is sent |
|
||||
| `ctx.app_idx` | The AppKey Index for the message encryption |
|
||||
| `ctx.addr` | The address of the destination nodes |
|
||||
| `ctx.send_ttl`| The TTL State, which determines how many times a message can be relayed|
|
||||
| `ctx.send_rel`| This parameter determines whether the Model will wait for an acknowledgment after sending a message |
|
||||
| `opcode` | The message opcode |
|
||||
| `msg->len` | The length of the `msg->data`|
|
||||
| `msg->data` | The pointer to sent data|
|
||||
| `msg_timeout` | The maximum duration (4000 ms by default) that the Model waits for an acknowledgment. |
|
||||
|`true` | True: an acknowledgement is required; False: no acknowledgement is required |
|
||||
| `msg_role` | The role of a message (node/provisioner) |
|
||||
|
||||
```c
|
||||
esp_ble_mesh_msg_ctx_t ctx = {
|
||||
.net_idx = info->net_idx,
|
||||
.app_idx = info->app_idx,
|
||||
.addr = info->dst,
|
||||
.send_rel = false,
|
||||
.send_ttl = 0,
|
||||
};
|
||||
err = esp_ble_mesh_client_model_send_msg(model, &ctx,
|
||||
ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET,
|
||||
msg->len, msg->data, info->timeout, true, info->role);
|
||||
```
|
||||
|
||||
#### 2.5.2 The Vendor Server sends messages
|
||||
|
||||
The **Vendor Server** Model has to bind its Appkey before calling the `esp_ble_mesh_server_model_send_msg` API to send a message.
|
||||
|
||||
```c
|
||||
esp_ble_mesh_server_model_send_msg(model, ctx, ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_STATUS,
|
||||
msg->len ,msg->data );
|
||||
```
|
||||
The **Vendor Server** Model calls the `esp_ble_mesh_model_publish` API to publish messages. Only the Models that have subscribed to this destination address receive the published messages.
|
||||
|
||||
```c
|
||||
esp_err_t esp_ble_mesh_model_publish(esp_ble_mesh_model_t *model, uint32_t opcode,
|
||||
uint16_t length, uint8_t *data,
|
||||
esp_ble_mesh_dev_role_t device_role);
|
||||
```
|
||||
|
After Width: | Height: | Size: 178 KiB |
|
After Width: | Height: | Size: 348 KiB |
|
After Width: | Height: | Size: 71 KiB |
|
After Width: | Height: | Size: 68 KiB |
|
After Width: | Height: | Size: 56 KiB |
@@ -0,0 +1,301 @@
|
||||
# Introduction
|
||||
|
||||
This demo demonstrates the Wi-Fi and Bluetooth (BLE/BR/EDR) coexistence feature of ESP32. Simply put, users can use the Wi-Fi function while operating Bluetooth. In this demo,
|
||||
|
||||
* The Wi-Fi function is demonstrated by measuring its transfer rate, using the `iperf` protocol;
|
||||
* The Bluetooth function is demonstrated by the fast provisioning function. Details can be seen in `ble_mesh_fast_prov_server`.
|
||||
|
||||
|
||||
> Note: In this demo, you call wifi API and bluetooth API to achieve the functions you want. such as `wifi_get_local_ip` API and `esp_ble_mesh_provisioner_add_unprov_dev` API.
|
||||
|
||||
# What You Need
|
||||
|
||||
Download and flash the `ble_mesh_wifi_coexist` project to your ESP32 development board and then use the following commands to get started with this demo.
|
||||
|
||||
1. Connect your development board to the Wi-Fi network by entering the `sta ssid password` command in your serial port tool.
|
||||
- For example, you should enter `sta tset_wifi 12345678` if you want to connect your board to a network with a SSID of `tset_wifi` and a password of `12345678`.
|
||||
|
||||
2. Start a TCP server by entering the `iperf -s -i 3 -t 1000` command in your serial port tool, which prints the current transfer rate of the Wi-Fi network the board connects to.
|
||||
|
||||
3. Start a TCP client by entering the `iperf -c board_IP_address -i 3 -t 60` command in your PC terminal.
|
||||
- For example, you should enter `iperf -c 192.168.10.42 -i 3 -t 60`, if the IP address of your board is 192.168.10.42.
|
||||
|
||||
|
||||
Meanwhile, you can use the Bluetooth function during the whole process, for example, controlling the LED indicator on your board.
|
||||
|
||||
> Note:
|
||||
>
|
||||
> 1. Please use the correct serial port number for connecting your board when entering commands in your serial port tool;
|
||||
> 2. Your PC and board should connect to the same Wi-Fi network;
|
||||
|
||||
|
||||
# Project Directory
|
||||
|
||||
The `ble_mesh_wifi_coexist` demo contains the following files and subfolders:
|
||||
|
||||
```
|
||||
$ tree examples/bluetooth/ble_mesh/ble_mesh/ble_mesh_wifi_coexist
|
||||
├── main /* Stores the `.c` and `.h` application code files for this demo */
|
||||
├── components /* Stores the `.c` and `.h` iperf code files for this demo */
|
||||
├── Makefile /* Compiling parameters for the demo */
|
||||
├── README.md /* Quick start guide */
|
||||
├── build
|
||||
├── sdkconfig /* Current parameters of `make menuconfig` */
|
||||
├── sdkconfig.defaults /* Default parameters of `make menuconfig` */
|
||||
├── sdkconfig.old /* Previously saved parameters of `make menuconfig` */
|
||||
└── tutorial /* More in-depth information about the demo */
|
||||
```
|
||||
|
||||
The `main` folder mainly implements the BLE Mesh feature. Details can be seen in `ble_mesh_fast_prov_server`.
|
||||
|
||||
The `components` folder mainly implements the Wi-Fi feature, which allows some basic commands and `iperf-relared` test commands.
|
||||
|
||||
> Note:
|
||||
>
|
||||
> [Iperf](https://iperf.fr) is a tool for active measurements of the maximum achievable bandwidth on IP networks. It supports tuning of various parameters related to timing, buffers and protocols (TCP, UDP, SCTP with IPv4 and IPv6).
|
||||
|
||||
# Example Walkthrough
|
||||
|
||||
## Main Entry Point
|
||||
|
||||
The program’s entry point is the `app_main()` function.
|
||||
|
||||
## Initialization
|
||||
|
||||
The code block below first initialize the board, then its bluetooth-related functions (including the Bluetooth and BLE Mesh) and the Wi-Fi console.
|
||||
|
||||
```c
|
||||
void app_main(void)
|
||||
{
|
||||
esp_err_t err;
|
||||
|
||||
ESP_LOGI(TAG, "Initializing...");
|
||||
|
||||
err = board_init();
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "board_init failed (err %d)", err);
|
||||
return;
|
||||
}
|
||||
|
||||
err = bluetooth_init();
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "esp32_bluetooth_init failed (err %d)", err);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Initialize the Bluetooth Mesh Subsystem */
|
||||
err = ble_mesh_init();
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Bluetooth mesh init failed (err %d)", err);
|
||||
return;
|
||||
}
|
||||
|
||||
wifi_console_init();
|
||||
}
|
||||
```
|
||||
|
||||
### Initializing the Board
|
||||
|
||||
This demo calls the `board_init` function to:
|
||||
|
||||
1. First initialize three pins for the LED indicator, and set its initial status to OFF (i.e. initialize the `led_state[i].previous` variable to `LED_OFF`).
|
||||
|
||||
```c
|
||||
for (int i = 0; i < 3; i++) {
|
||||
gpio_pad_select_gpio(led_state[i].pin);
|
||||
gpio_set_direction(led_state[i].pin, GPIO_MODE_OUTPUT);
|
||||
gpio_set_level(led_state[i].pin, LED_OFF);
|
||||
led_state[i].previous = LED_OFF;
|
||||
}
|
||||
```
|
||||
|
||||
2. Create a task named `led_action_thread` for controlling the status of the light, and then a queue named `led_action_queue` for storing status data, whose format is defined in `struct _led_state`.
|
||||
|
||||
```c
|
||||
led_action_queue = xQueueCreate(60, sizeof(struct _led_state));
|
||||
ret = xTaskCreate(led_action_thread, "led_action_thread", 4096, NULL, 5, NULL);
|
||||
```
|
||||
|
||||
3. The `led_action_thread` task continuously sets the status of the LED indicator by calling the `gpio_set_level` function, using status data obtains data from the `led_action_queue` queue.
|
||||
|
||||
```c
|
||||
static void led_action_thread(void *arg)
|
||||
{
|
||||
struct _led_state led = {0};
|
||||
|
||||
while (1) {
|
||||
if (xQueueReceive(led_action_queue, &led, (portTickType)portMAX_DELAY)) {
|
||||
ESP_LOGI(TAG, "%s: pin 0x%04x onoff 0x%02x", __func__, led.pin, led.current);
|
||||
/* If the node is controlled by phone, add a delay when turn on/off led */
|
||||
if (fast_prov_server.primary_role == true) {
|
||||
vTaskDelay(50 / portTICK_PERIOD_MS);
|
||||
}
|
||||
gpio_set_level(led.pin, led.current);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Initializing the Bluetooth
|
||||
|
||||
This demo calls the `bluetooth_init` function to:
|
||||
|
||||
1. First initialize the non-volatile storage library, which allows saving key-value pairs in flash memory and is used by some components. You can save the node's keys and configuration information at `menuconfig` --> `Bluetooth Mesh support` --> `Store Bluetooth Mesh key and configuration persistently`:
|
||||
|
||||
```c
|
||||
esp_err_t ret = nvs_flash_init();
|
||||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
ret = nvs_flash_init();
|
||||
}
|
||||
ESP_ERROR_CHECK( ret );
|
||||
```
|
||||
|
||||
2. Initializes the BT controller by first creating a BT controller configuration structure named `esp_bt_controller_config_t` with default settings generated by the `BT_CONTROLLER_INIT_CONFIG_DEFAULT()` macro. The BT controller implements the Host Controller Interface (HCI) on the controller side, the Link Layer (LL) and the Physical Layer (PHY). The BT Controller is invisible to the user applications and deals with the lower layers of the BLE stack. The controller configuration includes setting the BT controller stack size, priority and HCI baud rate. With the settings created, the BT controller is initialized and enabled with the `esp_bt_controller_init()` function:
|
||||
|
||||
```c
|
||||
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
||||
ret = esp_bt_controller_init(&bt_cfg);
|
||||
```
|
||||
|
||||
Next, the controller is enabled in BLE Mode.
|
||||
|
||||
```c
|
||||
ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
|
||||
```
|
||||
The controller should be enabled in `ESP_BT_MODE_BTDM`, if you want to use the dual mode (BLE + BT). There are four Bluetooth modes supported:
|
||||
|
||||
* `ESP_BT_MODE_IDLE`: Bluetooth not running
|
||||
* `ESP_BT_MODE_BLE`: BLE mode
|
||||
* `ESP_BT_MODE_CLASSIC_BT`: BT Classic mode
|
||||
* `ESP_BT_MODE_BTDM`: Dual mode (BLE + BT Classic)
|
||||
|
||||
After the initialization of the BT controller, the Bluedroid stack, which includes the common definitions and APIs for both BT Classic and BLE, is initialized and enabled by using:
|
||||
|
||||
```c
|
||||
ret = esp_bluedroid_init();
|
||||
ret = esp_bluedroid_enable();
|
||||
```
|
||||
|
||||
### Initializing the BLE Mesh
|
||||
|
||||
This demo calls the `ble_mesh_init` function to:
|
||||
|
||||
1. Initialize the board's uuid by setting the `dev_uuid` variable, which is used to distinguish devices when provisioning.
|
||||
|
||||
```c
|
||||
static esp_err_t ble_mesh_init(void)
|
||||
{
|
||||
esp_err_t err;
|
||||
|
||||
/* First two bytes of device uuid is compared with match value by Provisioner */
|
||||
memcpy(dev_uuid + 2, esp_bt_dev_get_address(), 6);
|
||||
|
||||
esp_ble_mesh_register_prov_callback(example_ble_mesh_provisioning_cb);
|
||||
esp_ble_mesh_register_custom_model_callback(example_ble_mesh_custom_model_cb);
|
||||
esp_ble_mesh_register_config_client_callback(example_ble_mesh_config_client_cb);
|
||||
esp_ble_mesh_register_config_server_callback(example_ble_mesh_config_server_cb);
|
||||
|
||||
err = esp_ble_mesh_init(&prov, &comp);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "%s: Failed to initialize BLE Mesh", __func__);
|
||||
return err;
|
||||
}
|
||||
...
|
||||
return ESP_OK;
|
||||
}
|
||||
```
|
||||
2. Rregister the provisioning callback function in the BLE Mesh stack with `esp_ble_mesh_register_prov_callback(esp_ble_mesh_prov_cb)`, among which `esp_ble_mesh_prov_cb` is used to handle events thrown by protocol stations. This requires the user to implement it himself, and also needs to know the meaning of the event and how to trigger it. For example: The `ESP_BLE_MESH_PROVISIONER_PROV_LINK_OPEN_EVT` event is triggered when the provisioner starts provisioning unprovisioned device, and is handled in the `example_ble_mesh_provisioning_cb` function. Note that you need to register this function with the BLE Mesh protocol stack by calling the `esp_ble_mesh_register_prov_callback` API.
|
||||
|
||||
```c
|
||||
ESP_BLE_MESH_PROVISIONER_PROV_LINK_OPEN_EVT, /*!< Provisioner establish a BLE Mesh link event */
|
||||
|
||||
static void example_ble_mesh_provisioning_cb(esp_ble_mesh_prov_cb_event_t event,
|
||||
esp_ble_mesh_prov_cb_param_t *param)
|
||||
{
|
||||
esp_err_t err;
|
||||
|
||||
switch (event) {
|
||||
case ESP_BLE_MESH_PROVISIONER_PROV_LINK_OPEN_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_PROV_LINK_OPEN_EVT");
|
||||
provisioner_prov_link_open(param->provisioner_prov_link_open.bearer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
esp_ble_mesh_register_prov_callback(example_ble_mesh_provisioning_cb);
|
||||
```
|
||||
3. Register BLE Mesh callback for user-defined Models' operations with `esp_ble_mesh_register_custom_model_callback(esp_ble_mesh_model_cb)`.
|
||||
|
||||
4. Register BLE Mesh Config Client Model callback with `esp_ble_mesh_register_config_client_callback(example_ble_mesh_config_client_cb)`.
|
||||
5. Register BLE Mesh Config Server Model callback with `esp_ble_mesh_register_config_server_callback(example_ble_mesh_config_server_cb)`.
|
||||
|
||||
6. Initialize the BLE Mesh module by calling the `esp_ble_mesh_init(&prov, &comp)` API, which initializes the provisioning capabilities and composition data information. Registered information is stored in the `prov` struct, which is essentially a composition of one or more Models.
|
||||
|
||||
|
||||
### Initializing the Wi-Fi Console
|
||||
|
||||
This demo calls the `wifi_console_init` function:
|
||||
|
||||
```c
|
||||
initialise_wifi();
|
||||
initialize_console();
|
||||
|
||||
/* Register commands */
|
||||
esp_console_register_help_command();
|
||||
register_wifi();
|
||||
```
|
||||
|
||||
1. Initialize the basic Wi-Fi function by calling `initialise_wifi`, which sets
|
||||
|
||||
* the Current Wi-Fi power save type to `WIFI_PS_MIN_MODEM`, which indicates the station wakes up to receive beacon every DTIM period
|
||||
* the Wi-Fi API configuration storage type to `WIFI_STORAGE_RAM`, which indicates all configuration will only be stored in the embedded memory
|
||||
* the Wi-Fi operating mode to `WIFI_MODE_STA`, which allows the board to work in Station mode.
|
||||
|
||||
|
||||
2. Initialize the Wi-Fi console by calling the `initialize_console` function.
|
||||
3. Enable the `Help` function by calling the `esp_console_register_help_command()`. After that, you can view all the currently supported Wi-Fi commands by entering the `help` command in your serial port tool.
|
||||
4. Register the commands by calling the `register_wifi` function.
|
||||
* An example of registering a `restart` command with a `restart()` function to handle this command can be seen below. After the initialization, you can enter the `restart` command in your serial port tool to call the `restart()` function.
|
||||
|
||||
```c
|
||||
static int restart(int argc, char **argv)
|
||||
{
|
||||
ESP_LOGI(TAG, "Restarting");
|
||||
esp_restart();
|
||||
}
|
||||
const esp_console_cmd_t restart_cmd = {
|
||||
.command = "restart",
|
||||
.help = "Restart the program",
|
||||
.hint = NULL,
|
||||
.func = &restart,
|
||||
};
|
||||
```
|
||||
|
||||
Note that the `sta`,`scan`,`ap`,`query`,`iperf`,`restart` and `heap` commands are supported in this demo.
|
||||
|
||||
The main program of the Wi-Fi constantly reads data from the command line. The `esp_console_run` function will parse the command entered from your serial port tool, then call the handler function registered for this command.
|
||||
|
||||
```c
|
||||
/* Main loop */
|
||||
while (true) {
|
||||
/* Get a line using linenoise.
|
||||
* The line is returned when ENTER is pressed.
|
||||
*/
|
||||
char *line = linenoise(prompt);
|
||||
if (line == NULL) { /* Ignore empty lines */
|
||||
continue;
|
||||
}
|
||||
/* Add the command to the history */
|
||||
linenoiseHistoryAdd(line);
|
||||
|
||||
/* Try to run the command */
|
||||
int ret;
|
||||
esp_err_t err = esp_console_run(line, &ret);
|
||||
...
|
||||
/* linenoise allocates line buffer on the heap, so need to free it */
|
||||
linenoiseFree(line);
|
||||
}
|
||||
return;
|
||||
}
|
||||
```
|
||||