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

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

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

Postby meneses.leonardo » Fri Jun 22, 2018 10:02 pm

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 parameters with minimum and maximum values I found in one example.

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 2069 times
As you can see, the advertising interval is wrong, not 20ms, which I clarify I'm not using, but rather is the default interval shown in ble_gap_api 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;

Now, looking for advertising normative in Apple iBeacon (https://developer.apple.com/ibeacon/) which is 100ms and Goggle Eddystone 200ms, or actually any value different from 32 shows the output of the advertising packet but not the scan response packet.



ibeacon.png
ibeacon.png (86.22 KiB) Viewed 2069 times
min 160, max 160 (100ms)



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

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

chegewara
Posts: 968
Joined: Wed Jun 14, 2017 9:00 pm

Re: BLE advertising and scan response packets not working simultaneously with adv parameters

Postby chegewara » Fri Jun 22, 2018 10:56 pm

I think you need to start advertising here:

Code: Select all

scrs_data 

Code: Select all

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;

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

Re: BLE advertising and scan response packets not working simultaneously with adv parameters

Postby meneses.leonardo » Fri Jun 22, 2018 11:35 pm

I don't think I understand your answer. There are two packets, the advertising data is an array at the beginning, and the scan response data consist only of local name. Both parameters are set in the task after registration of the callback, but is necessary to check if both are ready in order to start advertising.

This order is working when set min and max interval parameters to the minimum offered by the API, which is false if you really wanted to advertise at 20ms, but not with any other parameters

chegewara
Posts: 968
Joined: Wed Jun 14, 2017 9:00 pm

Re: BLE advertising and scan response packets not working simultaneously with adv parameters

Postby chegewara » Sat Jun 23, 2018 3:26 am

Sorry, i missread your code.

I dont know what might cause yours issue, maybe a bug. I have had many times issues with advertising intervals as you described (interval 1200+) but sometimes it disappeared after few restarts esp32, good findings.

Who is online

Users browsing this forum: Google [Bot] and 45 guests