Closed secureschwob closed 5 years ago
@secureschwob, Can you provide your test code?
Dear @Weijian-Espressif , thanks for your fast response.
All lines of code, which modified the original esp-idf/examples/bluetooth/gatt_security_server/
example can be found at https://gist.github.com/secureschwob/8e829e909a695b1338f269e07950c618 .
Are you missing something particular?
@secureschwob, Sorry I can not open the URL, probably because of China's firewall. Can you send an attachment?
@Weijian-Espressif Please find the source code from the Gist below:
/* File: example_ble_sec_gatts_demo.h */
// Battery Service
enum {
BS_IDX_SVC,
BS_IDX_MEAS_CHAR,
BS_IDX_MEAS_VAL,
BS_IDX_NB,
};
// Environmental Sensing Service (ESS) (partly implemented)
enum {
ESS_IDX_SVC, // ESS service index
ESS_IDX_ES_TEMP_MEAS_CHAR, // Characteristic index
ESS_IDX_ES_TEMP_MEAS_VAL, // Characteristic value index
ESS_IDX_ES_MEAS_NTF_CFG, ESS notifications configuration index
ESS_IDX_NB, // number of table elements
};
/* File: example_ble_sec_gatts_demo.c */
#include "example_ble_sec_gatts_demo.h"
#include "environmental_sensing_service.h" #includes UUIDs of the service not found in
#define PROFILE_NUM 2
#define BATTERY_PROFILE_APP_IDX 0
#define ESP_BATTERY_APP_ID 0x57 //arbitrarily chosen
#define BATTERY_SVC_INST_ID 0
static uint16_t battery_service_handle_table[BS_IDX_NB];
#define ESS_PROFILE_APP_IDX 1
#define ESP_ESS_APP_ID 0x75 //arbitrarily chosen
#define ESS_SVC_INST_ID 0
static uint16_t ess_handle_table[ESS_IDX_NB];
static struct gatts_profile_inst profile_tab[PROFILE_NUM] = {
[BATTERY_PROFILE_APP_IDX] = {
.gatts_cb = gatts_profile_event_handler, //TODO set another event handler?
.gatts_if = ESP_GATT_IF_NONE,
},
[ESS_PROFILE_APP_IDX] = {
.gatts_cb = gatts_profile_event_handler, //TODO set another event handler?
.gatts_if = ESP_GATT_IF_NONE,
},
};
/*Environmental Sensing PROFILE ATTRIBUTES */
// Environmental Sensing Service
static const uint16_t ess_svc = ESS_UUID_SERVICE; //0x181A
/// ESS Characteristic
static const uint16_t temperature_uuid = ESS_UUID_TEMP_CHAR; //0x2A6E
static const uint8_t temperature_value[1] = {0x0A};
static const esp_gatts_attr_db_t ess_gatt_db[ESS_IDX_NB] = {
// Environmental Sensing Service Declaration
[ESS_IDX_SVC] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&primary_service_uuid, ESP_GATT_PERM_READ,
sizeof(uint16_t), sizeof(ess_svc), (uint8_t *)&ess_svc}},
// Battery Service Characteristic Declaration - wenn ich das auskommentiere sehe ich nur einen Leeren Battery Service mit dem ich nichts machen kann
[ESS_IDX_ES_TEMP_MEAS_CHAR] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ,
CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_read}},
// Battery Service Characteristic Value - wenn ich das auskommentiere sehe ich den Battery Service nicht
[ESS_IDX_ES_TEMP_MEAS_VAL] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&temperature_uuid, ESP_GATT_PERM_READ_ENCRYPTED,
sizeof(uint8_t), sizeof(temperature_value), (uint8_t *)temperature_value}},
};
#endif
/* Battery Service PROFILE ATRIBUTES */
/// Battery Service
static const uint16_t battery_svc = ESP_GATT_UUID_BATTERY_SERVICE_SVC;
/// Battery Level Characteristic
static const uint16_t battery_level_uuid = ESP_GATT_UUID_BATTERY_LEVEL;
static const uint8_t battery_level_value[1] = {0x60};
/// Full Battery Level Service Database Description - Used to add attributes into the database
static const esp_gatts_attr_db_t battery_level_gatt_db[BS_IDX_NB] = {
// Battery Level Service Declaration - ohne den sehe ich in der Nordic App den Service nicht, HeartRate jedoch immer noch doppelt :D
[BS_IDX_SVC] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&primary_service_uuid, ESP_GATT_PERM_READ,
sizeof(uint16_t), sizeof(battery_svc), (uint8_t *)&battery_svc}},
// Battery Service Characteristic Declaration - wenn ich das auskommentiere sehe ich nur einen Leeren Battery Service mit dem ich nichts machen kann
[BS_IDX_MEAS_CHAR] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ,
CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_read}},
// Battery Service Characteristic Value - wenn ich das auskommentiere sehe ich den Battery Service nicht
[BS_IDX_MEAS_VAL] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&battery_level_uuid, ESP_GATT_PERM_READ_ENCRYPTED,
sizeof(uint8_t), sizeof(battery_level_value), (uint8_t *)battery_level_value}},
};
static void gatts_profile_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
{
ESP_LOGV(GATTS_TABLE_TAG, "event = %x\n",event);
switch (event) {
case ESP_GATTS_REG_EVT:
esp_ble_gap_set_device_name(EXCAMPLE_DEVICE_NAME);
//generate a resolvable random address
esp_ble_gap_config_local_privacy(true);
esp_ble_gatts_create_attr_tab(battery_level_gatt_db, gatts_if, BS_IDX_NB, BATTERY_SVC_INST_ID);
esp_ble_gatts_create_attr_tab(ess_gatt_db, gatts_if, ESS_IDX_NB, ESS_SVC_INST_ID);
break;
//(...)
case ESP_GATTS_CREAT_ATTR_TAB_EVT: {
ESP_LOGI(GATTS_TABLE_TAG, "The number handle = %x",param->add_attr_tab.num_handle);
if (param->create.status == ESP_GATT_OK){ //ESP_GATT_OK=0x0
if (param->add_attr_tab.num_handle == BS_IDX_NB) {
memcpy(battery_service_handle_table, param->add_attr_tab.handles,
sizeof(battery_service_handle_table));
esp_ble_gatts_start_service(battery_service_handle_table[BS_IDX_SVC]);
} else if (param->add_attr_tab.num_handle == ESS_IDX_NB) {
memcpy(ess_handle_table, param->add_attr_tab.handles,
sizeof(ess_handle_table));
esp_ble_gatts_start_service(ess_handle_table[ESS_IDX_SVC]);
} else {
ESP_LOGE(GATTS_TABLE_TAG, "Create attribute table abnormally, num_handle (%d) doesn't equal to BS_IDX_NB(%d) or ESS_IDX_NB(%d)",
param->add_attr_tab.num_handle, BS_IDX_NB, param->add_attr_tab.num_handle, ESS_IDX_NB);
}
}else{
ESP_LOGE(GATTS_TABLE_TAG, " Create attribute table failed, error code = %x", param->create.status);
}
break;
}
default:
break;
}
}
do {
int idx;
for (idx = 0; idx < PROFILE_NUM; idx++) {
if (gatts_if == ESP_GATT_IF_NONE || /* ESP_GATT_IF_NONE, not specify a certain gatt_if, need to call every profile cb function */
gatts_if == profile_tab[idx].gatts_if) {
if (profile_tab[idx].gatts_cb) {
profile_tab[idx].gatts_cb(event, gatts_if, param);
}
}
}
} while (0);
void app_main()
{
// ---
ret = esp_ble_gatts_app_register(ESP_BATTERY_APP_ID);
if (ret){
ESP_LOGE(GATTS_TABLE_TAG, "gatts app register error, error code = %x", ret);
return;
}
ret = esp_ble_gatts_app_register(ESP_ESS_APP_ID);
if (ret){
ESP_LOGE(GATTS_TABLE_TAG, "gatts app register error, error code = %x", ret);
return;
}
}
I added two additional screenshots, which further demonstrate the observed behavior, to the initial post.
Thank you for your efforts!
@secureschwob I can not visit the Gist because of China's firewall, please send .c and .h files as an attachment. or send your source code to the mail zhiweijian@espressif.com
@secureschwob
I have modified your test code, please replace your hws_secure_sensor_node.c
file and try and restart your phone Bluetooth to clean the cache.
Please check your mailbox
You solved my problem, thank you very much!
My key error obviously was this:
static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if,
esp_ble_gatts_cb_param_t *param)
{
//printf("%s app_id %d gatts_if %d", __func__, param->reg.app_id, gatts_if);
/* If event is register event, store the gatts_if for each profile */
if (event == ESP_GATTS_REG_EVT) {
if (param->reg.status == ESP_GATT_OK) {
//this!
profile_tab[param->reg.app_id].gatts_if = gatts_if;
// rather than this:
// profile_tab[ESS_PROFILE_APP_IDX].gatts_if = gatts_if;
// profile_tab[BATTERY_PROFILE_APP_IDX].gatts_if = gatts_if;
} else {
ESP_LOGI(GATTS_TABLE_TAG, "Reg app failed, app_id %04x, status %d\n",
param->reg.app_id,
param->reg.status);
return;
}
}
together with using different gatts_profile_event_handler
for each of my services.
Environment
Problem Description
I extended the
gatt_security_server
example provided byesp-idf
with additional services, namely the Battery Level Service and the Environmental Sensing Service. In order to do so, I followed the tutorials provided in the example folder and copied the lines of code used to create the Heart Rate Service in the original example. I played around with any combination of HRS, Battery Level and ESS and then connect to the ESP32 using the nrfConnect Android and Linux apps. As soon as I have created more than one GATT service at the ESP32, I see every service created twice (see screenshot. Let's number the services 1 to 4 beginning from the topmost Battery Service). I can read the characteristics of services 1 to 4 to get the dummy values written into the source code. However, only reading services 3 and 4 (i.e. the Battery Service and the Environmental Sensing Service displayed at the bottom of the screenshot) trigger an event in the debug logs on the monitor (e.g.V (1491156) HWS_SENSOR: event = 1
).An additional observation: Not only are the services shown twice, each characteristic within a service is also shown twice (please see the screenshot).
Removing everything related to the Environmental Sensing Service, thus the Battery Sensing Service being the only service present, also removes the duplicate characteristics:
Stepping through my Sourcecode with GDB shows, that the debug log messages
appear directly after having stepped over line 56 of the following GDB log:
Trying to step into
btc_transfer_context
causes my debugger to stop, thus I could not dig deeper.Am I mistaken about how to add services?
Expected Behavior
Every service created should be visible only once.
Actual Behavior
Every service created is shown twice.
Steps to reproduce
gatt_security_server
example provided byesp-idf
Code to reproduce this issue
Please see relevant snippets at https://gist.github.com/secureschwob/8e829e909a695b1338f269e07950c618.
Debug Logs