BLE advertising and scan response packets not working simultaneously with advertising interval parameters

meneses.leonardo
Posts: 7
Joined: Wed Feb 21, 2018 8:45 pm

BLE advertising and scan response packets not working simultaneously with advertising interval parameters

Postby meneses.leonardo » Sun Jul 01, 2018 3:24 am

Hello everyone, I'm having an issue when setting a Beacon with both advertising packet and scan response.

Here is my code.

Code: Select all

// C programming
#include <stdio.h>
#include <string.h>

// freertos
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

// system
#include "esp_log.h"
#include "nvs_flash.h"
#include "sdkconfig.h"
#include "esp_err.h"

// STORAGE
#include "esp_partition.h"
#include "nvs_flash.h"
#include "nvs.h"

// BLE
#include "esp_bt.h"
#include "esp_bt_main.h"
#include "esp_gap_ble_api.h"
#include "esp_bt_defs.h"


////////////////////////////////
// ADVERTISING PARAMETERS
////////////////////////////////

// Size of advertising packages on BT 4. Hopefully if ESP32 supports BT 5, then blesize would change to 256.
#define blesize 31

// vector for advertising data
static uint8_t adv_raw_data[blesize]={0x03, 0x03, 0xAA, 0xFE, 0x13, 0x16, 0xAA, 0xFE, 0x10, 0x20, 0x03, 0x67, 0x6F, 0x6F, 0x2E, 0x67, 0x6C, 0x2F, 0x4A, 0x39, 0x61, 0x4D, 0x51, 0x53};

// boolean keys to know if data is ready to send.
static bool adv_data_ready;
static bool scrs_data_ready;

// parameters for scan response data. only local name will be used.
static esp_ble_adv_data_t scrs_data ={
		.set_scan_rsp = true,
		.include_name = true,
};

// data advertising parameters.
// TODO error with min. and max
static esp_ble_adv_params_t ble_adv_params = {
		.adv_int_min = 32,
		.adv_int_max = 32,
		.adv_type = ADV_TYPE_NONCONN_IND,
		.own_addr_type  = BLE_ADDR_TYPE_PUBLIC,
		.channel_map = ADV_CHNL_ALL,
		.adv_filter_policy  = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
};





// BT STACK SETUP
void bt_setup(){

	static const char *tag = "BLE_INIT";
	esp_err_t ret;

	// initialization parameters for BT CONTROLLER.
	esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();

	//  BT classic release memory.
	if ((ret= esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT)) != ESP_OK) {
		ESP_LOGE(tag, "Bluetooth controller memory for classic BT release failed due to error: %s", esp_err_to_name(ret));
		return;
	}
	else ESP_LOGV(tag,"Bluetooth controller memory for classic BT released successfully");

	// BT CONTROLLER initialization verification.
	if ((ret = esp_bt_controller_init(&bt_cfg)) != ESP_OK) {
		ESP_LOGE(tag, "Bluetooth controller initialization failed due to error: %s", esp_err_to_name(ret));
		return;
	}
	else ESP_LOGV(tag,"Bluetooth controller initialized successfully");

	// Initialization in MODE BLE Verification.
	if ((ret = esp_bt_controller_enable(ESP_BT_MODE_BLE)) != ESP_OK) {
		ESP_LOGE(tag, "Bluetooth controller enable in BLE mode failed due to error: %s", esp_err_to_name(ret));
		return;
	}
	else ESP_LOGV(tag,"Bluetooth controller successfully enabled in BLE mode");

	// Set TX power value based on stored value.
	ESP_LOGV(tag,"Setting BLE TX power");
	esp_power_level_t val=7;
	if ((ret = esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, val)) != ESP_OK){
		ESP_LOGE(tag, "Bluetooth tx power set failed: %s", esp_err_to_name(ret));
		return;
	}
	else ESP_LOGV(tag,"Value of TX power is %d", esp_ble_tx_power_get(ESP_BLE_PWR_TYPE_ADV));

	// Verify BLUEDROID library initialization.
	if ((ret = esp_bluedroid_init()) != ESP_OK){
		ESP_LOGE(tag, "Bluedroid library initialization failed: %s", esp_err_to_name(ret));
		return;
	}
	else ESP_LOGV(tag,"Bluedroid library successfully initialized");

	// Verify BLUEDROID library enable.
	if ((ret = 	esp_bluedroid_enable()) != ESP_OK){
		ESP_LOGE(tag, "Bluedroid library enable failed: %s", esp_err_to_name(ret));
		return;
	}
	else ESP_LOGV(tag,"Bluedroid library successfully enabled");

}

// NVS INIT
void nvs_flash_storage_init() {

	esp_err_t ret;
	static const char *tag="NVS_INIT";

	switch((ret = nvs_flash_init())){

	case ESP_OK:
		ESP_LOGV(tag, "NVS storage initialized successfully");
		break;

	case ESP_ERR_NVS_NO_FREE_PAGES:
		ESP_LOGE(tag,"Could not initialize NVS NO_FREE_PAGES\n");
		// find the NVS partition
		const esp_partition_t* nvs_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, NULL);
		if(!nvs_partition) {

			ESP_LOGE(tag,"FATAL ERROR: No NVS partition found\n");
			while(1) vTaskDelay(10 / portTICK_PERIOD_MS);
		}
		else ESP_LOGV(tag, "NVS Storage found, formatting");

		if((ret=esp_partition_erase_range(nvs_partition, 0, nvs_partition->size)) != ESP_OK){
			ESP_LOGE(tag,"Fatal Error in NVS Format, err: %s\n",esp_err_to_name(ret));
		}
		else ESP_LOGV(tag, "Storage successfully formatted, Initializing again");

		if((ret=nvs_flash_init()) != ESP_OK){
			ESP_LOGE(tag,"Fatal Error in NVS initialization, err: %s\n",esp_err_to_name(ret));
		}
		else ESP_LOGV(tag, "NVS storage successfully initialized");
		break;

	default:
		ESP_LOGE(tag,"Fatal Error in NVS initialization, err: %s\n",esp_err_to_name(ret));
		break;
	}
}


////////////////////////////////
// CALLBACK
////////////////////////////////
static void esp_gap_cb(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param){

	esp_err_t ret;
	static const char *tag = "CALLBACK_EVENT";


	switch (event) {

	case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT:

		adv_data_ready = true;
		if (scrs_data_ready){
			if((ret = esp_ble_gap_start_advertising(&ble_adv_params)) !=ESP_OK){
				ESP_LOGE(tag,"Could not set advertising data due to error: %s",esp_err_to_name(ret));
			}
			else ESP_LOGV(tag,"Advertising data set successfully");
		}
		break;

	case ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT:

		scrs_data_ready = true;
		if (adv_data_ready){
			if((ret = esp_ble_gap_start_advertising(&ble_adv_params)) != ESP_OK){
				ESP_LOGE(tag,"Could not set Scan Response data due to error: %s",esp_err_to_name(ret));
			}
			else ESP_LOGV(tag,"Scan Response data set successfully");
		}
		break;

	case ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT:

		scrs_data_ready = true;
		if (adv_data_ready){
			if((ret = esp_ble_gap_start_advertising(&ble_adv_params)) != ESP_OK){
				ESP_LOGE(tag,"Could not set Scan Response data due to error: %s",esp_err_to_name(ret));
			}
			else ESP_LOGV(tag,"Scan Response data set successfully");
		}
		break;

	case ESP_GAP_BLE_ADV_START_COMPLETE_EVT:

		if(param->adv_start_cmpl.status == ESP_BT_STATUS_SUCCESS) {
			ESP_LOGV(tag,"Advertising started Successfully");
		}
		else ESP_LOGE(tag,"Unable to start advertising process, error code %d", param->scan_start_cmpl.status);
		break;

	case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT:

		ESP_LOGV(tag,"Advertising Stopped");
		break;




	default:

		ESP_LOGV(tag,"Event %d unhandled\n\n", event);
		break;
	}
}


////////////////////////////////
// TASK
////////////////////////////////
void bleCombinedTask(void *pvParameters)
{

	static const char *tag = "BLE_ADV";
	esp_err_t ret;

	// register GAP callback function
	if ((ret= esp_ble_gap_register_callback(esp_gap_cb)) != ESP_OK) {
		ESP_LOGE(tag, "GAP callback  could not be registered: %s", esp_err_to_name(ret));
		return;
	}

	// configure adv data
	if ((ret= esp_ble_gap_config_adv_data_raw(adv_raw_data,sizeof(adv_raw_data))) != ESP_OK) {
		ESP_LOGE(tag, "Could not set adv data: %s", esp_err_to_name(ret));
		return;
	}

	// local name
	ESP_LOGV(tag,"setting local name");
	if((ret = esp_ble_gap_set_device_name("HELLO 123")) != ESP_OK){
		ESP_LOGE(tag,"Could not set device local name due to error: %s",esp_err_to_name(ret));
	}
	else ESP_LOGV(tag,"Local device name set successfully");


	// configure scan response data
	if ((ret= esp_ble_gap_config_adv_data(&scrs_data)) != ESP_OK) {
		ESP_LOGE(tag, "Could not set Scan Response data: %s", esp_err_to_name(ret));
		return;
	}


	while (1){

		vTaskDelay((1000)/portTICK_PERIOD_MS);
	}
}


////////////////////////////////////////////
// MAIN
////////////////////////////////////////////
void app_main()
{

	nvs_flash_storage_init();

	bt_setup();

	xTaskCreate(&bleCombinedTask, "ble combined",4096,NULL,5,NULL);

	while(1){

		vTaskDelay(1000/portTICK_PERIOD_MS);

	}

}

Here you can see the advertising interval parameters with minimum and maximum values I found in one example. 32 would be 20ms.

Code: Select all

// data advertising parameters.
// TODO error with min. and max
static esp_ble_adv_params_t ble_adv_params = {
		.adv_int_min = 32,
		.adv_int_max = 32,
		.adv_type = ADV_TYPE_NONCONN_IND,
		.own_addr_type  = BLE_ADDR_TYPE_PUBLIC,
		.channel_map = ADV_CHNL_ALL,
		.adv_filter_policy  = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
};
and here is the output in NRF Connect.
ok.png
ok.png (87.72 KiB) Viewed 5000 times

As you can see, the advertising interval is wrong (not 20ms, which I clarify I'm not using) because is the default interval provided by ble_gap_api.h which is 1,2 seconds.

Code: Select all

typedef struct {
    uint16_t                adv_int_min;        /*!< Minimum advertising interval for
                                                  undirected and low duty cycle directed advertising.
                                                  Range: 0x0020 to 0x4000 Default: N = 0x0800 (1.28 second)
                                                  Time = N * 0.625 msec Time Range: 20 ms to 10.24 sec */
    uint16_t                adv_int_max;        /*!< Maximum advertising interval for
                                                  undirected and low duty cycle directed advertising.
                                                  Range: 0x0020 to 0x4000 Default: N = 0x0800 (1.28 second)
                                                  Time = N * 0.625 msec Time Range: 20 ms to 10.24 sec Advertising max interval */
    esp_ble_adv_type_t      adv_type;           /*!< Advertising type */
    esp_ble_addr_type_t     own_addr_type;      /*!< Owner bluetooth device address type */
    esp_bd_addr_t           peer_addr;          /*!< Peer device bluetooth device address */
    esp_ble_addr_type_t     peer_addr_type;     /*!< Peer device bluetooth device address type */
    esp_ble_adv_channel_t   channel_map;        /*!< Advertising channel map */
    esp_ble_adv_filter_t    adv_filter_policy;  /*!< Advertising filter policy */
} esp_ble_adv_params_t;




Unfortunately, this setting is the only way for advertising packet an scan response packet to coexist. Setting the interval to any value different from 20ms breaks the scan response functionality.



Now, the 1.2 second interval is not appropriate for advertising because only powerfull devices would catch the information. Looking for advertising normative in Apple iBeacon (https://developer.apple.com/ibeacon/) shows an appropriate value of 100ms for stability, and Goggle Eddystone says 200ms for a little more power-efficiency.
ibeacon.png
ibeacon.png (86.22 KiB) Viewed 5000 times
min 160, max 160 (100ms)


eddystone.png
eddystone.png (90.25 KiB) Viewed 5000 times
min 320, max 320 (200ms)


I appreciate any help you can provide me. feel free to ask any question.

Who is online

Users browsing this forum: No registered users and 25 guests