diff --git a/components/protocomm/src/simple_ble/simple_ble.c b/components/protocomm/src/simple_ble/simple_ble.c index 1d77493a3bc..b44ad075743 100644 --- a/components/protocomm/src/simple_ble/simple_ble.c +++ b/components/protocomm/src/simple_ble/simple_ble.c @@ -26,10 +26,50 @@ static const char *TAG = "simple_ble"; static simple_ble_cfg_t *g_ble_cfg_p; static uint16_t *g_gatt_table_map; -static uint8_t adv_config_done; +#if SIMPLE_BLE_LEGACY_ADV || SIMPLE_BLE_EXT_ADV +static uint8_t adv_config_pending_mask; +#endif + static esp_bd_addr_t s_cached_remote_bda = {0x0,}; -#define adv_config_flag (1 << 0) -#define scan_rsp_config_flag (1 << 1) +#if SIMPLE_BLE_LEGACY_ADV +#define ADV_CONFIG_FLAG (1 << 0) +#define SCAN_RSP_CONFIG_FLAG (1 << 1) +#elif SIMPLE_BLE_EXT_ADV +#define SIMPLE_BLE_EXT_ADV_INSTANCE 0 +#define EXT_ADV_PARAMS_CONFIG_FLAG (1 << 0) +#define EXT_ADV_DATA_CONFIG_FLAG (1 << 1) +#define EXT_SCAN_RSP_CONFIG_FLAG (1 << 2) +#define EXT_ADV_RAND_ADDR_CONFIG_FLAG (1 << 3) + +static esp_ble_gap_ext_adv_params_t s_ext_adv_params = { + .type = ESP_BLE_GAP_SET_EXT_ADV_PROP_LEGACY_IND, + .interval_min = 0x100, + .interval_max = 0x100, + .channel_map = ADV_CHNL_ALL, + .own_addr_type = BLE_ADDR_TYPE_PUBLIC, + .filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY, + .tx_power = EXT_ADV_TX_PWR_NO_PREFERENCE, + .primary_phy = ESP_BLE_GAP_PHY_1M, + .max_skip = 0, + .secondary_phy = ESP_BLE_GAP_PHY_1M, + .sid = 0, + .scan_req_notif = false, +}; + +static const esp_ble_gap_ext_adv_t s_ext_adv = { + .instance = SIMPLE_BLE_EXT_ADV_INSTANCE, + .duration = 0, + .max_events = 0, +}; + +static void simple_ble_ext_adv_start(void) +{ + esp_err_t err = esp_ble_gap_ext_adv_start(1, &s_ext_adv); + if (err != ESP_OK) { + ESP_LOGE(TAG, "ext_adv_start failed, error code = 0x%x", err); + } +} +#endif uint8_t get_keep_ble_on() { @@ -59,6 +99,7 @@ const uint8_t *simple_ble_get_uuid128(uint16_t handle) return NULL; } +#if SIMPLE_BLE_LEGACY_ADV static void simple_ble_set_random_addr_if_configured(void) { if (g_ble_cfg_p->ble_addr == NULL) { @@ -72,6 +113,7 @@ static void simple_ble_set_random_addr_if_configured(void) ESP_LOGW(TAG, "Failed to set random address, using configured address type"); } } +#endif static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) { @@ -80,24 +122,83 @@ static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param } switch (event) { +#if SIMPLE_BLE_LEGACY_ADV case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: - adv_config_done &= (~adv_config_flag); + if (param->adv_data_cmpl.status != ESP_BT_STATUS_SUCCESS) { + ESP_LOGE(TAG, "adv_data_set failed, status %d", param->adv_data_cmpl.status); + break; + } + adv_config_pending_mask &= (~ADV_CONFIG_FLAG); simple_ble_set_random_addr_if_configured(); - if (adv_config_done == 0) { + if (adv_config_pending_mask == 0) { esp_ble_gap_start_advertising(&g_ble_cfg_p->adv_params); } break; case ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT: - adv_config_done &= (~scan_rsp_config_flag); + if (param->scan_rsp_data_cmpl.status != ESP_BT_STATUS_SUCCESS) { + ESP_LOGE(TAG, "scan_rsp_data_set failed, status %d", param->scan_rsp_data_cmpl.status); + break; + } + adv_config_pending_mask &= (~SCAN_RSP_CONFIG_FLAG); simple_ble_set_random_addr_if_configured(); - if (adv_config_done == 0) { + if (adv_config_pending_mask == 0) { esp_ble_gap_start_advertising(&g_ble_cfg_p->adv_params); } break; +#elif SIMPLE_BLE_EXT_ADV + case ESP_GAP_BLE_EXT_ADV_SET_PARAMS_COMPLETE_EVT: + if (param->ext_adv_set_params.status != ESP_BT_STATUS_SUCCESS || + param->ext_adv_set_params.instance != SIMPLE_BLE_EXT_ADV_INSTANCE) { + ESP_LOGE(TAG, "ext_adv_set_params failed, status %d, instance %d", + param->ext_adv_set_params.status, param->ext_adv_set_params.instance); + break; + } + adv_config_pending_mask &= (~EXT_ADV_PARAMS_CONFIG_FLAG); + if (adv_config_pending_mask == 0) { + simple_ble_ext_adv_start(); + } + break; + case ESP_GAP_BLE_EXT_ADV_SET_RAND_ADDR_COMPLETE_EVT: + if (param->ext_adv_set_rand_addr.status != ESP_BT_STATUS_SUCCESS || + param->ext_adv_set_rand_addr.instance != SIMPLE_BLE_EXT_ADV_INSTANCE) { + ESP_LOGE(TAG, "ext_adv_set_rand_addr failed, status %d, instance %d", + param->ext_adv_set_rand_addr.status, param->ext_adv_set_rand_addr.instance); + break; + } + adv_config_pending_mask &= (~EXT_ADV_RAND_ADDR_CONFIG_FLAG); + if (adv_config_pending_mask == 0) { + simple_ble_ext_adv_start(); + } + break; + case ESP_GAP_BLE_EXT_ADV_DATA_SET_COMPLETE_EVT: + if (param->ext_adv_data_set.status != ESP_BT_STATUS_SUCCESS || + param->ext_adv_data_set.instance != SIMPLE_BLE_EXT_ADV_INSTANCE) { + ESP_LOGE(TAG, "ext_adv_data_set failed, status %d, instance %d", + param->ext_adv_data_set.status, param->ext_adv_data_set.instance); + break; + } + adv_config_pending_mask &= (~EXT_ADV_DATA_CONFIG_FLAG); + if (adv_config_pending_mask == 0) { + simple_ble_ext_adv_start(); + } + break; + case ESP_GAP_BLE_EXT_SCAN_RSP_DATA_SET_COMPLETE_EVT: + if (param->scan_rsp_set.status != ESP_BT_STATUS_SUCCESS || + param->scan_rsp_set.instance != SIMPLE_BLE_EXT_ADV_INSTANCE) { + ESP_LOGE(TAG, "ext_scan_rsp_data_set failed, status %d, instance %d", + param->scan_rsp_set.status, param->scan_rsp_set.instance); + break; + } + adv_config_pending_mask &= (~EXT_SCAN_RSP_CONFIG_FLAG); + if (adv_config_pending_mask == 0) { + simple_ble_ext_adv_start(); + } + break; +#endif case ESP_GAP_BLE_SEC_REQ_EVT: esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, true); break; @@ -145,18 +246,65 @@ static void gatts_profile_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_ ESP_LOGE(TAG, "set device name failed, error code = 0x%x", ret); return; } +#if SIMPLE_BLE_LEGACY_ADV ret = esp_ble_gap_config_adv_data(g_ble_cfg_p->adv_data_p); if (ret) { ESP_LOGE(TAG, "config raw adv data failed, error code = 0x%x ", ret); return; } - adv_config_done |= adv_config_flag; + adv_config_pending_mask |= ADV_CONFIG_FLAG; ret = esp_ble_gap_config_adv_data(g_ble_cfg_p->scan_rsp_data_p); if (ret) { ESP_LOGE(TAG, "config raw scan rsp data failed, error code = 0x%x", ret); return; } - adv_config_done |= scan_rsp_config_flag; + adv_config_pending_mask |= SCAN_RSP_CONFIG_FLAG; +#elif SIMPLE_BLE_EXT_ADV + s_ext_adv_params.own_addr_type = BLE_ADDR_TYPE_PUBLIC; + if (g_ble_cfg_p->ble_addr != NULL) { + s_ext_adv_params.own_addr_type = BLE_ADDR_TYPE_RANDOM; + } + + /* Pre-set all expected flags before the first async call. */ + adv_config_pending_mask = EXT_ADV_PARAMS_CONFIG_FLAG | + EXT_ADV_DATA_CONFIG_FLAG | + EXT_SCAN_RSP_CONFIG_FLAG; + if (g_ble_cfg_p->ble_addr != NULL) { + adv_config_pending_mask |= EXT_ADV_RAND_ADDR_CONFIG_FLAG; + } + + ret = esp_ble_gap_ext_adv_set_params(SIMPLE_BLE_EXT_ADV_INSTANCE, &s_ext_adv_params); + if (ret) { + ESP_LOGE(TAG, "ext_adv_set_params failed, error code = 0x%x", ret); + return; + } + + if (g_ble_cfg_p->ble_addr != NULL) { + esp_bd_addr_t rand_addr; + memcpy(rand_addr, g_ble_cfg_p->ble_addr, sizeof(esp_bd_addr_t)); + ret = esp_ble_gap_ext_adv_set_rand_addr(SIMPLE_BLE_EXT_ADV_INSTANCE, rand_addr); + if (ret) { + ESP_LOGE(TAG, "ext_adv_set_rand_addr failed, error code = 0x%x", ret); + return; + } + } + + ret = esp_ble_gap_config_ext_adv_data_raw(SIMPLE_BLE_EXT_ADV_INSTANCE, + g_ble_cfg_p->raw_adv_data_len, + g_ble_cfg_p->raw_adv_data_p); + if (ret) { + ESP_LOGE(TAG, "config_ext_adv_data_raw failed, error code = 0x%x", ret); + return; + } + + ret = esp_ble_gap_config_ext_scan_rsp_data_raw(SIMPLE_BLE_EXT_ADV_INSTANCE, + g_ble_cfg_p->raw_scan_rsp_data_len, + g_ble_cfg_p->raw_scan_rsp_data_p); + if (ret) { + ESP_LOGE(TAG, "config_ext_scan_rsp_data_raw failed, error code = 0x%x", ret); + return; + } +#endif break; case ESP_GATTS_READ_EVT: if (g_ble_cfg_p && g_ble_cfg_p->read_fn) { @@ -207,7 +355,11 @@ static void gatts_profile_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_ } memset(s_cached_remote_bda, 0, sizeof(esp_bd_addr_t)); if (g_ble_cfg_p) { +#if SIMPLE_BLE_LEGACY_ADV esp_ble_gap_start_advertising(&g_ble_cfg_p->adv_params); +#elif SIMPLE_BLE_EXT_ADV + simple_ble_ext_adv_start(); +#endif } break; case ESP_GATTS_CREAT_ATTR_TAB_EVT: { diff --git a/components/protocomm/src/simple_ble/simple_ble.h b/components/protocomm/src/simple_ble/simple_ble.h index e38290b6d3b..5f0ce2595e4 100644 --- a/components/protocomm/src/simple_ble/simple_ble.h +++ b/components/protocomm/src/simple_ble/simple_ble.h @@ -11,9 +11,16 @@ #include #include +#include "sdkconfig.h" #include #include +#if CONFIG_BT_BLE_42_ADV_EN +#define SIMPLE_BLE_LEGACY_ADV 1 +#elif CONFIG_BT_BLE_50_EXTEND_ADV_EN +#define SIMPLE_BLE_EXT_ADV 1 +#endif + typedef void (simple_ble_cb_t)(esp_gatts_cb_event_t event, esp_gatt_if_t p_gatts_if, esp_ble_gatts_cb_param_t *param); /** @@ -24,12 +31,21 @@ typedef void (simple_ble_cb_t)(esp_gatts_cb_event_t event, esp_gatt_if_t p_gatts typedef struct { /** Name to be displayed to devices scanning for ESP32 */ const char *device_name; +#if SIMPLE_BLE_LEGACY_ADV /** Raw advertisement data */ esp_ble_adv_data_t *adv_data_p; /** Raw scan response data */ esp_ble_adv_data_t *scan_rsp_data_p; /** Parameters to configure the nature of advertising */ esp_ble_adv_params_t adv_params; +#elif SIMPLE_BLE_EXT_ADV + /** Raw advertisement data for BLE 5.0+ extended advertising */ + uint8_t *raw_adv_data_p; + uint32_t raw_adv_data_len; + /** Raw scan response data for BLE 5.0+ extended advertising */ + uint8_t *raw_scan_rsp_data_p; + uint32_t raw_scan_rsp_data_len; +#endif /** Descriptor table which consists of the configuration * required by services and characteristics */ esp_gatts_attr_db_t *gatt_db; diff --git a/components/protocomm/src/transports/protocomm_ble.c b/components/protocomm/src/transports/protocomm_ble.c index 179c38c679c..8886a9f2a5e 100644 --- a/components/protocomm/src/transports/protocomm_ble.c +++ b/components/protocomm/src/transports/protocomm_ble.c @@ -92,6 +92,7 @@ static void protocomm_ble_reset_prepare_write(void) } // config adv data +#if SIMPLE_BLE_LEGACY_ADV static esp_ble_adv_data_t adv_config = { .set_scan_rsp = false, .include_txpower = true, @@ -122,6 +123,71 @@ static esp_ble_adv_params_t adv_params = { .channel_map = ADV_CHNL_ALL, .adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY, }; +#elif SIMPLE_BLE_EXT_ADV +#define PROTOCOMM_BLE_RAW_AD_MAX ESP_BLE_ADV_DATA_LEN_MAX + +static uint8_t s_raw_adv_data[PROTOCOMM_BLE_RAW_AD_MAX]; +static uint8_t s_raw_scan_rsp_data[PROTOCOMM_BLE_RAW_AD_MAX]; +static uint32_t s_raw_adv_data_len; +static uint32_t s_raw_scan_rsp_data_len; + +static esp_err_t protocomm_ble_build_raw_adv_data(const uint8_t *service_uuid) +{ + uint32_t offset = 0; + + if (offset + 3 > PROTOCOMM_BLE_RAW_AD_MAX) { + return ESP_ERR_INVALID_SIZE; + } + s_raw_adv_data[offset++] = 2; + s_raw_adv_data[offset++] = ESP_BLE_AD_TYPE_FLAG; + s_raw_adv_data[offset++] = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT); + + if (offset + 2 + ESP_UUID_LEN_128 > PROTOCOMM_BLE_RAW_AD_MAX) { + return ESP_ERR_INVALID_SIZE; + } + s_raw_adv_data[offset++] = 1 + ESP_UUID_LEN_128; + s_raw_adv_data[offset++] = ESP_BLE_AD_TYPE_128SRV_CMPL; + memcpy(&s_raw_adv_data[offset], service_uuid, ESP_UUID_LEN_128); + offset += ESP_UUID_LEN_128; + + s_raw_adv_data_len = offset; + return ESP_OK; +} + +static esp_err_t protocomm_ble_build_raw_scan_rsp_data(const char *name, + const uint8_t *mfg_data, + size_t mfg_len) +{ + uint32_t offset = 0; + size_t name_len = (name != NULL) ? strlen(name) : 0; + + if (name_len > 0) { + if (name_len > ESP_BLE_ADV_NAME_LEN_MAX) { + name_len = ESP_BLE_ADV_NAME_LEN_MAX; + } + if (offset + 2 + name_len > PROTOCOMM_BLE_RAW_AD_MAX) { + return ESP_ERR_INVALID_SIZE; + } + s_raw_scan_rsp_data[offset++] = 1 + (uint8_t)name_len; + s_raw_scan_rsp_data[offset++] = ESP_BLE_AD_TYPE_NAME_CMPL; + memcpy(&s_raw_scan_rsp_data[offset], name, name_len); + offset += name_len; + } + + if (mfg_data != NULL && mfg_len > 0) { + if (offset + 2 + mfg_len > PROTOCOMM_BLE_RAW_AD_MAX) { + return ESP_ERR_INVALID_SIZE; + } + s_raw_scan_rsp_data[offset++] = 1 + (uint8_t)mfg_len; + s_raw_scan_rsp_data[offset++] = ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE; + memcpy(&s_raw_scan_rsp_data[offset], mfg_data, mfg_len); + offset += mfg_len; + } + + s_raw_scan_rsp_data_len = offset; + return ESP_OK; +} +#endif static char *protocomm_ble_device_name = NULL; static uint8_t *protocomm_ble_mfg_data = NULL; @@ -723,8 +789,10 @@ static void protocomm_ble_cleanup(void) free(protoble_internal->service_uuid); protoble_internal->service_uuid = NULL; } +#if SIMPLE_BLE_LEGACY_ADV adv_config.p_service_uuid = NULL; adv_config.service_uuid_len = 0; +#endif if (protoble_internal->g_nu_lookup) { for (size_t i = 0; i < protoble_internal->g_nu_lookup_count; i++) { if (protoble_internal->g_nu_lookup[i].name) { @@ -857,6 +925,7 @@ esp_err_t protocomm_ble_start(protocomm_t *pc, const protocomm_ble_config_t *con protoble_internal->ble_notify = config->ble_notify; // Config adv data +#if SIMPLE_BLE_LEGACY_ADV adv_config.service_uuid_len = ESP_UUID_LEN_128; protoble_internal->service_uuid = (uint8_t *)malloc(ESP_UUID_LEN_128); if (protoble_internal->service_uuid == NULL) { @@ -870,6 +939,30 @@ esp_err_t protocomm_ble_start(protocomm_t *pc, const protocomm_ble_config_t *con // Config scan response data scan_rsp_config.manufacturer_len = protocomm_ble_mfg_data_len; scan_rsp_config.p_manufacturer_data = (uint8_t *) protocomm_ble_mfg_data; +#elif SIMPLE_BLE_EXT_ADV + protoble_internal->service_uuid = (uint8_t *)malloc(ESP_UUID_LEN_128); + if (protoble_internal->service_uuid == NULL) { + ESP_LOGE(TAG, "Error allocating memory for service UUID"); + protocomm_ble_cleanup(); + return ESP_ERR_NO_MEM; + } + memcpy(protoble_internal->service_uuid, config->service_uuid, ESP_UUID_LEN_128); + + esp_err_t raw_ret = protocomm_ble_build_raw_adv_data(protoble_internal->service_uuid); + if (raw_ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to build raw advertising data"); + protocomm_ble_cleanup(); + return raw_ret; + } + raw_ret = protocomm_ble_build_raw_scan_rsp_data(protocomm_ble_device_name, + protocomm_ble_mfg_data, + protocomm_ble_mfg_data_len); + if (raw_ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to build raw scan response data"); + protocomm_ble_cleanup(); + return raw_ret; + } +#endif simple_ble_cfg_t *ble_config = simple_ble_init(); if (ble_config == NULL) { @@ -887,10 +980,17 @@ esp_err_t protocomm_ble_start(protocomm_t *pc, const protocomm_ble_config_t *con ble_config->set_mtu_fn = transport_simple_ble_set_mtu; /* Set parameters required for advertising */ +#if SIMPLE_BLE_LEGACY_ADV ble_config->adv_params = adv_params; ble_config->adv_data_p = &adv_config; ble_config->scan_rsp_data_p = &scan_rsp_config; +#elif SIMPLE_BLE_EXT_ADV + ble_config->raw_adv_data_p = s_raw_adv_data; + ble_config->raw_adv_data_len = s_raw_adv_data_len; + ble_config->raw_scan_rsp_data_p = s_raw_scan_rsp_data; + ble_config->raw_scan_rsp_data_len = s_raw_scan_rsp_data_len; +#endif ble_config->device_name = protocomm_ble_device_name; ble_config->gatt_db_count = populate_gatt_db(&ble_config->gatt_db);