ESP-IDF v3.0蓝牙gatt服务器示例或帮助使用多种服务?

时间:2018-02-24 18:43:54

标签: bluetooth gatt esp32

我目前正在开发一个固件项目,我需要设备来广播多种蓝牙服务,例如设备信息服务,电池服务等......我已经通过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;
    }
}

我有一种感觉我正在做一些非常明显错误的事情......但是对此过程中的任何反馈,例子或建议都会非常感激!

1 个答案:

答案 0 :(得分:1)

对也一直在寻找答案的任何人表示抱歉。我设置了一个GitHub存储库,在其中将ESP-IDF GATTS服务表示例模块化。该项目将ESP-IDF蓝牙分为接口,GAP,GATT服务器和服务。关于它的好处是,这些服务被分解为单独的文件,因此可以根据提供的模板轻松快捷地添加新服务。这项工作仍在艰巨的过程中,但希望它将对任何对esp-idf蓝牙示例感到困惑的人有所帮助。

https://github.com/eagi223/esp-idf_Bluetooth_Multi-Service