-
Notifications
You must be signed in to change notification settings - Fork 7.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'docs/walkthrough_for_multi_adv_examples_v5.1' into 'rel…
…ease/v5.1' Nimble: Added Example Walkthrough tutorial for Multi Adv example (v5.1) See merge request espressif/esp-idf!24509
- Loading branch information
Showing
1 changed file
with
245 additions
and
0 deletions.
There are no files selected for viewing
245 changes: 245 additions & 0 deletions
245
...uetooth/nimble/ble_multi_adv/tutorial/Ble_Phy_Peripheral_Example_Walkthrough.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,245 @@ | ||
# BLE Peripheral Multi Advertising Example Walkthrough | ||
|
||
## Introduction | ||
|
||
In this tutorial, the ble_multi_adv example code for the espressif chipsets with BLE5.0 support is reviewed.This example aims at understanding support for multiple advertisements. It uses extended advertising functionality of BLE. | ||
|
||
## Includes | ||
|
||
This example is located in the examples folder of the ESP-IDF under the [ble_multi_adv/main](../main/). The [main.c](../main/main.c) file located in the main folder contains all the functionality that we are going to review. The header files contained in [main.c](../main/main.c) are: | ||
|
||
```c | ||
#include "esp_log.h" | ||
#include "nvs_flash.h" | ||
|
||
/* BLE */ | ||
#include "nimble/nimble_port.h" | ||
#include "nimble/nimble_port_freertos.h" | ||
#include "host/ble_hs.h" | ||
#include "host/util/util.h" | ||
#include "console/console.h" | ||
#include "services/gap/ble_svc_gap.h" | ||
#include "multi_adv.h" | ||
``` | ||
|
||
These `includes` are required for the FreeRTOS and underlying system components to run, including the logging functionality and a library to store data in non-volatile flash memory. We are interested in `“nimble_port.h”`, `“nimble_port_freertos.h”`, `"ble_hs.h"` and `“ble_svc_gap.h”`, `“multi_adv.h”` which expose the BLE APIs required to implement this example. | ||
|
||
* `nimble_port.h`: Includes the declaration of functions required for the initialization of the nimble stack. | ||
* `nimble_port_freertos.h`: Initializes and enables nimble host task. | ||
* `ble_hs.h`: Defines the functionalities to handle the host event | ||
* `ble_svc_gap.h`:Defines the macros for device name and device appearance and declares the function to set them. | ||
* `multi_adv.h`: Defines the functions used for multi advertising. | ||
|
||
## Main Entry Point | ||
|
||
The program’s entry point is the app_main() function: | ||
|
||
```c | ||
void | ||
app_main(void) | ||
{ | ||
int rc; | ||
|
||
/* Initialize NVS — it is used to store PHY calibration data */ | ||
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); | ||
|
||
ret = nimble_port_init(); | ||
if (ret != ESP_OK) { | ||
MODLOG_DFLT(ERROR, "Failed to init nimble %d \n", ret); | ||
return; | ||
} | ||
|
||
/* Initialize the NimBLE host configuration. */ | ||
ble_hs_cfg.reset_cb = ble_multi_adv_on_reset; | ||
ble_hs_cfg.sync_cb = ble_multi_adv_on_sync; | ||
ble_hs_cfg.gatts_register_cb = gatt_svr_register_cb; | ||
ble_hs_cfg.store_status_cb = ble_store_util_status_rr; | ||
|
||
ble_hs_cfg.sm_bonding = 1; | ||
ble_hs_cfg.sm_mitm = 1; | ||
ble_hs_cfg.sm_sc = 0; | ||
|
||
/* Enable the appropriate bit masks to make sure the keys | ||
* that are needed are exchanged | ||
*/ | ||
ble_hs_cfg.sm_our_key_dist = BLE_SM_PAIR_KEY_DIST_ENC; | ||
ble_hs_cfg.sm_their_key_dist = BLE_SM_PAIR_KEY_DIST_ENC; | ||
|
||
/* Initialize callbacks to NULL */ | ||
for (int i = 0; i < BLE_ADV_INSTANCES; i++) { | ||
ble_instance_cb[i].cb = NULL; | ||
} | ||
|
||
rc = gatt_svr_init(); | ||
assert(rc == 0); | ||
|
||
/* Set the default device name. */ | ||
rc = ble_svc_gap_device_name_set("nimble-multi-adv"); | ||
assert(rc == 0); | ||
|
||
/* XXX Need to have template for store */ | ||
ble_store_config_init(); | ||
|
||
nimble_port_freertos_init(ble_multi_adv_host_task); | ||
} | ||
``` | ||
The main function starts by initializing the non-volatile storage library. This library allows us to save the key-value pairs in flash memory.`nvs_flash_init()` stores the PHY calibration data. In a Bluetooth Low Energy (BLE) device, cryptographic keys used for encryption and authentication are often stored in Non-Volatile Storage (NVS).BLE stores the peer keys, CCCD keys, peer records, etc on NVS. By storing these keys in NVS, the BLE device can quickly retrieve them when needed, without the need for time-consuming key generations. | ||
```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 ); | ||
``` | ||
|
||
## BT Controller and Stack Initialization | ||
The main function calls `nimble_port_init()` to initialize BT Controller and nimble stack. This function initializes the BT controller by first creating its configuration structure named `esp_bt_controller_config_t` with default settings generated by the `BT_CONTROLLER_INIT_CONFIG_DEFAULT()` macro. It 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()` and `esp_bt_controller_enable()` functions: | ||
|
||
```c | ||
esp_bt_controller_config_t config_opts = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); | ||
ret = esp_bt_controller_init(&config_opts); | ||
``` | ||
|
||
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_BLE` if you want to use the BLE mode. | ||
There are four Bluetooth modes supported: | ||
|
||
1. `ESP_BT_MODE_IDLE`: Bluetooth not running | ||
2. `ESP_BT_MODE_BLE`: BLE mode | ||
3. `ESP_BT_MODE_CLASSIC_BT`: BT Classic mode | ||
4. `ESP_BT_MODE_BTDM`: Dual mode (BLE + BT Classic) | ||
|
||
After the initialization of the BT controller, the nimble stack, which includes the common definitions and APIs for BLE, is initialized by using `esp_nimble_init()`: | ||
|
||
```c | ||
esp_err_t esp_nimble_init(void) | ||
{ | ||
#if !SOC_ESP_NIMBLE_CONTROLLER | ||
/* Initialize the function pointers for OS porting */ | ||
npl_freertos_funcs_init(); | ||
|
||
npl_freertos_mempool_init(); | ||
|
||
if(esp_nimble_hci_init() != ESP_OK) { | ||
ESP_LOGE(NIMBLE_PORT_LOG_TAG, "hci inits failed\n"); | ||
return ESP_FAIL; | ||
} | ||
|
||
/* Initialize default event queue */ | ||
ble_npl_eventq_init(&g_eventq_dflt); | ||
/* Initialize the global memory pool */ | ||
os_mempool_module_init(); | ||
os_msys_init(); | ||
|
||
#endif | ||
/* Initialize the host */ | ||
ble_transport_hs_init(); | ||
|
||
return ESP_OK; | ||
} | ||
``` | ||
The host is configured by setting up the callbacks on Stack-reset, Stack-sync, registration of each GATT resource, and storage status. | ||
```c | ||
ble_hs_cfg.reset_cb = ble_multi_adv_on_reset; | ||
ble_hs_cfg.sync_cb = ble_multi_adv_on_sync; | ||
ble_hs_cfg.gatts_register_cb = gatt_svr_register_cb; | ||
ble_hs_cfg.store_status_cb = ble_store_util_status_rr; | ||
``` | ||
|
||
The Security Manager is configured by setting up the following SM's flag and attributes of the host | ||
|
||
1. sm_bonding: It represents Security Manager Bond Flag. | ||
2. sm_mitm : It represents the Security Manager MITM Flag which results in requiring Man-In-The-Middle protection while pairing if it is set. | ||
3. sm_sc: It represents Security Manager Secure Connections Flag. | ||
4. sm_our_key_dist: It represents Security Manager's local key distribution mask. | ||
5. sm_their_key_dist: It represents Security Manager remote key distribution mask. | ||
|
||
```c | ||
ble_hs_cfg.sm_bonding = 1; | ||
ble_hs_cfg.sm_mitm = 1; | ||
ble_hs_cfg.sm_sc = 0; | ||
|
||
/* Enable the appropriate bit masks to make sure the keys | ||
* that are needed are exchanged | ||
*/ | ||
ble_hs_cfg.sm_our_key_dist = BLE_SM_PAIR_KEY_DIST_ENC; | ||
ble_hs_cfg.sm_their_key_dist = BLE_SM_PAIR_KEY_DIST_ENC; | ||
``` | ||
|
||
The main function calls `ble_svc_gap_device_name_set()` to set the default device name. 'nimble-multi-adv' is passed as the default device name to this function. | ||
|
||
```c | ||
rc = ble_svc_gap_device_name_set("nimble-multi-adv"); | ||
``` | ||
|
||
main function calls `ble_store_config_init()` to configure the host by setting up the storage callbacks which handle the read, write, and deletion of security material. | ||
|
||
```c | ||
/* XXX Need to have a template for store */ | ||
ble_store_config_init(); | ||
``` | ||
|
||
The main function ends by creating a task where nimble will run using `nimble_port_freertos_init()`. This enables the nimble stack by using `esp_nimble_enable()`. | ||
|
||
```c | ||
nimble_port_freertos_init(ble_multi_adv_host_task); | ||
``` | ||
`esp_nimble_enable()` create a task where the nimble host will run. It is not strictly necessary to have a separate task for the nimble host, but since something needs to handle the default queue, it is easier to create a separate task. | ||
## MultiAdvertising | ||
The demo example starts 4 types of advertising: | ||
* Non connectable extended | ||
* Connectable extended | ||
* Scannable legacy | ||
* Legacy withe specified duration(5 sec) | ||
For each instance: | ||
* A random address is generated which is associated with the advertising instance | ||
```c | ||
rc = ble_multi_adv_set_addr(instance); | ||
``` | ||
|
||
* Once the address is set, then appropriate adv data is set . | ||
|
||
```c | ||
/* get mbuf for adv data */ | ||
data = os_msys_get_pkthdr(size_pattern, 0); | ||
assert(data); | ||
|
||
/* fill mbuf with adv data */ | ||
rc = os_mbuf_append(data, pattern, size_pattern); | ||
assert(rc == 0); | ||
|
||
rc = ble_gap_ext_adv_set_data(instance, data); | ||
assert (rc == 0); | ||
``` | ||
* Start advertising | ||
```c | ||
/* start advertising */ | ||
rc = ble_gap_ext_adv_start(instance, duration, 0); | ||
assert (rc == 0); | ||
ESP_LOGI(tag, "Instance %d started", instance); | ||
``` | ||
|
||
## Conclusion | ||
This example demos multi advertising using the Extended adv feature present in BLE5.0. User can have multiple instances of advertising with different advertisement reports. Each instance would show up to be associated with separate BT address when scanned from a remote device. |