Closed nouwon closed 6 months ago
@nouwon Can you provide a method and more information to help reproduce this issue? Does your usage scenario use WIFI and high throughput to transfer data?
BLE link layer disconnection does not report ESP_GATTS_DISCONNECT_EVT event is rarely encountered.
I use the Android BLE app to connect to the esp32 running the example of gatt_server_service_table. When the connection is disconnected, the disconnection event will be reported every time in gatts_profile_event_handler
Thank you very much for your response xulogzhuang. Following are relevant initialization and registration functions. I can provide further code if nothing wrong is present here.
Project brief: 1-First I walk through an initialization sequence in my main.c file with app_state_handler() function call.
static void app_state_handler(){
/* Check the application's current state. */
switch (appData.state)
{
/* Application's initial state. */
case APP_STATE_INIT:
{
app_init();
ESP_LOGI(SYS_TAG, "%s System is initialized: %s\n", __func__, esp_err_to_name(ESP_OK));
break;
}
case APP_STATE_TASKS_INIT:
{
tasks_init();
break;
}
case APP_STATE_ERROR:
{
ESP_LOGE(SYS_TAG, "%s System encountered error!: %s\n", __func__, esp_err_to_name(ESP_FAIL));
break;
}
/* The default state should never be executed. */
default:
{
appData.state = APP_STATE_INIT;
break;
}
}
}
2-app_init function call initializes ble
static void app_init(){
if(ble_init()){
ESP_LOGI(SYS_TAG, "%s ble initialized !: %s\n", __func__, esp_err_to_name(ESP_OK));
appData.state=APP_STATE_TASKS_INIT;
send_system_event(APP_STATE_CHANGED);
}
else
ESP_LOGE(SYS_TAG, "%s BLE init failed: %s\n", __func__, esp_err_to_name(ESP_FAIL));
}
}
here is my ble initializaton method copied as it is given in the examples.
bool ble_init(void)
{
esp_err_t ret;
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
// Initialize NVS
ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND)
{
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));
ret = esp_bt_controller_init(&bt_cfg);
if (ret)
{
ESP_LOGE(GATTS_TABLE_TAG, "%s esp bt controller init failed: %s\n", __func__, esp_err_to_name(ret));
return false;
}
ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
if (ret)
{
ESP_LOGE(GATTS_TABLE_TAG, "%s esp bt controller enable failed: %s\n", __func__, esp_err_to_name(ret));
return false;
}
ret = esp_bluedroid_init();
if (ret)
{
ESP_LOGE(GATTS_TABLE_TAG, "%s init bluetooth failed: %s\n", __func__, esp_err_to_name(ret));
return false;
}
ret = esp_bluedroid_enable();
if (ret)
{
ESP_LOGE(GATTS_TABLE_TAG, "%s enable bluetooth failed: %s\n", __func__, esp_err_to_name(ret));
return false;
}
esp_ble_gatts_register_callback(gatts_event_handler);
esp_ble_gap_register_callback(gap_event_handler);
esp_ble_gatts_app_register(ESP_SPP_APP_ID);
return true;
}
3- If ble initialization succeeds I proceed to initiliaze freeRTOS tasks with tasks_init() function call.
static void tasks_init(){
spi_controller_init();
obdmgr_tasks_init();
msgmgr_task_init();
spp_task_init();
cmdmgr_task_init();
}
above tasks are standard freeRtos tasks each of which perform well without any problem.
4- spp_task is straight forward ble_spp_server_demo.c code void spp_task_init(void) { spp_uart_init();
// moved to cmdmgr
/* cmd_cmd_queue = xQueueCreate(10, sizeof(uint32_t));
xTaskCreate(spp_cmd_task, "spp_cmd_task", 2048, NULL, 10, NULL);*/
}
5- callback functions as given by examples is used with minor changes .(changes are made to force fire ESP_GATTS_DISCONNECT_EVT and are not required as per project specifications.changes made no effect.)
static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
{
esp_err_t err;
switch (event)
{
case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT:
esp_ble_gap_start_advertising(&spp_adv_params);
break;
case ESP_GAP_BLE_ADV_START_COMPLETE_EVT:
// advertising start complete event to indicate advertising start successfully or failed
if ((err = param->adv_start_cmpl.status) != ESP_BT_STATUS_SUCCESS)
{
ESP_LOGE(GATTS_TABLE_TAG, "Advertising start failed: %s\n", esp_err_to_name(err));
}
break;
default:
break;
}
}
//-----------------------------------------------------------------------------------------------------------------------------
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_ble_gatts_cb_param_t *p_data = (esp_ble_gatts_cb_param_t *)param;
uint8_t res = 0xff;
ESP_LOGI(GATTS_TABLE_TAG, "event = %x\n", event);
switch (event)
{
case ESP_GATTS_REG_EVT:
ESP_LOGI(GATTS_TABLE_TAG, "%s %d\n", __func__, __LINE__);
esp_ble_gap_set_device_name(SAMPLE_DEVICE_NAME);
ESP_LOGI(GATTS_TABLE_TAG, "%s %d\n", __func__, __LINE__);
esp_ble_gap_config_adv_data_raw((uint8_t *)spp_adv_data, sizeof(spp_adv_data));
ESP_LOGI(GATTS_TABLE_TAG, "%s %d\n", __func__, __LINE__);
esp_ble_gatts_create_attr_tab(spp_gatt_db, gatts_if, SPP_IDX_NB, SPP_SVC_INST_ID);
break;
case ESP_GATTS_READ_EVT:
res = find_char_and_desr_index(p_data->read.handle);
if (res == SPP_IDX_SPP_STATUS_VAL)
{
// TODO:client read the status characteristic
}
break;
case ESP_GATTS_WRITE_EVT:
{
res = find_char_and_desr_index(p_data->write.handle);
if (p_data->write.is_prep == false)
{
ESP_LOGI(GATTS_TABLE_TAG, "ESP_GATTS_WRITE_EVT : handle = %d\n", res);
if (res == SPP_IDX_SPP_COMMAND_VAL)
{
uint8_t *spp_cmd_buff = NULL;
spp_cmd_buff = (uint8_t *)malloc((spp_mtu_size - 3) * sizeof(uint8_t));
if (spp_cmd_buff == NULL)
{
ESP_LOGE(GATTS_TABLE_TAG, "%s malloc failed\n", __func__);
break;
}
memset(spp_cmd_buff, 0x0, (spp_mtu_size - 3));
memcpy(spp_cmd_buff, p_data->write.value, p_data->write.len);
xQueueSend(cmd_cmd_queue, &spp_cmd_buff, 10 / portTICK_PERIOD_MS);
}
else if (res == SPP_IDX_SPP_DATA_NTF_CFG)
{
if ((p_data->write.len == 2) && (p_data->write.value[0] == 0x01) && (p_data->write.value[1] == 0x00))
{
enable_data_ntf = true;
}
else if ((p_data->write.len == 2) && (p_data->write.value[0] == 0x00) && (p_data->write.value[1] == 0x00))
{
enable_data_ntf = false;
}
}
else if (res == SPP_IDX_SPP_DATA_RECV_VAL)
{
#ifdef SPP_DEBUG_MODE
esp_log_buffer_char(GATTS_TABLE_TAG, (char *)(p_data->write.value), p_data->write.len);
#else
uart_write_bytes(UART_NUM_0, (char *)(p_data->write.value), p_data->write.len);
send_message_received_event((uint8_t *)(p_data->write.value), p_data->write.len);
#endif
}
else
{
// TODO:
ESP_LOGI(GATTS_TABLE_TAG, "unhandled case");
}
}
else if ((p_data->write.is_prep == true) && (res == SPP_IDX_SPP_DATA_RECV_VAL))
{
ESP_LOGI(GATTS_TABLE_TAG, "ESP_GATTS_PREP_WRITE_EVT : handle = %d\n", res);
store_wr_buffer(p_data);
}
break;
}
case ESP_GATTS_EXEC_WRITE_EVT:
{
ESP_LOGI(GATTS_TABLE_TAG, "ESP_GATTS_EXEC_WRITE_EVT\n");
if (p_data->exec_write.exec_write_flag)
{
print_write_buffer();
free_write_buffer();
}
break;
}
case ESP_GATTS_MTU_EVT:
spp_mtu_size = p_data->mtu.mtu;
break;
case ESP_GATTS_CONF_EVT:
break;
case ESP_GATTS_UNREG_EVT:
break;
case ESP_GATTS_DELETE_EVT:
break;
case ESP_GATTS_START_EVT:
break;
case ESP_GATTS_STOP_EVT:
break;
case ESP_GATTS_CONNECT_EVT:
spp_conn_id = p_data->connect.conn_id;
spp_gatts_if = gatts_if;
is_connected = true;
memcpy(&spp_remote_bda, &p_data->connect.remote_bda, sizeof(esp_bd_addr_t));
esp_ble_conn_update_params_t conn_params = {0};
memcpy(&conn_params.bda, &spp_remote_bda, sizeof(esp_bd_addr_t));
/* For the IOS system, please reference the apple official documents about the ble connection parameters restrictions. */
conn_params.latency = 0;
conn_params.max_int = 0x20; // max_int = 0x20*1.25ms = 40ms
conn_params.min_int = 0x10; // min_int = 0x10*1.25ms = 20ms
conn_params.timeout = 400; // timeout = 400*10ms = 4000ms
ESP_LOGI(GATTS_TABLE_TAG, "ESP_GATTS_CONNECT_EVT, conn_id %d, remote %02x:%02x:%02x:%02x:%02x:%02x:",
param->connect.conn_id,
param->connect.remote_bda[0], param->connect.remote_bda[1], param->connect.remote_bda[2],
param->connect.remote_bda[3], param->connect.remote_bda[4], param->connect.remote_bda[5]);
spp_profile_tab[SPP_PROFILE_APP_IDX].conn_id = param->connect.conn_id;
//start sending the update connection parameters to the peer device.
esp_ble_gap_update_conn_params(&conn_params);
break;
case ESP_GATTS_DISCONNECT_EVT:
ESP_LOGI(GATTS_TABLE_TAG, "ESP_GATTS_DISCONNECT_EVT, disconnect reason 0x%x", param->disconnect.reason);
is_connected = false;
enable_data_ntf = false;
esp_ble_gap_start_advertising(&spp_adv_params);
break;
case ESP_GATTS_OPEN_EVT:
break;
case ESP_GATTS_CANCEL_OPEN_EVT:
break;
case ESP_GATTS_CLOSE_EVT:
ESP_LOGI(GATTS_TABLE_TAG, "ESP_GATTS_CLOSE_EVT, disconnect reason 0x%x", param->disconnect.reason);
break;
case ESP_GATTS_LISTEN_EVT:
break;
case ESP_GATTS_CONGEST_EVT:
break;
case ESP_GATTS_CREAT_ATTR_TAB_EVT:
{
ESP_LOGI(GATTS_TABLE_TAG, "The number handle =%x\n", param->add_attr_tab.num_handle);
if (param->add_attr_tab.status != ESP_GATT_OK)
{
ESP_LOGE(GATTS_TABLE_TAG, "Create attribute table failed, error code=0x%x", param->add_attr_tab.status);
}
else if (param->add_attr_tab.num_handle != SPP_IDX_NB)
{
ESP_LOGE(GATTS_TABLE_TAG, "Create attribute table abnormally, num_handle (%d) doesn't equal to HRS_IDX_NB(%d)", param->add_attr_tab.num_handle, SPP_IDX_NB);
}
else
{
memcpy(spp_handle_table, param->add_attr_tab.handles, sizeof(spp_handle_table));
esp_ble_gatts_start_service(spp_handle_table[SPP_IDX_SVC]);
}
break;
}
default:
break;
}
}
//----------------------------------------------------------------------------------------------------------------------------------------------
static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
{
// ESP_LOGI(GATTS_TABLE_TAG, "event = %x\n", event);
/* 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)
{
spp_profile_tab[SPP_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;
}
}
do
{
int idx;
for (idx = 0; idx < SPP_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 == spp_profile_tab[idx].gatts_if)
{
if (spp_profile_tab[idx].gatts_cb)
{
spp_profile_tab[idx].gatts_cb(event, gatts_if, param);
}
}
}
} while (0);
}
The above code does not look much different from ble_spp_server. Since the above code is not complete, I used ble_spp_server to do the following tests:
SUPPORT_HEARTBEAT
macrocase ESP_GATTS_DISCONNECT_EVT:
add and print as follows
ESP_LOGI(GATTS_TABLE_TAG, "ESP_GATTS_DISCONNECT_EVT, disconnect reason 0x%x", param->disconnect.reason);
As can be seen in the figure above, there is a disconnection event
If your code behavior is inconsistent with the above process, please tell me more detailed information, such as the Android client used, the reproduced demo and process, etc.
I am migrating to esp-idf ver 5.0 current version is 4.4.3. As soon as I make it run with the new esp-idf version I will comment about the result. Thank you very much for your kind efforts to resolve the issue. May I learn your esp-idf version?
@xulongzhuang Now I use idf version 5.0. here is a log output: I (239365) GATTS_ARADS: ESP_GATTS_CONNECT_EVT, conn_id 0, remote 76:d4:e4:3b:71:b5: I (239955) GATTS_ARADS: update connection params device 76:d4:e4:3b:71:b5 ,status = 0, min_int = 16, max_int = 16,conn_int = 16,latency = 0, timeout = 400 I (240185) GATTS_ARADS: update connection params device 76:d4:e4:3b:71:b5 ,status = 0, min_int = 0, max_int = 0,conn_int = 6,latency = 0, timeout = 500 I (240425) GATTS_ARADS: event = 4
I (240505) GATTS_ARADS: update connection params device 76:d4:e4:3b:71:b5 ,status = 0, min_int = 0, max_int = 0,conn_int = 16,latency = 0, timeout = 400 I (240785) GATTS_ARADS: update connection params device 76:d4:e4:3b:71:b5 ,status = 0, min_int = 0, max_int = 0,conn_int = 9,latency = 0, timeout = 2000 I (240995) GATTS_ARADS: event = 2
weid thing is multiple update params occur for the same device adress.Is this related to my issue? On the client side I use both my custom app and nRF connect with the same result.
@xulongzhuang Problem seems to be a hardware problem.I could not figure out why but I changed the board and now the callback event is fired properly. Thank you for the help.
Thanks for reporting, feel free to reopen.
Answers checklist.
General issue report
How do I capture ESP_GATTS_DISCONNECT_EVT after client connection is closed?I am using esp-idf ver 4.4.3. Currently an android client performs connection,sends data,receives data successfully but when the android client disconnects gatt server call back event ESP_GATTS_DISCONNECT_EVT is never triggered. Similar problems have been reported by other users but there is no satisfying solution proposal for this issue? Any help will be highly apprecited. Thanks