1# Multi Adv Example Walkthrough
2
3## introduction
4
5In 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.
6
7## Includes
8
9First, let’s take a look at the include
10
11```c
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include "freertos/FreeRTOS.h"
16#include "freertos/task.h"
17#include "freertos/event_groups.h"
18#include "esp_system.h"
19#include "esp_log.h"
20#include "nvs_flash.h"
21#include "esp_bt.h"
22#include "esp_gap_ble_api.h"
23#include "esp_gatts_api.h"
24#include "esp_bt_defs.h"
25#include "esp_bt_main.h"
26#include "esp_gatt_common_api.h"
27#include "sdkconfig.h"
28```
29
30These 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.
31
32 * `esp_bt.h`: implements BT controller and VHCI configuration procedures from the host side.
33 * `esp_bt_main.h`: implements initialization and enabling of the Bluedroid stack.
34 * `esp_gap_ble_api.h`: implements GAP configuration, such as advertising and connection parameters.
35 * `esp_gatts_api.h`: implements GATT configuration, such as creating services and characteristics.
36
37## Main Entry Point
38
39The entry point to this example is the app_main() function:
40
41```c
42void app_main(void)
43{
44    esp_err_t ret;
45
46    // Initialize NVS.
47    ret = nvs_flash_init();
48    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
49        ESP_ERROR_CHECK(nvs_flash_erase());
50        ret = nvs_flash_init();
51    }
52    ESP_ERROR_CHECK( ret );
53
54    ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));
55
56    esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
57    ret = esp_bt_controller_init(&bt_cfg);
58    if (ret) {
59        ESP_LOGE(LOG_TAG, "%s initialize controller failed: %s\n", __func__, esp_err_to_name(ret));
60        return;
61    }
62
63    ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
64    if (ret) {
65        ESP_LOGE(LOG_TAG, "%s enable controller failed: %s\n", __func__, esp_err_to_name(ret));
66        return;
67    }
68    ret = esp_bluedroid_init();
69    if (ret) {
70        ESP_LOGE(LOG_TAG, "%s init bluetooth failed: %s\n", __func__, esp_err_to_name(ret));
71        return;
72    }
73    ret = esp_bluedroid_enable();
74    if (ret) {
75        ESP_LOGE(LOG_TAG, "%s enable bluetooth failed: %s\n", __func__, esp_err_to_name(ret));
76        return;
77    }
78    ret = esp_ble_gap_register_callback(gap_event_handler);
79    if (ret){
80        ESP_LOGE(LOG_TAG, "gap register error, error code = %x", ret);
81        return;
82
83   }
84
85   vTaskDelay(200 / portTICK_PERIOD_MS);
86
87   test_sem = xSemaphoreCreateBinary();
88   // 1M phy extend adv, Connectable advertising
89   FUNC_SEND_WAIT_SEM(esp_ble_gap_ext_adv_set_params(0, &ext_adv_params_1M), test_sem);
90   FUNC_SEND_WAIT_SEM(esp_ble_gap_ext_adv_set_rand_addr(0, addr_1m), test_sem);
91   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);
92
93   // 2M phy extend adv, Scannable advertising
94   FUNC_SEND_WAIT_SEM(esp_ble_gap_ext_adv_set_params(1, &ext_adv_params_2M), test_sem);
95   FUNC_SEND_WAIT_SEM(esp_ble_gap_ext_adv_set_rand_addr(1, addr_2m), test_sem);
96   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);
97
98   // 1M phy legacy adv, ADV_IND
99   FUNC_SEND_WAIT_SEM(esp_ble_gap_ext_adv_set_params(2, &legacy_adv_params), test_sem);
100   FUNC_SEND_WAIT_SEM(esp_ble_gap_ext_adv_set_rand_addr(2, addr_legacy), test_sem);
101   FUNC_SEND_WAIT_SEM(esp_ble_gap_config_ext_adv_data_raw(2, sizeof(legacy_adv_data), &legacy_adv_data[0]), test_sem);
102   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);
103
104   // coded phy extend adv, Connectable advertising
105   FUNC_SEND_WAIT_SEM(esp_ble_gap_ext_adv_set_params(3, &ext_adv_params_coded), test_sem);
106   FUNC_SEND_WAIT_SEM(esp_ble_gap_ext_adv_set_rand_addr(3, addr_coded), test_sem);
107   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);
108
109   // start all adv
110   FUNC_SEND_WAIT_SEM(esp_ble_gap_ext_adv_start(4, &ext_adv[0]), test_sem);
111
112   return;
113
114}
115```
116The 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:
117
118```c
119ret = nvs_flash_init();
120```
121## BT Controller and Stack Initialization
122
123The 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:
124
125```c
126esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
127ret = esp_bt_controller_init(&bt_cfg);
128```
129
130Next, the controller is enabled in BLE Mode.
131
132```c
133ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
134```
135> The controller should be enabled in `ESP_BT_MODE_BTDM`, if you want to use the dual mode (BLE + BT).
136
137There are four Bluetooth modes supported:
138
1391. `ESP_BT_MODE_IDLE`: Bluetooth not running
1402. `ESP_BT_MODE_BLE`: BLE mode
1413. `ESP_BT_MODE_CLASSIC_BT`: BT Classic mode
1424. `ESP_BT_MODE_BTDM`: Dual mode (BLE + BT Classic)
143
144After 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:
145
146```c
147ret = esp_bluedroid_init();
148ret = esp_bluedroid_enable();
149```
150The 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
151such 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
152to 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:
153
154```c
155esp_ble_gap_register_callback(gap_event_handler);
156```
157The functions  `gap_event_handler()` handle all the events that are pu
158shed to the application from the BLE stack.
159
160## Setting GAP Parameters
161
162The 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.
163
164The 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:
165
166```c
167/**
168* @brief ext adv parameters
169*/
170typedef struct {
171    esp_ble_ext_adv_type_mask_t type;   /*!< ext adv type */
172    uint32_t interval_min;              /*!< ext adv minimum interval */
173    uint32_t interval_max;              /*!< ext adv maximum interval */
174    esp_ble_adv_channel_t channel_map;  /*!< ext adv channel map */
175    esp_ble_addr_type_t own_addr_type;  /*!< ext adv own addresss type */
176    esp_ble_addr_type_t peer_addr_type; /*!< ext adv peer address type */
177    esp_bd_addr_t peer_addr;            /*!< ext adv peer address */
178    esp_ble_adv_filter_t filter_policy; /*!< ext adv filter policy */
179    int8_t tx_power;                    /*!< ext adv tx power */
180    esp_ble_gap_pri_phy_t primary_phy;  /*!< ext adv primary phy */
181    uint8_t max_skip;                   /*!< ext adv maximum skip */
182    esp_ble_gap_phy_t secondary_phy;    /*!< ext adv secondary phy */
183    uint8_t sid;                        /*!< ext adv sid */
184    bool scan_req_notif;                /*!< ext adv sacn request event notify */
185} esp_ble_gap_ext_adv_params_t;
186
187```
1881M phy example->
189Ext adv param:
190
191```c
192esp_ble_gap_ext_adv_params_t ext_adv_params_1M = {
193    .type = ESP_BLE_GAP_SET_EXT_ADV_PROP_CONNECTABLE,
194    .interval_min = 0x30,
195    .interval_max = 0x30,
196    .channel_map = ADV_CHNL_ALL,
197    .filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
198    .primary_phy = ESP_BLE_GAP_PHY_1M,
199    .max_skip = 0,
200    .secondary_phy = ESP_BLE_GAP_PHY_1M,
201    .sid = 0,
202    .scan_req_notif = false,
203    .own_addr_type = BLE_ADDR_TYPE_RANDOM,
204};
205
206```
207Random addr for 1M phy:
208
209```c
210uint8_t addr_1m[6] = {0xc0, 0xde, 0x52, 0x00, 0x00, 0x01};
211
212```
213Ext adv data for 1M phy:
214
215```c
216static uint8_t raw_adv_data_1m[] = {
217        0x02, 0x01, 0x06,
218        0x02, 0x0a, 0xeb,
219        0x11, 0x09, 'E', 'S', 'P', '_', 'M', 'U', 'L', 'T', 'I', '_', 'A',
220        'D', 'V', '_', '1', 'M'
221};
222
223```
224
225Once 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.
226
227## GAP Event Handler
228Once 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.
229
230```c
231static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
232{
233    switch (event) {
234    case ESP_GAP_BLE_EXT_ADV_SET_RAND_ADDR_COMPLETE_EVT:
235        xSemaphoreGive(test_sem);
236        ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_ADV_SET_RAND_ADDR_COMPLETE_EVT, status %d", param->ext
237_adv_set_rand_addr.status);
238        break;
239    case ESP_GAP_BLE_EXT_ADV_SET_PARAMS_COMPLETE_EVT:
240        xSemaphoreGive(test_sem);
241        ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_ADV_SET_PARAMS_COMPLETE_EVT, status %d", param->ext_ad
242v_set_params.status);
243        break;
244    case ESP_GAP_BLE_EXT_ADV_DATA_SET_COMPLETE_EVT:
245        xSemaphoreGive(test_sem);
246        ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_ADV_DATA_SET_COMPLETE_EVT, status %d", param->ext_adv_
247data_set.status);
248        break;
249    case ESP_GAP_BLE_EXT_SCAN_RSP_DATA_SET_COMPLETE_EVT:
250        xSemaphoreGive(test_sem);
251        ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_SCAN_RSP_DATA_SET_COMPLETE_EVT, status %d", param->sca
252n_rsp_set.status);
253        break;
254    case ESP_GAP_BLE_EXT_ADV_START_COMPLETE_EVT:
255        xSemaphoreGive(test_sem);
256        ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_ADV_START_COMPLETE_EVT, status %d", param->ext_adv_sta
257rt.status);
258        break;
259    case ESP_GAP_BLE_EXT_ADV_STOP_COMPLETE_EVT:
260        xSemaphoreGive(test_sem);
261        ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_ADV_STOP_COMPLETE_EVT, status %d", param->ext_adv_stop
262.status);
263        break;
264    default:
265        break;
266    }
267}
268
269```
270## Default config
271
272This example by default  configured with
2731M phy extend adv, Connectable advertising
2742M phy extend adv, Scannable advertising
2751M phy legacy adv, ADV_IND
276coded phy extend adv, Connectable advertising
277
278We can change Ext adv param ( adv type ), Random addr and Raw data using above struct and output will be seen accordingly.
279
280
281## Conclusion
282In 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.
283