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