我目前正在开发一个固件项目,我需要设备来广播多种蓝牙服务,例如设备信息服务,电池服务等......我已经通过esp-idf GitHub和readthedocs网站进行了梳理GATT服务器的示例似乎只有一个服务。截至目前,我已经完成了广告宣传和1项服务功能,但我绝对不知道如何让第二个工作正常。如果有人有任何示例或建议,将不胜感激!
我的大部分内容来自ESP-IDF GATT服务器服务表示例: https://github.com/espressif/esp-idf/tree/master/examples/bluetooth/gatt_server_service_table
我正在初始化这样的蓝牙库(在我的代码中,为了便于阅读,我删除了大量的LOG和错误处理......功能相同):
esp_err_t Bluetooth_Interface_Init(void)
{
esp_err_t err;
Bluetooth_Driver_Init(); //Takes care of bt hardware inits
err = esp_ble_gatts_register_callback(gatts_event_handler);
err = esp_ble_gap_register_callback(gap_event_handler);
err = esp_ble_gatts_app_register(ESP_APP_ID);
err = esp_ble_gatt_set_local_mtu(500);
return err;
}
我的广告数据:
static uint8_t service_uuid[16] =
{
/* LSB <--------------------------------------------------------------------------------> MSB */
//first uuid, 16bit, [12],[13] is the value
0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x18, 0x0D, 0x00, 0x00,
};
/* The length of adv data must be less than 31 bytes */
static esp_ble_adv_data_t adv_data = {
.set_scan_rsp = false,
.include_name = true,
.include_txpower = true,
.min_interval = 0x20,
.max_interval = 0x40,
.appearance = 0x00,
.manufacturer_len = 0, //TEST_MANUFACTURER_DATA_LEN,
.p_manufacturer_data = NULL, //test_manufacturer,
.service_data_len = 0,
.p_service_data = NULL,
.service_uuid_len = sizeof(service_uuid),
.p_service_uuid = service_uuid,
.flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT),
};
// scan response data
static esp_ble_adv_data_t scan_rsp_data = {
.set_scan_rsp = true,
.include_name = true,
.include_txpower = true,
.min_interval = 0x20,
.max_interval = 0x40,
.appearance = 0x00,
.manufacturer_len = 0, //TEST_MANUFACTURER_DATA_LEN,
.p_manufacturer_data = NULL, //&test_manufacturer[0],
.service_data_len = 0,
.p_service_data = NULL,
.service_uuid_len = sizeof(service_uuid),
.p_service_uuid = service_uuid,
.flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT),
};
static esp_ble_adv_params_t adv_params = {
.adv_int_min = 0x20,
.adv_int_max = 0x40,
.adv_type = ADV_TYPE_IND,
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
.channel_map = ADV_CHNL_ALL,
.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
};
我的GAP事件处理程序:
static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
{
switch (event) {
case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT:
adv_config_done &= (~ADV_CONFIG_FLAG);
if (adv_config_done == 0){
esp_ble_gap_start_advertising(&adv_params);
}
break;
case ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT:
adv_config_done &= (~SCAN_RSP_CONFIG_FLAG);
if (adv_config_done == 0){
esp_ble_gap_start_advertising(&adv_params);
}
break;
case ESP_GAP_BLE_ADV_START_COMPLETE_EVT:
/* advertising start complete event to indicate advertising start successfully or failed */
if (param->adv_start_cmpl.status != ESP_BT_STATUS_SUCCESS) {
ESP_LOGE(TAG_IBLUETOOTH, "advertising start failed");
}else{
ESP_LOGI(TAG_IBLUETOOTH, "advertising start successfully");
}
break;
case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT:
if (param->adv_stop_cmpl.status != ESP_BT_STATUS_SUCCESS) {
ESP_LOGE(TAG_IBLUETOOTH, "Advertising stop failed");
}
else {
ESP_LOGI(TAG_IBLUETOOTH, "Stop adv successfully\n");
}
break;
case ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT:
ESP_LOGI(TAG_IBLUETOOTH, "update connetion params status = %d, min_int = %d, max_int = %d,conn_int = %d,latency = %d, timeout = %d",
param->update_conn_params.status,
param->update_conn_params.min_int,
param->update_conn_params.max_int,
param->update_conn_params.conn_int,
param->update_conn_params.latency,
param->update_conn_params.timeout);
break;
default:
break;
}
}
我的GATTS事件处理程序:
static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
{
#ifdef IBLUETOOTH_DEBUG
ESP_LOGI(TAG_IBLUETOOTH, "gatts event handler: %d", event);
#endif
/* 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) {
bt_profile_tab[INFO_IDX].gatts_if = gatts_if; //This is all that works... It registers the info profile
//bt_profile_tab[param->reg.app_id].gatts_if = gatts_if; //Nothing gets registered when doing this
//bt_profile_tab[WIFI_IDX].gatts_if = gatts_if; //Doing this always fails to register both.. Info Service is all that gets registered
} else {
ESP_LOGE(TAG_IBLUETOOTH, "reg app failed, app_id %04x, status %d", param->reg.app_id, param->reg.status);
return;
}
}
do {
int idx;
for (idx = 0; idx < PROFILE_NUM; idx++) {
/* ESP_GATT_IF_NONE, not specify a certain gatt_if, need to call every profile cb function */
if (gatts_if == ESP_GATT_IF_NONE || gatts_if == bt_profile_tab[idx].gatts_if) {
if (bt_profile_tab[idx].gatts_cb) {
bt_profile_tab[idx].gatts_cb(event, gatts_if, param);
}
}
}
} while (0);
}
其中一个服务事件处理程序的示例:
static const uint16_t INFO_SERV_uuid = ESP_GATT_UUID_DEVICE_INFO_SVC; //0x180A
static const uint16_t INFO_SERV_char_sysid_uuid = ...;
static const uint16_t INFO_SERV_char_model_uuid = ...;
static const uint16_t INFO_SERV_char_serial_uuid = ...;
static const uint16_t INFO_SERV_char_fw_uuid = ...;
static const uint16_t INFO_SERV_char_protocol_uuid = ...;
static const uint8_t INFO_SERV_char_sysid_descr[] = ...;
static const uint8_t INFO_SERV_char_model_descr[] = ...;
static const uint8_t INFO_SERV_char_serial_descr[] = ...;
static const uint8_t INFO_SERV_char_fw_descr[] = ...;
static const uint8_t INFO_SERV_char_protocol_descr[] = ...;
static const esp_gatts_attr_db_t info_serv_gatt_db[INFO_NB] =
{
[INFO_SERV] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *) &primary_service_uuid, ESP_GATT_PERM_READ, sizeof(uint16_t), sizeof(INFO_SERV_uuid), (uint8_t *)&INFO_SERV_uuid}},
...
};
static void info_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
{
switch (event) {
case ESP_GATTS_REG_EVT:{
esp_err_t set_dev_name_ret = esp_ble_gap_set_device_name(DEVICE_NAME);
//config adv data
esp_err_t ret = esp_ble_gap_config_adv_data(&adv_data);
adv_config_done |= ADV_CONFIG_FLAG;
//config scan response data
ret = esp_ble_gap_config_adv_data(&scan_rsp_data);
adv_config_done |= SCAN_RSP_CONFIG_FLAG;
esp_err_t create_attr_ret = esp_ble_gatts_create_attr_tab(info_serv_gatt_db, gatts_if, INFO_NB, SVC_INST_ID);
}
break;
case ESP_GATTS_READ_EVT:
...
案例ESP_GATTS_EXEC_WRITE_EVT:
...
案例ESP_GATTS_MTU_EVT:
ESP_LOGI(TAG_IBLUETOOTH,“ESP_GATTS_MTU_EVT,MTU%d”,param-&gt; mtu.mtu);
打破;
case ESP_GATTS_CONF_EVT:
ESP_LOGI(TAG_IBLUETOOTH, "ESP_GATTS_CONF_EVT, status = %d", param->conf.status);
break;
case ESP_GATTS_START_EVT:
ESP_LOGI(TAG_IBLUETOOTH, "SERVICE_START_EVT, status %d, service_handle %d", param->start.status, param->start.service_handle);
break;
case ESP_GATTS_CONNECT_EVT:
ESP_LOGI(TAG_IBLUETOOTH, "ESP_GATTS_CONNECT_EVT, conn_id = %d", param->connect.conn_id);
esp_log_buffer_hex(TAG_IBLUETOOTH, param->connect.remote_bda, 6);
esp_ble_conn_update_params_t conn_params = {0};
memcpy(conn_params.bda, param->connect.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
//start sent the update connection parameters to the peer device.
esp_ble_gap_update_conn_params(&conn_params);
break;
case ESP_GATTS_DISCONNECT_EVT:
ESP_LOGI(TAG_IBLUETOOTH, "ESP_GATTS_DISCONNECT_EVT, reason = %d", param->disconnect.reason);
esp_ble_gap_start_advertising(&adv_params);
break;
case ESP_GATTS_CREAT_ATTR_TAB_EVT:
if (param->add_attr_tab.status != ESP_GATT_OK){
ESP_LOGE(TAG_IBLUETOOTH, "create attribute table failed, error code=0x%x", param->add_attr_tab.status);
}
else if (param->add_attr_tab.num_handle != INFO_NB){
ESP_LOGE(TAG_IBLUETOOTH, "create attribute table abnormally, num_handle (%d) doesn't equal to HRS_IDX_NB(%d)", param->add_attr_tab.num_handle, INFO_NB);
}
else {
ESP_LOGI(TAG_IBLUETOOTH, "create attribute table successfully, the number handle = %d\n",param->add_attr_tab.num_handle);
memcpy(info_handle_table, param->add_attr_tab.handles, sizeof(info_handle_table));
esp_ble_gatts_start_service(info_handle_table[INFO_SERV]);
}
break;
case ESP_GATTS_STOP_EVT:
case ESP_GATTS_OPEN_EVT:
case ESP_GATTS_CANCEL_OPEN_EVT:
case ESP_GATTS_CLOSE_EVT:
case ESP_GATTS_LISTEN_EVT:
case ESP_GATTS_CONGEST_EVT:
case ESP_GATTS_UNREG_EVT:
case ESP_GATTS_DELETE_EVT:
default:
break;
}
}
我有一种感觉我正在做一些非常明显错误的事情......但是对此过程中的任何反馈,例子或建议都会非常感激!
答案 0 :(得分:1)
对也一直在寻找答案的任何人表示抱歉。我设置了一个GitHub存储库,在其中将ESP-IDF GATTS服务表示例模块化。该项目将ESP-IDF蓝牙分为接口,GAP,GATT服务器和服务。关于它的好处是,这些服务被分解为单独的文件,因此可以根据提供的模板轻松快捷地添加新服务。这项工作仍在艰巨的过程中,但希望它将对任何对esp-idf蓝牙示例感到困惑的人有所帮助。