Readme for the bluedroid ble50 example with tutorial of walkthrough example.

pull/7958/head
satish.solanke 2021-10-22 18:19:18 +05:30
rodzic 4161434837
commit b523256c49
10 zmienionych plików z 1639 dodań i 10 usunięć

Wyświetl plik

@ -1,3 +1,72 @@
| Supported Targets | ESP32-C3 |
| ----------------- | -------- |
| Supported Targets | ESP32-C3 | ESP32-S3 |
| ----------------- | -------- | -------- |
# ESP-IDF Gatt Security Client Example
This example shows how to use the ESP BLE5.0 security APIs to connect in secure manner with peer device and use encryption for data exchange.
## How to Use Example
Before project configuration and build, be sure to set the correct chip target using:
```bash
idf.py set-target <chip_name>
```
To test this demo, you can run the [ble50_security_server_demo](../ble50_security_server), which starts advertising and can be connected to
this demo automatically.
There are some important points for this demo:
1. `esp_ble_gap_set_security_param` should be used to set the security parameters in the initial stage;
2. `esp_ble_set_encryption` should be used to start encryption with peer device. If the peer device initiates the encryption,
`esp_ble_gap_security_rsp` should be used to send security response to the peer device when `ESP_GAP_BLE_SEC_REQ_EVT` is received.
3. The `gatt_security_client_demo` will receive a `ESP_GAP_BLE_AUTH_CMPL_EVT` once the encryption procedure has completed.
Please, check this [tutorial](tutorial/ble50_security_client_Example_Walkthrough.md) for more information about this example.
### Hardware Required
* A development board with ESP32-C3 SoC, ESP32-S3 SoC and BT5.0 supported chip (e.g., ESP32-C3-DevKitC-1 etc.)
* A USB cable for Power supply and programming
See [Development Boards](https://www.espressif.com/en/products/devkits) for more information about it.
### Build and Flash
Run `idf.py -p PORT flash monitor` to build, flash and monitor the project.
(To exit the serial monitor, type ``Ctrl-]``.)
See the [Getting Started Guide](https://idf.espressif.com/) for full steps to configure and use ESP-IDF to build projects.
## Example Output
```
I (364) BTDM_INIT: BT controller compile version [3e61eea]
I (374) coexist: coexist rom version 8459080
I (374) phy_init: phy_version 500,985899c,Apr 19 2021,16:05:08
I (494) system_api: Base MAC address is not set
I (494) system_api: read default base MAC address from EFUSE
I (494) BTDM_INIT: Bluetooth MAC: 7c:df:a1:40:01:dd
I (514) SEC_GATTC_DEMO: EVT 0, gattc if 3
I (514) SEC_GATTC_DEMO: REG_EVT
I (524) SEC_GATTC_DEMO: Scan start success
I (2654) SEC_GATTC_DEMO: legacy adv, adv type 0x13 data len 31
I (2654) SEC_GATTC_DEMO: legacy adv, adv type 0x1b data len 21
I (3624) SEC_GATTC_DEMO: legacy adv, adv type 0x13 data len 31
I (3624) SEC_GATTC_DEMO: legacy adv, adv type 0x1b data len 21
I (4594) SEC_GATTC_DEMO: legacy adv, adv type 0x13 data len 31
I (4594) SEC_GATTC_DEMO: legacy adv, adv type 0x1b data len 21
I (5514) SEC_GATTC_DEMO: legacy adv, adv type 0x13 data len 31
I (5524) SEC_GATTC_DEMO: legacy adv, adv type 0x1b data len 0
I (7494) SEC_GATTC_DEMO: legacy adv, adv type 0x13 data len 31
I (7494) SEC_GATTC_DEMO: legacy adv, adv type 0x1b data len 21
I (8614) SEC_GATTC_DEMO: legacy adv, adv type 0x13 data len 31
I (8614) SEC_GATTC_DEMO: legacy adv, adv type 0x1b data len 0
```
## Troubleshooting
For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon.

Wyświetl plik

@ -0,0 +1,147 @@
# BLE50 GATT Security Client Example Walkthrough
## Introduction
* This document presents a review of the GATT Security Client code example for the ESP32C3 or BLE5.0 supported Chip.
* The GATT Client is capable of scanning for nearby devices and once it has found a device of interest, it requests a secure connection. The GATT client behaves as a central device that initiates a connection to a peripheral by sending a *Aux Connect Pairing Request* as specified by the [Bluetooth Core Specification Version 5.0](https://www.bluetooth.com/specifications/bluetooth-core-specification).
* The peripheral device is normally a GATT Server that exposes Services and Characteristics. The peripheral replies with a *Aux Connect Pairing Response* followed by authentication and exchange of keys. If the bonding process is also executed, the Long Term Keys are stored for subsequent connections. Finally an encrypted channel is established which can support protection against Man-In-The-Middle (MITM) attacks depending on the security configuration.
* The code is implemented using an Application Profile that upon registration, allows to set the local privacy configuration as events are triggered during the life time of the program.
This document only includes a description of the security aspects of the BLE5.0 Security GATT Client implementation, for the more infor about extended scan , periodic scan please refer to [Periodic_Sync_Example Walkthrough] (../../peroidic_sync/tutorial/Periodic_Sync_Example_Walkthrough.md).
##include
```c
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <stdio.h>
#include "nvs.h"
#include "nvs_flash.h"
#include "esp_bt.h"
#include "esp_gap_ble_api.h"
#include "esp_gattc_api.h"
#include "esp_gatt_defs.h"
#include "esp_bt_main.h"
#include "esp_gatt_common_api.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.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 `“bt.h”`, `“esp_bt_main.h”`, `"esp_gap_ble_api.h"` and `“esp_gattc_api.h”`, which expose the BLE APIs required to implement this example.
* `bt.h`: configures the BT controller and VHCI from the host side.
* `esp_bt_main.h`: initializes and enables the Bluedroid stack.
* `esp_gap_ble_api.h`: implements the GAP configuration, such as advertising and connection parameters.
* `esp_gattc_api.h`: implements the GATT Client configuration, such as connecting to peripherals and searching for services.
## Configuring Local Privacy of the Security Client
The example registers one Application Profile defined as:
```c
#define PROFILE_NUM 1
#define PROFILE_A_APP_ID 0
```
The registration takes place in the ``app_main()`` function by using the ``esp_ble_gattc_app_register()`` function:
```c
ret = esp_ble_gattc_app_register(PROFILE_A_APP_ID);
if (ret){
ESP_LOGE(GATTC_TAG, "%s gattc app register error, error code = %x\n", __func__, ret);
}
```
The Application Profile registration triggers an ``ESP_GATTC_REG_EVT`` event which is managed by the ``esp_gattc_cb()`` callback function and forwarded to the Profile A event handler ``gattc_profile_event_handler()``. Here, the event is used to configure the local privacy of the slave device by using the ``esp_ble_gap_config_local_privacy()`` function.
```c
case ESP_GATTC_REG_EVT:
ESP_LOGI(GATTC_TAG, "REG_EVT");
esp_ble_gap_config_local_privacy(true);
break;
```
This function is a Bluedroid API call for configuring default privacy settings on the local device. Once the privacy is set, an ``ESP_GAP_BLE_SET_LOCAL_PRIVACY_COMPLETE_EVT`` is triggered which is used to set scan parameters and start scanning for nearby peripherals:
```c
case ESP_GAP_BLE_SET_LOCAL_PRIVACY_COMPLETE_EVT:
if (param->local_privacy_cmpl.status != ESP_BT_STATUS_SUCCESS){
ESP_LOGE(GATTC_TAG, "config local privacy failed, error code =%x", param->local_priva
cy_cmpl.status);
break;
}
esp_err_t scan_ret = esp_ble_gap_set_ext_scan_params(&ext_scan_params);
if (scan_ret){
ESP_LOGE(GATTC_TAG, "set extend scan params error, error code = %x", scan_ret);
}
break;
case ESP_GAP_BLE_SET_EXT_SCAN_PARAMS_COMPLETE_EVT: {
if (param->set_ext_scan_params.status != ESP_BT_STATUS_SUCCESS) {
ESP_LOGE(GATTC_TAG, "extend scan parameters set failed, error status = %x", param->se
t_ext_scan_params.status);
break;
}
//the unit of the duration is second
esp_ble_gap_start_ext_scan(EXT_SCAN_DURATION, EXT_SCAN_PERIOD);
break;
}
case ESP_GAP_BLE_EXT_SCAN_START_COMPLETE_EVT:
if (param->ext_scan_start.status != ESP_BT_STATUS_SUCCESS) {
ESP_LOGE(GATTC_TAG, "scan start failed, error status = %x", param->scan_start_cmpl.st
atus);
```
## Configuring and Bonding to a Slave Device
The rest of the configuration for the GATT Client is performed normally in the same way as the regular GATT Client example. That is, the client finds a device of interest and opens a connection. At this point the GATT client, which is usually the central, initiates the pairing process by sending a Pairing Request to the peripheral device. This request should be acknowledged with a Pairing Response. The Pairing process is implemented automatically by the stack and no extra user configuration is needed. However, depending on the I/O capabilities of both devices, a passkey might be generated on the ESP32 which is presented to the user with the ``ESP_GAP_BLE_PASSKEY_NOTIF_EVT``:
```c
case ESP_GAP_BLE_PASSKEY_NOTIF_EVT:
///the app will receive this evt when the IO has Output capability and the peer device IO has Input capability.
///show the passkey number to the user to input it in the peer device.
ESP_LOGE(GATTS_TABLE_TAG, "The passkey Notify number:%d", param->ble_security.key_notif.passkey);
break;
```
The combination of input and output capabilities that determine which algorithm is used are:
| | Display Only | Display Yes/No | Keyboard Only | No Input No Output | Keyboard Display|
| :-- | :------------- | :------------- | :------------- | :----------------- | :-------------- |
| **Display Only** | Just Works | Just Works | Passkey Entry | Just Works | Passkey Entry |
| **Display Yes/No** | Just Works | Just Works | Passkey Entry | Just Works | Passkey Entry |
| **Keyboard Only** | Passkey Entry | Passkey Entry | Passkey Entry | Just Works | Passkey Entry |
| **No Input No Output** | Just Works | Just Works | Just Works | Just Works | Just Works |
| **Keyboard Display** | Passkey Entry | Passkey Entry | Passkey Entry | Just Works | Passkey Entry |
In the Just Works method, the Temporary Key is set to 0. This is a practical way to authenticate devices when no display or keyboards are attached to them, so that there is no way to show or enter a passkey. However, if the ESP32 GATT Client has an LCD, it can present the passkey generated locally so that the user can input it on the other peer device, or if the GATT Client has a keyboard, it can input the passkey generated by the other peer device. Additionally, a numeric comparison can be performed if both devices have a display and yes/no confirm buttons and LE Secure Connections are used, that way an independently generated passkey is displayed on both devices and the user manually checks that both 6-digit confirmation values match.
## Exchanging Keys
When the client connects to a remote device and the pairing is done successfully, The initiator and responder keys as decided during pairing req / rsp are exchanged. For each key exchange message, an ``ESP_GAP_BLE_KEY_EVT`` event is triggered which can be used to print the type of key received:
```c
case ESP_GAP_BLE_KEY_EVT:
//shows the ble key info share with peer device to the user.
ESP_LOGI(GATTS_TABLE_TAG, "key type = %s", esp_key_type_to_str(param->ble_security.ble_key.key_type));
break;
```
When the keys are exchanged successfully, the pairing process is completed and encryption of payload data can be started using the AES-128 engine. This triggers an ``ESP_GAP_BLE_AUTH_CMPL_EVT`` event which is used to print information:
```c
case ESP_GAP_BLE_AUTH_CMPL_EVT: {
esp_bd_addr_t bd_addr;
memcpy(bd_addr, param->ble_security.auth_cmpl.bd_addr, sizeof(esp_bd_addr_t));
ESP_LOGI(GATTS_TABLE_TAG, "remote BD_ADDR: %08x%04x",\
(bd_addr[0] << 24) + (bd_addr[1] << 16) + (bd_addr[2] << 8) + bd_addr[3], (bd_addr[4] << 8) + bd_addr[5]);
ESP_LOGI(GATTS_TABLE_TAG, "address type = %d", param->ble_security.auth_cmpl.addr_type);
ESP_LOGI(GATTS_TABLE_TAG, "pair status = %s",param->ble_security.auth_cmpl.success ? "success" : "fail");
break;
```
## Conclusion
In this document, a review of the security aspects of the BLE5.0 GATT Client has been realized. BLE security encompasses Pairing, Bonding and Encryption. In order to establish a secure link between a central and a peripheral device, the local privacy of the GATT client is set, which allows the BLE stack to set necessary security parameters automatically without the need of additional user configuration. The combination of features and capabilities of the peer devices results in the selection of the appropriate pairing method which the BLE stack then executes. Immediately, the required keys are generated and exchanged and the encryption of subsequent messages is started using the AES-128 engine. These steps trigger different events that are managed by the GATT and GAP event handlers which can be used to print useful information such as the types of keys exchanged and the pairing status. The rest of the security GATT client functionality such as registering for notifications of characteristics is implemented in the same way as in [Periodic Sync Example Walkthrough](../../peroidic_sync/tutorial/Periodic_Sync_Example_Walkthrough.md).

Wyświetl plik

@ -1,4 +1,61 @@
| Supported Targets | ESP32-C3 |
| ----------------- | -------- |
| Supported Targets | ESP32-C3 | ESP32-S3 |
| ----------------- | -------- | -------- |
# ESP-IDF BLE50 Security Server Example
This example shows how to use the APIs to connect in secure manner with peer device and use encryption for data exchange.
To test this example, you can run [ble50_security_client_demo](../ble50_security_client), which starts scanning, connects to and starts encryption with `ble50_sec_gattc_demo` automatically.
Please, check this [tutorial](tutorial/ble50_security_server_Example_Walkthrough.md) for more information about this example.
## How to Use Example
Before project configuration and build, be sure to set the correct chip target using:
```bash
idf.py set-target <chip_name>
```
There are some important points for this demo:
1.`esp_ble_gap_set_security_param` should be used to set the security parameters in the initial stage;
2.`esp_ble_set_encryption` should be used to start encryption with peer device. If the peer device initiates the encryption,
`esp_ble_gap_security_rsp` should be used to send security response to the peer device when `ESP_GAP_BLE_SEC_REQ_EVT` is received.
3.The `ble50_sec_gattc_demo` will receive a `ESP_GAP_BLE_AUTH_CMPL_EVT` once the encryption procedure has completed.
### Hardware Required
* A development board with ESP32-C3 SoC, ESP32-S3 and BLE5.0 supoorted chips. (e.g., ESP32-C3-DevKitC-1, etc.)
* A USB cable for Power supply and programming
See [Development Boards](https://www.espressif.com/en/products/devkits) for more information about it.
### Build and Flash
Run `idf.py -p PORT flash monitor` to build, flash and monitor the project.
(To exit the serial monitor, type ``Ctrl-]``.)
See the [Getting Started Guide](https://idf.espressif.com/) for full steps to configure and use ESP-IDF to build projects.
## Example Output
```
I (363) BTDM_INIT: BT controller compile version [3e61eea]
I (373) coexist: coexist rom version 8459080
I (373) phy_init: phy_version 500,985899c,Apr 19 2021,16:05:08
I (493) system_api: Base MAC address is not set
I (493) system_api: read default base MAC address from EFUSE
I (493) BTDM_INIT: Bluetooth MAC: 7c:df:a1:40:01:c5
I (503) SEC_GATTS_DEMO: app_main init bluetooth
I (523) SEC_GATTS_DEMO: ESP_GATTS_REG_EVT
I (523) SEC_GATTS_DEMO: The number handle = 8
I (523) SEC_GATTS_DEMO: ESP_GAP_BLE_SET_LOCAL_PRIVACY_COMPLETE_EVT, tatus = 0
I (523) SEC_GATTS_DEMO: ESP_GAP_BLE_EXT_ADV_SET_PARAMS_COMPLETE_EVT status 0
I (533) SEC_GATTS_DEMO: ESP_GAP_BLE_EXT_ADV_DATA_SET_COMPLETE_EVT status 0
I (543) SEC_GATTS_DEMO: ESP_GAP_BLE_EXT_ADV_START_COMPLETE_EVT, status = 0
```
## Troubleshooting
For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon.

Wyświetl plik

@ -0,0 +1,235 @@
# BLE50 Gatt Security Server Example Walkthrough
## Introduction
In this document, a description of the security GATT security Server BLE example for the ESP32C3 is presented. The security configuration enables a GATT Server acting as a peripheral device to bond with a central and establish an encrypted link between them. This functionality is defined by the [Bluetooth Specification version 4.2](https://www.bluetooth.com/specifications/bluetooth-core-specification) and implemented on the ESP-IDF BLE stack, specifically on the Security Manager Protocol (SMP) API.
BLE security involves three interrelated concepts: pairing, bonding and encryption. Pairing concerns with the exchange of security features and types of keys needed. In addition, the pairing procedure takes care of the generation and exchange of shared keys. The core specification defines the legacy pairing and Secure Connections pairing (introduced in Bluetooth 5.0), which are both supported by ESP32C3. Once the exchange of shared keys is completed, a temporary encrypted link is established to exchange short term and long term keys. Bonding refers to storing the exchanged keys for subsequent connections so that they do not have to be transmitted again. Finally, encryption pertains to the ciphering of plain text data using the AES-128 engine and the shared keys. Server attributes may also be defined to allow only encrypted write and read messages. At any point of the communication, a peripheral device can always ask to start encryption by issuing a security request to the other peer device, which returns a security response by calling an API.
This document only describes the security configuration. The rest of the GATT server functionalities, such as defining the service table, are explained in the GATT Server example walkthrough documentation. For a better understanding of this example workflow, it is recommended that the reader is familiar with the pairing feature exchange and key generation defined in the section 3.5 of the [Bluetooth Specification Version 4.2](https://www.bluetooth.com/specifications/bluetooth-core-specification) [Vol 3, Part H].
## Setting Security Parameters
The ESP32 requires a series of security parameters in order to define how the pairing request and response are going to be built. The Pairing Response packet built by the GATT Server includes fields such as the input/output capabilities, Secure Connections pairing, authenticated Man-In-The-Middle (MITM) protection or no security requirements (see Section 2.3.1 of the [Bluetooth Specification Version 4.2](https://www.bluetooth.com/specifications/bluetooth-core-specification) [Vol 3, Part H]). In this example, this procedure is done in the `app_main()` function. The pairing request is sent by the initiator which in this case is a remote GATT client. The ESP32 server implemented in this example receives this request and replies with a pairing response, which contains the same security parameters in order for both devices to agree on the resources available and the applicable pairing algorithm (*Just Works* or *Passkey Entry*). Both the pairing request and response commands have the following parameters:
* *IO Capability*: describes if the device has input/output capabilities such as a display or a keyboard.
* *OOB Flag*: describes if the device supports Out of Band passkey exchange, for example using NFC or Wi-Fi to exchange keys as TKs.
* *Authorization Request*: indicates the requested security properties such as Bonding, Secure Connections (SC), MITM protection or none that will be present in the Pairing Request and Response packets.
* *Maximum Encryption Key Size*: maximum encryption key size in octets.
* *Initiator Key Distribution/Generation*: indicates which keys the initiator is requesting to distribute/generate or use during the Transport Specific Key Distribution phase. In the pairing request, these keys are requested, while in the pairing response, these keys are confirmed to be distributed.
* *Responder Key Distribution/Generation*: indicates which keys the initiator is requesting the responder to distribute/generate or use during the Transport Specific Key Distribution phase. In the pairing request, these keys are requested, while in the pairing response, these keys are confirmed to be distributed.
In code, these parameters are defined as follows:
* *IO Capability*:
```c
esp_ble_io_cap_t iocap = ESP_IO_CAP_NONE;//set the IO capability to No Input No Output
```
The possible values for *IO Capabilities* are:
```c
ESP_IO_CAP_OUT 0 /*!< DisplayOnly */
ESP_IO_CAP_IO 1 /*!< DisplayYesNo */
ESP_IO_CAP_IN 2 /*!< KeyboardOnly */
ESP_IO_CAP_NONE 3 /*!< NoInputNoOutput */
ESP_IO_CAP_KBDISP 4 /*!< Keyboard display */
```
* *Authorization Request*:
```c
esp_ble_auth_req_t auth_req = ESP_LE_AUTH_BOND; //bonding with peer device after authentication
```
The possible values for *Authorization Request* are a combination of Bonding, MITM protection and Secure Connections requests:
```c
ESP_LE_AUTH_NO_BOND: No bonding.
ESP_LE_AUTH_BOND: Bonding is performed.
ESP_LE_AUTH_REQ_MITM: MITM Protection is enabled.
ESP_LE_AUTH_REQ_SC_ONLY: Secure Connections without bonding enabled.
ESP_LE_AUTH_REQ_SC_BOND: Secure Connections with bonding enabled.
ESP_LE_AUTH_REQ_SC_MITM: Secure Connections with MITM Protection and no bonding enabled.
ESP_LE_AUTH_REQ_SC_MITM_BOND: Secure Connections with MITM Protection and bonding enabled.
```
* *Maximum Encryption Key Size*:
```c
uint8_t key_size = 16; //the key size should be 7~16 bytes
```
* *Initiator Key Distribution/Generation*:
```c
uint8_t init_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK;
```
The initiator distributes the LTK and IRK keys by the setting the EncKey and IdKey masks.
* *Responder Key Distribution/Generation*:
```c
uint8_t rsp_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK;
```
The responder distributes the LTK and IRK keys by the setting the *EncKey* and *IdKey* masks.
Once defined, the parameters are set using the `esp_ble_gap_set_security_param()` function. This function sets the parameter type, the parameter value and the parameter length:
```c
esp_ble_gap_set_security_param(ESP_BLE_SM_AUTHEN_REQ_MODE, &auth_req, sizeof(uint8_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &iocap, sizeof(uint8_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_MAX_KEY_SIZE, &key_size, sizeof(uint8_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_SET_INIT_KEY, &init_key, sizeof(uint8_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_SET_RSP_KEY, &rsp_key, sizeof(uint8_t));
```
This information is enough for the BLE stack to perform the pairing process, including pairing confirmation and key generation. The procedure is invisible to the user and executed automatically by the stack.
## Connecting and Bonding to a Peer Device
The security parameters set previously are stored locally to be used later when the central device connects to the peripheral. Every time a remote device connects to the local GATT server, the connection event `ESP_GATTS_CONNECT_EVT` is triggered. This event is employed to perform the pairing and bonding process by invoking the `esp_ble_set_encryption()` function which takes as parameters the remote device address and the type of encryption that will be performed. The BLE stack then executes the actual pairing process in the background. In this example, the encryption includes MITM protection.
```c
case ESP_GATTS_CONNECT_EVT:
//start security connect with peer device when receive the connect event sent by the central.
esp_ble_set_encryption(param->connect.remote_bda, ESP_BLE_SEC_ENCRYPT_MITM);
break;
```
The types of encryptions available are:
* `ESP_BLE_SEC_NONE`
* `ESP_BLE_SEC_ENCRYPT`
* `ESP_BLE_SEC_ENCRYPT_NO_MITM`
* `ESP_BLE_SEC_ENCRYPT_MITM`
The difference between `ESP_BLE_SEC_ENCRYPT` and `ESP_BLE_SEC_ENCRYPT_NO_MITM` lies in the fact that a previous connection might have a security level that needs to be upgraded, therefore requires to exchange keys again.
In this example, the I/O capabilities are set to *No Input No Output*, therefore the *Just Works* pairing method, which doesn't not require the generation of a random 6-digit passkey, is used (For details, please refer to the table below). The user may modify the example to set the I/O capabilities to use other than *No Input No Output*. Therefore, depending on the I/O capabilities of the remote device, a passkey might be generated on the ESP32 which is presented to the user with the `ESP_GAP_BLE_PASSKEY_NOTIF_EVT`:
```c
case ESP_GAP_BLE_PASSKEY_NOTIF_EVT:
///the app will receive this evt when the IO has Output capability and the peer device IO has Input capability.
///show the passkey number to the user to input it in the peer device.
ESP_LOGE(GATTS_TABLE_TAG, "The passkey Notify number:%d", param->ble_security.key_notif.passkey);
break;
```
The combination of input and output capabilities that determine which algorithm is used are:
| | Display Only | Display Yes/No | Keyboard Only | No Input No Output | Keyboard Display|
| :-- | :------------- | :------------- | :------------- | :----------------- | :-------------- |
| **Display Only** | Just Works | Just Works | Passkey Entry | Just Works | Passkey Entry |
| **Display Yes/No** | Just Works | Just Works | Passkey Entry | Just Works | Passkey Entry |
| **Keyboard Only** | Passkey Entry | Passkey Entry | Passkey Entry | Just Works | Passkey Entry |
| **No Input No Output** | Just Works | Just Works | Just Works | Just Works | Just Works |
| **Keyboard Display** | Passkey Entry | Passkey Entry | Passkey Entry | Just Works | Passkey Entry |
## Exchanging Keys
When the client connects to the server and the pairing is done successfully, the keys indicated by the `init_key` and `rsp_key` security parameters are exchanged. In this example the following keys are generated and distributed:
* Local device LTK
* Local device IRK
* Local device CSRK
* Peer device LTK
* Peer device IRK
Note that for this example only, the peer device CSRK is not exchanged. For each key exchange message, an `ESP_GAP_BLE_KEY_EVT` event is triggered, which can be used to print the type of key received:
```c
case ESP_GAP_BLE_KEY_EVT:
//shows the ble key info share with peer device to the user.
ESP_LOGI(GATTS_TABLE_TAG, "key type = %s", esp_key_type_to_str(param->ble_security.ble_key.key_type));
break;
```
When the keys are exchanged successfully, the pairing process is done. This triggers an `ESP_GAP_BLE_AUTH_CMPL_EVT` event, which is used to print information such as remote device, address type and pair status:
```c
case ESP_GAP_BLE_AUTH_CMPL_EVT: {
esp_bd_addr_t bd_addr;
memcpy(bd_addr, param->ble_security.auth_cmpl.bd_addr,
sizeof(esp_bd_addr_t));
ESP_LOGI(GATTS_TABLE_TAG, "remote BD_ADDR: %08x%04x",\
(bd_addr[0] << 24) + (bd_addr[1] << 16) + (bd_addr[2] << 8) +
bd_addr[3],
(bd_addr[4] << 8) + bd_addr[5]);
ESP_LOGI(GATTS_TABLE_TAG, "address type = %d",
param->ble_security.auth_cmpl.addr_type);
ESP_LOGI(GATTS_TABLE_TAG, "pair status = %s",
param->ble_security.auth_cmpl.success ? "success" : "fail");
break;
}
```
## Security Permission for Attributes
When defining the attributes of the server, different permissions can be set to the write and read events. Attributes permissions can be:
* Permission to read
* Permission to read with encryption
* Permission to read with encryption and MITM protection
* Permission to write
* Permission to write with encryption
* Permission to write with encryption and MITM protection
* Permission to signed write
* Permission to signed write with MITM protection
These permissions are defined in the API as:
* `ESP_GATT_PERM_READ`
* `ESP_GATT_PERM_READ_ENCRYPTED`
* `ESP_GATT_PERM_READ_ENC_MITM`
* `ESP_GATT_PERM_WRITE`
* `ESP_GATT_PERM_WRITE_ENCRYPTED`
* `ESP_GATT_PERM_WRITE_ENC_MITM`
* `ESP_GATT_PERM_WRITE_SIGNED`
* `ESP_GATT_PERM_WRITE_SIGNED_MITM`
When creating the services table, each attribute can have permissions to read or write, with or without encryption. When an attribute has encrypted permissions and a peer device that does not have the required security clearance tries to read or write to that attribute, the local host sends an Insufficient Authorization Error. In the example, the following attributes are defined with permissions with encryption:
```c
// Body Sensor Location Characteristic Value
[HRS_IDX_BOBY_SENSOR_LOC_VAL] = {
{ESP_GATT_AUTO_RSP},
{ESP_UUID_LEN_16,
(uint8_t *)&body_sensor_location_uuid,
ESP_GATT_PERM_READ_ENCRYPTED,
sizeof(uint8_t),
sizeof(body_sensor_loc_val),
(uint8_t *)body_sensor_loc_val}
},
// Heart Rate Control Point Characteristic Value
[HRS_IDX_HR_CTNL_PT_VAL] = {
{ESP_GATT_AUTO_RSP},
{ESP_UUID_LEN_16,
(uint8_t *)&heart_rate_ctrl_point,
ESP_GATT_PERM_WRITE_ENCRYPTED|ESP_GATT_PERM_READ_ENCRYPTED,
sizeof(uint8_t),
sizeof(heart_ctrl_point),
(uint8_t *)heart_ctrl_point}
},
```
## Security Requests
During the communication between a central and a peripheral device, the peripheral might request to start encryption at any moment by issuing a security request command. This command will trigger an `ESP_GAP_BLE_SEC_REQ_EVT` event on the central, which will reply a positive (true) security response to the peer device to accept the request or a negative (false) one to reject the request. In this example, this event is used to reply a start encryption response by using the `esp_ble_gap_security_rsp()` API call.
```c
case ESP_GAP_BLE_SEC_REQ_EVT:
/* send the positive (true) security response to the peer device to accept the security request.
If not accept the security request, should send the security response with negative(false) accept value*/
esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, true);
break;
```
## Conclusion
In this document, a review of the security aspects of the GATT Server has been realized. BLE security encompasses Pairing, Bonding and Encryption. In order to establish a secured link between a central and a peripheral device, security parameters that define the capabilities and features each device possess are set. The combination of features and capabilities of the peer devices results in the selection of the appropriate pairing method which the BLE stack then executes. Immediately, the required keys are generated and exchanged, and the encryption of subsequent messages is started using the AES-128 engine and these keys. These steps trigger different events that are managed by the GATT and GAP event handlers which can be used to print useful information such as the types of keys exchanged and the pairing status. In addition, attribute permissions are appointed to allow only encrypted read and write events when needed. The rest of the Security GATT server functionalities such as defining services and characteristics are implemented in the same way as presented in the GATT Server example.

Wyświetl plik

@ -1,3 +1,63 @@
| Supported Targets | ESP32-C3 |
| ----------------- | -------- |
| Supported Targets | ESP32-C3 | ESP32-S3 |
| ----------------- | -------- | -------- |
#ESP-IDF Multi Adv Example
This example support legacy as well as extended advertisement for all phy.
Please, check this [tutorial](tutorial/Mulit_Adv_Example_Walkthrough.md) for more information about this example.
## How to Use Example
Before project configuration and build, be sure to set the correct chip target using:
```bash
idf.py set-target <chip_name>
```
### Hardware Required
* A development board with ESP32-C3 SoC and ESP32-S3 and BLE5.0 supported chips (e.g., ESP32-C3-DevKitC, etc.)
* A USB cable for Power supply and programming
See [Development Boards](https://www.espressif.com/en/products/devkits) for more information about it.
### Build and Flash
Run `idf.py -p PORT flash monitor` to build, flash and monitor the project.
(To exit the serial monitor, type ``Ctrl-]``.)
See the [Getting Started Guide](https://idf.espressif.com/) for full steps to configure and use ESP-IDF to build projects.
## Example Output
```
I (361) BTDM_INIT: BT controller compile version [3e61eea]
I (371) coexist: coexist rom version 8459080
I (371) phy_init: phy_version 500,985899c,Apr 19 2021,16:05:08
I (491) system_api: Base MAC address is not set
I (491) system_api: read default base MAC address from EFUSE
I (491) BTDM_INIT: Bluetooth MAC: 7c:df:a1:40:01:c5
I (711) MULTI_ADV_DEMO: ESP_GAP_BLE_EXT_ADV_SET_PARAMS_COMPLETE_EVT, status 0
I (711) MULTI_ADV_DEMO: ESP_GAP_BLE_EXT_ADV_SET_RAND_ADDR_COMPLETE_EVT, status 0
I (711) MULTI_ADV_DEMO: ESP_GAP_BLE_EXT_ADV_DATA_SET_COMPLETE_EVT, status 0
I (721) MULTI_ADV_DEMO: ESP_GAP_BLE_EXT_ADV_SET_PARAMS_COMPLETE_EVT, status 0
I (731) MULTI_ADV_DEMO: ESP_GAP_BLE_EXT_ADV_SET_RAND_ADDR_COMPLETE_EVT, status 0
I (741) MULTI_ADV_DEMO: ESP_GAP_BLE_EXT_SCAN_RSP_DATA_SET_COMPLETE_EVT, status 0
I (741) MULTI_ADV_DEMO: ESP_GAP_BLE_EXT_ADV_SET_PARAMS_COMPLETE_EVT, status 0
I (751) MULTI_ADV_DEMO: ESP_GAP_BLE_EXT_ADV_SET_RAND_ADDR_COMPLETE_EVT, status 0
I (761) MULTI_ADV_DEMO: ESP_GAP_BLE_EXT_ADV_DATA_SET_COMPLETE_EVT, status 0
I (771) MULTI_ADV_DEMO: ESP_GAP_BLE_EXT_SCAN_RSP_DATA_SET_COMPLETE_EVT, status 0
I (781) MULTI_ADV_DEMO: ESP_GAP_BLE_EXT_ADV_SET_PARAMS_COMPLETE_EVT, status 0
I (781) MULTI_ADV_DEMO: ESP_GAP_BLE_EXT_ADV_SET_RAND_ADDR_COMPLETE_EVT, status 0
I (791) MULTI_ADV_DEMO: ESP_GAP_BLE_EXT_SCAN_RSP_DATA_SET_COMPLETE_EVT, status 0
I (801) MULTI_ADV_DEMO: ESP_GAP_BLE_EXT_ADV_START_COMPLETE_EVT, status 0
```
## Troubleshooting
For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon.

Wyświetl plik

@ -0,0 +1,282 @@
# Multi Adv Example Walkthrough
## introduction
In this document, we review the Multi Adv example code which implements a Bluetooth Low Energy (BLE5.0) Multi adv profile on the ESP32C3. This example is designed around two Application Profiles and a series of events that are handled in order to execute a sequence of configuration steps, such as defining extended advertising parameters with all phy 1M,2M and coded and Ext adv data.
## Includes
First, lets take a look at the include
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_bt.h"
#include "esp_gap_ble_api.h"
#include "esp_gatts_api.h"
#include "esp_bt_defs.h"
#include "esp_bt_main.h"
#include "esp_gatt_common_api.h"
#include "sdkconfig.h"
```
These includes are required for the FreeRTOS and underlaying system components to run, including the logging functionality and a library to store data in non-volatile flash memory. We are interested in `"esp_bt.h"`, `"esp_bt_main.h"`, `"esp_gap_ble_api.h"` and `"esp_gatts_api.h"`, which expose the BLE APIs required to implement this example.
* `esp_bt.h`: implements BT controller and VHCI configuration procedures from the host side.
* `esp_bt_main.h`: implements initialization and enabling of the Bluedroid stack.
* `esp_gap_ble_api.h`: implements GAP configuration, such as advertising and connection parameters.
* `esp_gatts_api.h`: implements GATT configuration, such as creating services and characteristics.
## Main Entry Point
The entry point to this example is the app_main() function:
```c
void app_main(void)
{
esp_err_t ret;
// Initialize NVS.
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 );
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
ret = esp_bt_controller_init(&bt_cfg);
if (ret) {
ESP_LOGE(LOG_TAG, "%s initialize controller failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
if (ret) {
ESP_LOGE(LOG_TAG, "%s enable controller failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
ret = esp_bluedroid_init();
if (ret) {
ESP_LOGE(LOG_TAG, "%s init bluetooth failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
ret = esp_bluedroid_enable();
if (ret) {
ESP_LOGE(LOG_TAG, "%s enable bluetooth failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
ret = esp_ble_gap_register_callback(gap_event_handler);
if (ret){
ESP_LOGE(LOG_TAG, "gap register error, error code = %x", ret);
return;
}
vTaskDelay(200 / portTICK_PERIOD_MS);
test_sem = xSemaphoreCreateBinary();
// 1M phy extend adv, Connectable advertising
FUNC_SEND_WAIT_SEM(esp_ble_gap_ext_adv_set_params(0, &ext_adv_params_1M), test_sem);
FUNC_SEND_WAIT_SEM(esp_ble_gap_ext_adv_set_rand_addr(0, addr_1m), test_sem);
FUNC_SEND_WAIT_SEM(esp_ble_gap_config_ext_adv_data_raw(0, sizeof(raw_adv_data_1m), &raw_adv_data_1m[0]), test_sem);
// 2M phy extend adv, Scannable advertising
FUNC_SEND_WAIT_SEM(esp_ble_gap_ext_adv_set_params(1, &ext_adv_params_2M), test_sem);
FUNC_SEND_WAIT_SEM(esp_ble_gap_ext_adv_set_rand_addr(1, addr_2m), test_sem);
FUNC_SEND_WAIT_SEM(esp_ble_gap_config_ext_scan_rsp_data_raw(1, sizeof(raw_scan_rsp_data_2m), raw_scan_rsp_data_2m), test_sem);
// 1M phy legacy adv, ADV_IND
FUNC_SEND_WAIT_SEM(esp_ble_gap_ext_adv_set_params(2, &legacy_adv_params), test_sem);
FUNC_SEND_WAIT_SEM(esp_ble_gap_ext_adv_set_rand_addr(2, addr_legacy), test_sem);
FUNC_SEND_WAIT_SEM(esp_ble_gap_config_ext_adv_data_raw(2, sizeof(legacy_adv_data), &legacy_adv_data[0]), test_sem);
FUNC_SEND_WAIT_SEM(esp_ble_gap_config_ext_scan_rsp_data_raw(2, sizeof(legacy_scan_rsp_data), &legacy_scan_rsp_data[0]), test_sem);
// coded phy extend adv, Connectable advertising
FUNC_SEND_WAIT_SEM(esp_ble_gap_ext_adv_set_params(3, &ext_adv_params_coded), test_sem);
FUNC_SEND_WAIT_SEM(esp_ble_gap_ext_adv_set_rand_addr(3, addr_coded), test_sem);
FUNC_SEND_WAIT_SEM(esp_ble_gap_config_ext_scan_rsp_data_raw(3, sizeof(raw_scan_rsp_data_coded), &raw_scan_rsp_data_coded[0]), test_sem);
// start all adv
FUNC_SEND_WAIT_SEM(esp_ble_gap_ext_adv_start(4, &ext_adv[0]), test_sem);
return;
}
```
The main function starts by initializing the non-volatile storage library. This library allows tosave key-value pairs in flash memory and is used by some components such as the Wi-Fi library to save the SSID and password:
```c
ret = nvs_flash_init();
```
## BT Controller and Stack Initialization
The main function also 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 code is exposed as a library that interacts with underlying Bluetooth 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:
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 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();
```
The Bluetooth stack is up and running at this point in the program flow, however the functionality of the application has not been defined yet. The functionality is defined by reacting to events
such as what happens when another device tries to read or write parameters and establish a connection. User need to define GAP and GATT handlers. The application needs
to register a callback function for each event handler in order to let the application know which functions are going to handle the GAP and GATT events:
```c
esp_ble_gap_register_callback(gap_event_handler);
```
The functions `gap_event_handler()` handle all the events that are pu
shed to the application from the BLE stack.
## Setting GAP Parameters
The register application event is the first one that is triggered during the lifetime of the program, this example uses the Profile A GATT event handle to configure the advertising parameters upon registration. This example has the option to use both standard Bluetooth Core Specification advertising parameters or a customized raw buffer. The option can be selected with the `CONFIG_SET_RAW_ADV_DATA` define. The raw advertising data can be used to implement iBeacons, Eddystone or other proprietary, and custom frame types such as the ones used for Indoor Location Services that are different from the standard specifications.
The function is used to configure different types of extended advertisement types and legacy adv with 1M,2M and coded phy in esp_ble_gap_ext_adv_set_params , esp_ble_gap_ext_adv_set_rand_addr and esp_ble_gap_config_ext_adv_data_raw. Respective structure of each one of them mentioned below with one example:
```c
/**
* @brief ext adv parameters
*/
typedef struct {
esp_ble_ext_adv_type_mask_t type; /*!< ext adv type */
uint32_t interval_min; /*!< ext adv minimum interval */
uint32_t interval_max; /*!< ext adv maximum interval */
esp_ble_adv_channel_t channel_map; /*!< ext adv channel map */
esp_ble_addr_type_t own_addr_type; /*!< ext adv own addresss type */
esp_ble_addr_type_t peer_addr_type; /*!< ext adv peer address type */
esp_bd_addr_t peer_addr; /*!< ext adv peer address */
esp_ble_adv_filter_t filter_policy; /*!< ext adv filter policy */
int8_t tx_power; /*!< ext adv tx power */
esp_ble_gap_pri_phy_t primary_phy; /*!< ext adv primary phy */
uint8_t max_skip; /*!< ext adv maximum skip */
esp_ble_gap_phy_t secondary_phy; /*!< ext adv secondary phy */
uint8_t sid; /*!< ext adv sid */
bool scan_req_notif; /*!< ext adv sacn request event notify */
} esp_ble_gap_ext_adv_params_t;
```
1M phy example->
Ext adv param:
```c
esp_ble_gap_ext_adv_params_t ext_adv_params_1M = {
.type = ESP_BLE_GAP_SET_EXT_ADV_PROP_CONNECTABLE,
.interval_min = 0x30,
.interval_max = 0x30,
.channel_map = ADV_CHNL_ALL,
.filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
.primary_phy = ESP_BLE_GAP_PHY_1M,
.max_skip = 0,
.secondary_phy = ESP_BLE_GAP_PHY_1M,
.sid = 0,
.scan_req_notif = false,
.own_addr_type = BLE_ADDR_TYPE_RANDOM,
};
```
Random addr for 1M phy:
```c
uint8_t addr_1m[6] = {0xc0, 0xde, 0x52, 0x00, 0x00, 0x01};
```
Ext adv data for 1M phy:
```c
static uint8_t raw_adv_data_1m[] = {
0x02, 0x01, 0x06,
0x02, 0x0a, 0xeb,
0x11, 0x09, 'E', 'S', 'P', '_', 'M', 'U', 'L', 'T', 'I', '_', 'A',
'D', 'V', '_', '1', 'M'
};
```
Once we config the all the adv instance we can start all the adv using the func esp_ble_gap_ext_adv_start which can post this to scanner side with respective param.
## GAP Event Handler
Once the Extended advertising data have been set, the GAP event `ESP_GAP_BLE_EXT_ADV_SET_PARAMS_COMPLETE_EVT, ESP_GAP_BLE_EXT_ADV_SET_RAND_ADDR_COMPLETE_EVT and ESP_GAP_BLE_EXT_ADV_DATA_SET_COMPLETE_EVT ` is triggered.
```c
static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
{
switch (event) {
case ESP_GAP_BLE_EXT_ADV_SET_RAND_ADDR_COMPLETE_EVT:
xSemaphoreGive(test_sem);
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_ADV_SET_RAND_ADDR_COMPLETE_EVT, status %d", param->ext
_adv_set_rand_addr.status);
break;
case ESP_GAP_BLE_EXT_ADV_SET_PARAMS_COMPLETE_EVT:
xSemaphoreGive(test_sem);
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_ADV_SET_PARAMS_COMPLETE_EVT, status %d", param->ext_ad
v_set_params.status);
break;
case ESP_GAP_BLE_EXT_ADV_DATA_SET_COMPLETE_EVT:
xSemaphoreGive(test_sem);
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_ADV_DATA_SET_COMPLETE_EVT, status %d", param->ext_adv_
data_set.status);
break;
case ESP_GAP_BLE_EXT_SCAN_RSP_DATA_SET_COMPLETE_EVT:
xSemaphoreGive(test_sem);
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_SCAN_RSP_DATA_SET_COMPLETE_EVT, status %d", param->sca
n_rsp_set.status);
break;
case ESP_GAP_BLE_EXT_ADV_START_COMPLETE_EVT:
xSemaphoreGive(test_sem);
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_ADV_START_COMPLETE_EVT, status %d", param->ext_adv_sta
rt.status);
break;
case ESP_GAP_BLE_EXT_ADV_STOP_COMPLETE_EVT:
xSemaphoreGive(test_sem);
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_ADV_STOP_COMPLETE_EVT, status %d", param->ext_adv_stop
.status);
break;
default:
break;
}
}
```
## Default config
This example by default configured with
1M phy extend adv, Connectable advertising
2M phy extend adv, Scannable advertising
1M phy legacy adv, ADV_IND
coded phy extend adv, Connectable advertising
We can change Ext adv param ( adv type ), Random addr and Raw data using above struct and output will be seen accordingly.
## Conclusion
In this document, we have gone through the Multi adv example code describing each section. The application is designed around the concept of Application Profiles. In addition, the procedures that this example uses to register event handlers are explained. The events follow a sequence of configuration steps, such as defining Extended advertising parameters, Random address and Raw dat with respective phy.

Wyświetl plik

@ -1,3 +1,59 @@
| Supported Targets | ESP32-C3 |
| ----------------- | -------- |
| Supported Targets | ESP32-C3 | ESP32-S3 |
| ----------------- | -------- | -------- |
# ESP_IDF Periodic Adv Example
This example support for the periodic advertisement which allow the scanner to sync with the advertiser so that scanner and advertiser wake up same time. It support extended adv with 2M phy in connectable mode.
To test this demo, we can run the [periodic_sync_demo](../peroidic_sync), which can do periodic scan and try to sync with periodic adv.
Please, check this [tutorial](tutorial/Periodic_adv_Example_Walkthrough.md) for more information about this example.
## How to Use Example
Before project configuration and build, be sure to set the correct chip target using:
```bash
idf.py set-target <chip_name>
```
### Hardware Required
* A development board with ESP32-C3 SoC, ESP32-S3 and BLE5.0 supported chips (e.g., ESP32-C3-DevKitC-1, etc.)
* A USB cable for Power supply and programming
See [Development Boards](https://www.espressif.com/en/products/devkits) for more information about it.
### Build and Flash
Run `idf.py -p PORT flash monitor` to build, flash and monitor the project.
(To exit the serial monitor, type ``Ctrl-]``.)
See the [Getting Started Guide](https://idf.espressif.com/) for full steps to configure and use ESP-IDF to build projects.
## Example Output
```
I (362) BTDM_INIT: BT controller compile version [3e61eea]
I (372) coexist: coexist rom version 8459080
I (372) phy_init: phy_version 500,985899c,Apr 19 2021,16:05:08
I (492) system_api: Base MAC address is not set
I (492) system_api: read default base MAC address from EFUSE
I (492) BTDM_INIT: Bluetooth MAC: 7c:df:a1:40:01:dd
I (712) MULTI_ADV_DEMO: ESP_GAP_BLE_EXT_ADV_SET_PARAMS_COMPLETE_EVT, status 0
I (712) MULTI_ADV_DEMO: ESP_GAP_BLE_EXT_ADV_SET_RAND_ADDR_COMPLETE_EVT, status 0
I (712) MULTI_ADV_DEMO: ESP_GAP_BLE_EXT_ADV_DATA_SET_COMPLETE_EVT, status 0
I (722) MULTI_ADV_DEMO: ESP_GAP_BLE_EXT_ADV_START_COMPLETE_EVT, status 0
I (732) MULTI_ADV_DEMO: ESP_GAP_BLE_PERIODIC_ADV_SET_PARAMS_COMPLETE_EVT, status 0
I (742) MULTI_ADV_DEMO: ESP_GAP_BLE_PERIODIC_ADV_DATA_SET_COMPLETE_EVT, status 0
I (742) MULTI_ADV_DEMO: ESP_GAP_BLE_PERIODIC_ADV_START_COMPLETE_EVT, status 0
```
## Troubleshooting
For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon.

Wyświetl plik

@ -0,0 +1,299 @@
# Periodic Adv Example Walkthrough
## introduction
In this document, We review the Periodic Adv example code which implements a Bluetooth Low Energy (BLE5.0) Multi adv profile on the ESP32C3. This example is designed the periodic advertisement which allow the scanner to sync with the advertiser so that scanner and advertiser wake up same time.
##include
First, lets take a look at the include
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_bt.h"
#include "esp_gap_ble_api.h"
#include "esp_gatts_api.h"
#include "esp_bt_defs.h"
#include "esp_bt_main.h"
#include "esp_gatt_common_api.h"
#include "sdkconfig.h"
#include "freertos/semphr.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 `"esp_bt.h"`, `"esp_bt_main.h"`, `"esp_gap_ble_api.h"` and `"esp_gatts_api.h"`, which expose the BLE APIs required to implement this example.
* `esp_bt.h`: implements BT controller and VHCI configuration procedures from the host side.
* `esp_bt_main.h`: implements initialization and enabling of the Bluedroid stack.
* `esp_gap_ble_api.h`: implements GAP configuration, such as advertising and connection parameters.
* `esp_gatts_api.h`: implements GATT configuration, such as creating services and characteristics.
## Main Entry Point
The entry point to this example is the app_main() function:
```c
void app_main(void)
{
esp_err_t ret;
// Initialize NVS.
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 );
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
ret = esp_bt_controller_init(&bt_cfg);
if (ret) {
ESP_LOGE(LOG_TAG, "%s initialize controller failed: %s\n", __func__, esp_err_to_name(ret)
);
return;
}
ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
if (ret) {
ESP_LOGE(LOG_TAG, "%s enable controller failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
ret = esp_bluedroid_init();
if (ret) {
ESP_LOGE(LOG_TAG, "%s init bluetooth failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
ret = esp_bluedroid_enable();
if (ret) {
ESP_LOGE(LOG_TAG, "%s enable bluetooth failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
ret = esp_ble_gap_register_callback(gap_event_handler);
if (ret){
ESP_LOGE(LOG_TAG, "gap register error, error code = %x", ret);
return;
}
vTaskDelay(200 / portTICK_PERIOD_MS);
test_sem = xSemaphoreCreateBinary();
// 2M phy extend adv, Connectable advertising
FUNC_SEND_WAIT_SEM(esp_ble_gap_ext_adv_set_params(EXT_ADV_HANDLE, &ext_adv_params_2M), test_s
em);
FUNC_SEND_WAIT_SEM(esp_ble_gap_ext_adv_set_rand_addr(EXT_ADV_HANDLE, addr_2m), test_sem);
FUNC_SEND_WAIT_SEM(esp_ble_gap_config_ext_adv_data_raw(EXT_ADV_HANDLE, sizeof(raw_ext_adv_dat
a_2m), &raw_ext_adv_data_2m[0]), test_sem);
// start all adv
FUNC_SEND_WAIT_SEM(esp_ble_gap_ext_adv_start(NUM_EXT_ADV, &ext_adv[0]), test_sem);
FUNC_SEND_WAIT_SEM(esp_ble_gap_periodic_adv_set_params(EXT_ADV_HANDLE, &periodic_adv_params),
test_sem);
FUNC_SEND_WAIT_SEM(esp_ble_gap_config_periodic_adv_data_raw(EXT_ADV_HANDLE, sizeof(periodic_a
dv_raw_data), &periodic_adv_raw_data[0]), test_sem);
FUNC_SEND_WAIT_SEM(esp_ble_gap_periodic_adv_start(EXT_ADV_HANDLE), test_sem);
return;
}
```
The main function starts by initializing the non-volatile storage library. This library allows to save key-value pairs in flash memory and is used by some components such as the Wi-Fi library to
save the SSID and password:
```c
ret = nvs_flash_init();
```
## BT Controller and Stack Initialization
The main function also 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:
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 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();
```
The Bluetooth stack is up and running at this point in the program flow, however the functionality of the application has not been defined yet. The functionality is defined by reacting to events such as what happens when another device tries to read or write parameters and establish a connection. The two main managers of events are the GAP and GATT event handlers. The application needs to register a callback function for each event handler in order to let the application know which functions are going to handle the GAP and GATT events:
```c
esp_ble_gap_register_callback(gap_event_handler);
```
The functions `gap_event_handler()` handle all the events that are pushed to the application from the BLE stack.
## Setting GAP Parameters
The register application event is the first one that is triggered during the lifetime of the program, this example uses the Profile A GATT event handle to configure the advertising parameters upon registration. This example has the option to use both standard Bluetooth Core Specification advertising parameters or a customized raw buffer. The option can be selected with the `CONFIG_SET_RAW_ADV_DATA` define. The raw advertising data can be used to implement iBeacons, Eddystone or other proprietaries, and custom frame types such as the ones used for Indoor Location Services that are different from the standard specifications.
The function is used to configure different types of extended advertisement types and legacy adv with 1M,2M and coded phy is esp_ble_gap_ext_adv_set_params , esp_ble_gap_ext_adv_set_rand_addr and esp_ble_gap_config_ext_adv_data_raw. Respective structure of each one of them mentioned below with one example:
```c
/**
* @brief ext adv parameters
*/
typedef struct {
esp_ble_ext_adv_type_mask_t type; /*!< ext adv type */
uint32_t interval_min; /*!< ext adv minimum interval */
uint32_t interval_max; /*!< ext adv maximum interval */
esp_ble_adv_channel_t channel_map; /*!< ext adv channel map */
esp_ble_addr_type_t own_addr_type; /*!< ext adv own addresss type */
esp_ble_addr_type_t peer_addr_type; /*!< ext adv peer address type */
esp_bd_addr_t peer_addr; /*!< ext adv peer address */
esp_ble_adv_filter_t filter_policy; /*!< ext adv filter policy */
int8_t tx_power; /*!< ext adv tx power */
esp_ble_gap_pri_phy_t primary_phy; /*!< ext adv primary phy */
uint8_t max_skip; /*!< ext adv maximum skip */
esp_ble_gap_phy_t secondary_phy; /*!< ext adv secondary phy */
uint8_t sid; /*!< ext adv sid */
bool scan_req_notif; /*!< ext adv sacn request event notify */
} esp_ble_gap_ext_adv_params_t;
```
2M phy example->
Ext adv param:
```c
esp_ble_gap_ext_adv_params_t ext_adv_params_2M = {
.type = ESP_BLE_GAP_SET_EXT_ADV_PROP_NONCONN_NONSCANNABLE_UNDIRECTED,
.interval_min = 0x30,
.interval_max = 0x30,
.channel_map = ADV_CHNL_ALL,
.filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
.primary_phy = ESP_BLE_GAP_PHY_1M,
.max_skip = 0,
.secondary_phy = ESP_BLE_GAP_PHY_2M,
.sid = 0,
.scan_req_notif = false,
.own_addr_type = BLE_ADDR_TYPE_RANDOM,
};
```
Ext adv Random addr:
```c
uint8_t addr_2m[6] = {0xc0, 0xde, 0x52, 0x00, 0x00, 0x02};
```
Ext adv raw data:
```c
static uint8_t raw_ext_adv_data_2m[] = {
0x02, 0x01, 0x06,
0x02, 0x0a, 0xeb,
0x13, 0x09, 'E', 'S', 'P', '_', 'M', 'U', 'L', 'T', 'I', '_', 'A',
'D', 'V', '_', '8', '0', 'M', 'S'
};
```
Similar thing for the periodic param :
The function is used for the esp_ble_gap_periodic_adv_set_params, esp_ble_gap_config_periodic_adv_data_raw and esp_ble_gap_periodic_adv_start. Respective structure of each one of them mentioned below with one example:
```c
static esp_ble_gap_periodic_adv_params_t periodic_adv_params = {
.interval_min = 0x40, // 80 ms interval
.interval_max = 0x40,
.properties = 0, // Do not include TX power
};
```
```c
static uint8_t periodic_adv_raw_data[] = {
0x02, 0x01, 0x06,
0x02, 0x0a, 0xeb,
0x03, 0x03, 0xab, 0xcd,
0x11, 0x09, 'E', 'S', 'P', '_', 'P', 'E', 'R', 'I', 'O', 'D', 'I',
'C', '_', 'A', 'D', 'V'
};
```
```c
static esp_ble_gap_ext_adv_t ext_adv[1] = {
// instance, duration, peroid
[0] = {EXT_ADV_HANDLE, 0, 0},
};
```
Once we config the all the adv instances, We can start advertising using the function esp_ble_gap_ext_adv_start a which can post this to scanner side with respective param.
## GAP Event Handler
Once the Extended advertising data have been set, the GAP event `ESP_GAP_BLE_EXT_ADV_SET_PARAMS_COMPLETE_EVT, ESP_GAP_BLE_EXT_ADV_SET_RAND_ADDR_COMPLETE_EVT,ESP_GAP_BLE_EXT_ADV_DATA_SET_COMPLETE_EVT ESP_GAP_BLE_PERIODIC_ADV_SET_PARAMS_COMPLETE_EVT, ESP_GAP_BLE_PERIODIC_ADV_DATA_SET_COMPLETE_EVT and ESP_GAP_BLE_PERIODIC_ADV_START_COMPLETE_EVT` is triggered.
```c
static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param){
switch (event) {
case ESP_GAP_BLE_EXT_ADV_SET_RAND_ADDR_COMPLETE_EVT:
xSemaphoreGive(test_sem);
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_ADV_SET_RAND_ADDR_COMPLETE_EVT, status %d", param->ext _adv_set_rand_addr.status);
break;
case ESP_GAP_BLE_EXT_ADV_SET_PARAMS_COMPLETE_EVT:
xSemaphoreGive(test_sem);
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_ADV_SET_PARAMS_COMPLETE_EVT, status %d", param->ext_adv_set_params.status);
break;
case ESP_GAP_BLE_EXT_ADV_DATA_SET_COMPLETE_EVT:
xSemaphoreGive(test_sem);
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_ADV_DATA_SET_COMPLETE_EVT, status %d", param->ext_adv_data_set.status);
break;
case ESP_GAP_BLE_EXT_SCAN_RSP_DATA_SET_COMPLETE_EVT:
xSemaphoreGive(test_sem);
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_SCAN_RSP_DATA_SET_COMPLETE_EVT, status %d", param->scan_rsp_set.status);
break;
case ESP_GAP_BLE_EXT_ADV_START_COMPLETE_EVT:
xSemaphoreGive(test_sem);
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_ADV_START_COMPLETE_EVT, status %d", param->ext_adv_start.status);
break;
case ESP_GAP_BLE_EXT_ADV_STOP_COMPLETE_EVT:
xSemaphoreGive(test_sem);
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_ADV_STOP_COMPLETE_EVT, status %d", param->ext_adv_stop.status);
break;
case ESP_GAP_BLE_PERIODIC_ADV_SET_PARAMS_COMPLETE_EVT:
xSemaphoreGive(test_sem);
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_PERIODIC_ADV_SET_PARAMS_COMPLETE_EVT, status %d", param->p
eroid_adv_set_params.status);
break;
case ESP_GAP_BLE_PERIODIC_ADV_DATA_SET_COMPLETE_EVT:
xSemaphoreGive(test_sem);
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_PERIODIC_ADV_DATA_SET_COMPLETE_EVT, status %d", param->per
iod_adv_data_set.status);
break;
case ESP_GAP_BLE_PERIODIC_ADV_START_COMPLETE_EVT:
xSemaphoreGive(test_sem);
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_PERIODIC_ADV_START_COMPLETE_EVT, status %d", param->period
_adv_start.status);
break;
default:
break;
}
}
```
## Default config
2M phy with connectable mode of periodic adv.
## Conclusion
In this document, we have gone through the Periodic adv example code describing each section. The application is designed around the concept of Application Profiles. In addition, the procedures that this example uses to register event handlers are explained. The events follow a sequence of configuration steps, such as defining Extended advertising parameters, Random address, Raw data, Periodic param, periodic data and start of Periodic adv in connectable mode.

Wyświetl plik

@ -1,3 +1,73 @@
| Supported Targets | ESP32-C3 |
| ----------------- | -------- |
| Supported Targets | ESP32-C3 | ESP32-S3 |
| ----------------- | -------- | -------- |
# ESP-IDF Periodic Sync Example
This example supports the periodic extended scan to scan the extended advertisement.
To test this demo, we can run the [periodic_adv_demo](../peroidic_adv), which can start extended advertisement with supported param.
Please, check this [tutorial](tutorial/Periodic_Sync_Example_Walkthrough.md) for more information about this example.
## How to Use Example
Before project configuration and build, be sure to set the correct chip target using:
```bash
idf.py set-target <chip_name>
```
### Hardware Required
* A development board with ESP32-C3 SoC, ESP32-S3 and BLE5.0 supported chips (e.g., ESP32-C3-DevKitC-1, etc.)
* A USB cable for Power supply and programming
See [Development Boards](https://www.espressif.com/en/products/devkits) for more information about it.
### Build and Flash
Run `idf.py -p PORT flash monitor` to build, flash and monitor the project.
(To exit the serial monitor, type ``Ctrl-]``.)
See the [Getting Started Guide](https://idf.espressif.com/) for full steps to configure and use ESP-IDF to build projects.
## Example Output
```
I (362) BTDM_INIT: BT controller compile version [3e61eea]
I (372) coexist: coexist rom version 8459080
I (372) phy_init: phy_version 500,985899c,Apr 19 2021,16:05:08
I (492) system_api: Base MAC address is not set
I (492) system_api: read default base MAC address from EFUSE
I (492) BTDM_INIT: Bluetooth MAC: 7c:df:a1:40:01:c5
Output1 Without advertisement:
I (712) PERIODIC_SYNC: ESP_GAP_BLE_SET_EXT_SCAN_PARAMS_COMPLETE_EVT, status 0
I (712) PERIODIC_SYNC: ESP_GAP_BLE_EXT_SCAN_START_COMPLETE_EVT, status 0
Output2 with advetisement:
I (712) PERIODIC_SYNC: ESP_GAP_BLE_SET_EXT_SCAN_PARAMS_COMPLETE_EVT, status 0
I (712) PERIODIC_SYNC: ESP_GAP_BLE_EXT_SCAN_START_COMPLETE_EVT, status 0
I (712) PERIODIC_SYNC: Start create sync with the peer device ESP_MULTI_ADV_80MS
I (722) PERIODIC_SYNC: ESP_GAP_BLE_PERIODIC_ADV_CREATE_SYNC_COMPLETE_EVT, status 0
I (812) PERIODIC_SYNC: ESP_GAP_BLE_PERIODIC_ADV_SYNC_ESTAB_EVT, status 0
I (812) sync addr: c0 de 52 00 00 02
I (812) PERIODIC_SYNC: sync handle 1 sid 0 perioic adv interval 64 adv phy 2
I (812) PERIODIC_SYNC: periodic adv report, sync handle 1 data status 0 data len 28 rssi -48
I (892) PERIODIC_SYNC: periodic adv report, sync handle 1 data status 0 data len 28 rssi -47
I (972) PERIODIC_SYNC: periodic adv report, sync handle 1 data status 0 data len 28 rssi -48
I (1052) PERIODIC_SYNC: periodic adv report, sync handle 1 data status 0 data len 28 rssi -47
I (1132) PERIODIC_SYNC: periodic adv report, sync handle 1 data status 0 data len 28 rssi -49
I (1212) PERIODIC_SYNC: periodic adv report, sync handle 1 data status 0 data len 28 rssi -48
I (1292) PERIODIC_SYNC: ESP_GAP_BLE_PERIODIC_ADV_SYNC_LOST_EVT, sync handle 1
```
## Troubleshooting
For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon.

Wyświetl plik

@ -0,0 +1,354 @@
#Periodic Sync Example Walkthrough
## Introduction
In this tutorial, the Periodic sync example code for the ESP32C3 is reviewed. The code implement Bluetooth Low Energy (BLE5.0) periodic sync , which scans for nearby peripheral which can support legacy, extended and periodic advertisement. Periodic Sync allow the advertiser to sync with scanner so that scanner and advertiser wake up at same time.
* ADV_EXT_IND is over primary advertising channels
* AUX_ADV_IND and AUX_SYNC_IND are over secondary advertising channels
Little info about the EXT_ADV_IND , AUX_ADV_IND and AUX_SYNC_IND with scanner support of periodic sync.
ADV_EXT_IND is over primary advertising channels and is used to indicate that an advertisement will be sent on a secondary advertisement channel. The information in ADV_EXT_IND will inform the scanner:
* Which secondary advertising channel will be used by AUX_ADV_IND
* Which PHY will be used by AUX_ADV_IND, 1M PHY, 2M PHY, or 1M Coded PHY
* When AUX_ADV_IND will be presented on that specified secondary advertising channel
If the scanner is capable of periodic advertising, it will enable its receiver at a specific channel and PHY at a specific time slot.
AUX_ADV_IND is over the secondary advertising channels and is used to indicate a periodic advertising event. The information in AUX_ADV_IND, which points to the first AUX_SYNC_IND, are:
* The offset time of the next periodic advertising packet
* The interval of periodic advertising
* The secondary channel map used through this periodic advertising lifetime
Access address, etc.
With this information, the scanner can synchronize with the advertiser and they will dance together.
*AUX_SYNC_IND includes the AdvData which needs to be periodically advertised.
## Includes
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h
#include "esp_system.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_bt.h"
#include "esp_gap_ble_api.h"
#include "esp_gatts_api.h"
#include "esp_bt_defs.h"
#include "esp_bt_main.h"
#include "esp_gatt_common_api.h"
#include "sdkconfig.h"
#include "freertos/semphr.h"
```
These `includes` are required for the FreeRTOS and underlaying system components to run, including the logging functionality and a library to store data in non-volatile flash memory. We are interested in `“bt.h”`, `“esp_bt_main.h”`, `"esp_gap_ble_api.h"` and `“esp_gattc_api.h”`, which expose the BLE APIs required to implement this example.
* `esp_bt.h`: configures the BT controller and VHCI from the host side.
* `esp_bt_main.h`: initializes and enables the Bluedroid stack.
* `esp_gap_ble_api.h`: implements the GAP configuration, such as advertising and connection parameters.
* `esp_gattc_api.h`: implements the GATT Client configuration, such as connecting to peripherals and searching for services.
## Main Entry Point
```c
void app_main(void)
{
esp_err_t ret;
// Initialize NVS.
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 );
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
ret = esp_bt_controller_init(&bt_cfg);
if (ret) {
ESP_LOGE(LOG_TAG, "%s initialize controller failed: %s\n", __func__, esp_err_to_name(ret)
);
return;
}
ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
if (ret) {
ESP_LOGE(LOG_TAG, "%s enable controller failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
ret = esp_bluedroid_init();
if (ret) {
ESP_LOGE(LOG_TAG, "%s init bluetooth failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
ret = esp_bluedroid_enable();
if (ret) {
ESP_LOGE(LOG_TAG, "%s enable bluetooth failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
ret = esp_ble_gap_register_callback(gap_event_handler);
if (ret){
ESP_LOGE(LOG_TAG, "gap register error, error code = %x", ret);
return;
}
vTaskDelay(200 / portTICK_PERIOD_MS);
test_sem = xSemaphoreCreateBinary();
FUNC_SEND_WAIT_SEM(esp_ble_gap_set_ext_scan_params(&ext_scan_params), test_sem);
FUNC_SEND_WAIT_SEM(esp_ble_gap_start_ext_scan(EXT_SCAN_DURATION, EXT_SCAN_PERIOD), test_sem);
return;
}
```
The main function starts by initializing the non-volatile storage library. This library allows to save key-value pairs in flash memory and is used by some components such as the Wi-Fi library to save the SSID and password:
```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 also 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:
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 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();
```
The main function ends by registering the GAP and GATT event handlers, as well as the Application Profile and set the maximum supported MTU size.
```c
//register the callback function to the gap module
ret = esp_ble_gap_register_callback(esp_gap_cb);
//register the callback function to the gattc module
ret = esp_ble_gattc_register_callback(esp_gattc_cb);
ret = esp_ble_gattc_app_register(PROFILE_A_APP_ID);
esp_err_t local_mtu_ret = esp_ble_gatt_set_local_mtu(500);
if (local_mtu_ret){
ESP_LOGE(GATTC_TAG, "set local MTU failed, error code = %x", local_mtu_ret);
}
```
The GAP and GATT event handlers are the functions used to catch the events generated by the BLE stack and execute functions to configure parameters of the application. Moreover, the event handlers are also used to handle read and write events coming from the central. The GAP event handler takes care of scanning and connecting to servers and the GATT handler manages events that happen after the client has connected to a server, such as searching for services and writing and reading data. The GAP and GATT event handlers are registered by using:
```c
esp_ble_gap_register_callback();
esp_ble_gattc_register_callback();
```
The functions `esp_gap_cb()` and `esp_gattc_cb()` handle all the events generated by the BLE stack.
## Setting Scan Parameters
if interested. However, in order to perform the scanning, first the configuration parameters needto be set.
The func will be called in the context of bin semaphore esp_ble_gap_set_ext_scan_params,which takes the param as struct esp_ble_ext_scan_params_t
```c
/**
* @brief ext scan parameters
*/
typedef struct {
esp_ble_addr_type_t own_addr_type; /*!< ext scan own addresss type */
esp_ble_scan_filter_t filter_policy; /*!< ext scan filter policy */
esp_ble_scan_duplicate_t scan_duplicate; /*!< ext scan duplicate scan */
esp_ble_ext_scan_cfg_mask_t cfg_mask; /*!< ext scan config mask */
esp_ble_ext_scan_cfg_t uncoded_cfg; /*!< ext scan uncoded config parameters */
esp_ble_ext_scan_cfg_t coded_cfg; /*!< ext scan coded config parameters */
} esp_ble_ext_scan_params_t;
/**
* @brief ext scan config
*/
typedef struct {
esp_ble_scan_type_t scan_type; /*!< ext scan type */
uint16_t scan_interval; /*!< ext scan interval. This is defined as the ti
me interval from when the Controller started its last LE scan until it begins the subsequent LE s
can.*/
//Range: 0x0004 to 0x4000
//Default: 0x0010 (10 ms)
//Time = N * 0.625 msec
//Time Range: 2.5 msec to 10.24 seconds
uint16_t scan_window; /*!< ext scan window. The duration of the LE scan
. LE_Scan_Window shall be less than or equal to LE_Scan_Interval*/
//Range: 0x0004 to 0x4000 //Defaul
t: 0x0010 (10 ms)
//Time = N * 0.625 msec
//Time Range: 2.5 msec to 10240 msec
} esp_ble_ext_scan_cfg_t;
```
An it is initialized as :
```c
static esp_ble_ext_scan_params_t ext_scan_params = {
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
.filter_policy = BLE_SCAN_FILTER_ALLOW_ALL,
.scan_duplicate = BLE_SCAN_DUPLICATE_ENABLE,
.cfg_mask = ESP_BLE_GAP_EXT_SCAN_CFG_UNCODE_MASK | ESP_BLE_GAP_EXT_SCAN_CFG_CODE_MASK,
.uncoded_cfg = {BLE_SCAN_TYPE_ACTIVE, 40, 40},
.coded_cfg = {BLE_SCAN_TYPE_ACTIVE, 40, 40},
};
```
same for the periodic sync:
```c
/**
* @brief periodic adv sync parameters
*/
typedef struct {
esp_ble_gap_sync_t filter_policy; /*!< periodic advertising sync filter policy */
uint8_t sid; /*!< periodic advertising sid */
esp_ble_addr_type_t addr_type; /*!< periodic advertising address type */
esp_bd_addr_t addr; /*!< periodic advertising address */
uint16_t skip; /*!< the maximum number of periodic advertising events t
hat can be skipped */
uint16_t sync_timeout; /*!< synchronization timeout */
} esp_ble_gap_periodic_adv_sync_params_t;
```
An it is initialized as:
```c
static esp_ble_gap_periodic_adv_sync_params_t periodic_adv_sync_params = {
.filter_policy = 0,
.sid = 0,
.addr_type = BLE_ADDR_TYPE_RANDOM,
.skip = 10,
.sync_timeout = 1000,
};
```
The BLE scan parameters are configured so that the type of scanning is active (includes reading he scanning response), it is of public type, allows any advertising device to be read and has a scanning interval of 80 ms (1.25 ms * 0x40) and a scanning window of 80 ms (1.25 ms * 0x40).
## Start Scanning
This func invoke to start the scan to get near by discover devices esp_ble_gap_start_ext_scan.
## Getting Scan Results
The Below call back fun used for the event from start of scan to the end of getting adv report extanded as well as periodic report.
We can differer extended and periodic adv using this event ESP_GAP_BLE_PERIODIC_ADV_REPORT_EVT and ESP_GAP_BLE_EXT_ADV_REPORT_EVT.
```c
static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
{
switch (event) {
case ESP_GAP_BLE_SET_EXT_SCAN_PARAMS_COMPLETE_EVT:
xSemaphoreGive(test_sem);
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_SET_EXT_SCAN_PARAMS_COMPLETE_EVT, status %d", param->set_e
xt_scan_params.status);
break;
case ESP_GAP_BLE_EXT_SCAN_START_COMPLETE_EVT:
xSemaphoreGive(test_sem);
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_SCAN_START_COMPLETE_EVT, status %d", param->ext_scan_s
tart.status);
break;
case ESP_GAP_BLE_EXT_SCAN_STOP_COMPLETE_EVT:
xSemaphoreGive(test_sem);
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_SCAN_STOP_COMPLETE_EVT, status %d", param->period_adv_
stop.status);
break;
case ESP_GAP_BLE_PERIODIC_ADV_CREATE_SYNC_COMPLETE_EVT:
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_PERIODIC_ADV_CREATE_SYNC_COMPLETE_EVT, status %d", param->
period_adv_create_sync.status);
break;
case ESP_GAP_BLE_PERIODIC_ADV_SYNC_CANCEL_COMPLETE_EVT:
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_PERIODIC_ADV_SYNC_CANCEL_COMPLETE_EVT, status %d", param->
period_adv_sync_cancel.status);
break;
case ESP_GAP_BLE_PERIODIC_ADV_SYNC_TERMINATE_COMPLETE_EVT:
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_PERIODIC_ADV_SYNC_TERMINATE_COMPLETE_EVT, status %d", para
m->period_adv_sync_term.status);
break;
case ESP_GAP_BLE_PERIODIC_ADV_SYNC_LOST_EVT:
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_PERIODIC_ADV_SYNC_LOST_EVT, sync handle %d", param->period
ic_adv_sync_lost.sync_handle);
break;
case ESP_GAP_BLE_PERIODIC_ADV_SYNC_ESTAB_EVT:
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_PERIODIC_ADV_SYNC_ESTAB_EVT, status %d", param->periodic_a
dv_sync_estab.status);
esp_log_buffer_hex("sync addr", param->periodic_adv_sync_estab.adv_addr, 6);
ESP_LOGI(LOG_TAG, "sync handle %d sid %d perioic adv interval %d adv phy %d", param->periodic_adv_sync_estab.sync_handle,
param->periodic_adv_sync_estab.sid,
param->periodic_adv_sync_estab.period_adv_interval,
param->periodic_adv_sync_estab.adv_phy);
break;
case ESP_GAP_BLE_EXT_ADV_REPORT_EVT: {
uint8_t *adv_name = NULL;
uint8_t adv_name_len = 0;
adv_name = esp_ble_resolve_adv_data(param->ext_adv_report.params.adv_data, ESP_BLE_AD_TYPE_NAME_CMPL, &adv_name_len);
if ((adv_name != NULL) && (memcmp(adv_name, "ESP_MULTI_ADV_80MS", adv_name_len) == 0)
&& !periodic_sync) {
periodic_sync = true;
char adv_temp_name[30] = {'0'};
memcpy(adv_temp_name, adv_name, adv_name_len);
ESP_LOGI(LOG_TAG, "Start create sync with the peer device %s", adv_temp_name);
periodic_adv_sync_params.sid = param->ext_adv_report.params.sid;
periodic_adv_sync_params.addr_type = param->ext_adv_report.params.addr_type;
memcpy(periodic_adv_sync_params.addr, param->ext_adv_report.params.addr, sizeof(esp_bd_addr_t));
esp_ble_gap_periodic_adv_create_sync(&periodic_adv_sync_params);
}
}
break;
case ESP_GAP_BLE_PERIODIC_ADV_REPORT_EVT:
ESP_LOGI(LOG_TAG, "periodic adv report, sync handle %d data status %d data len %d rssi %d
", param->period_adv_report.params.sync_handle,
param->period_adv_report.params.data_status,
param->period_adv_report.params.data_length,
param->period_adv_report.params.rssi);
break;
default:
break;
}
}
```
## Default Config
Here we are doing scan as Active with the fixed duration of 80msec.
## Conclusion
We have reviewed the Periodic Sync example code for the ESP32C3. This example scans for nearby devices which support extended adv and periodic adv.