// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include #include "bta/bta_gatt_api.h" #include "btc/btc_task.h" #include "btc/btc_manage.h" #include "btc_gatts.h" #include "btc_gatt_util.h" #include "osi/future.h" #include "osi/allocator.h" #include "btc/btc_main.h" #include "esp_gatts_api.h" #if (GATTS_INCLUDED == TRUE) #define A2C_GATTS_EVT(_bta_event) (_bta_event) //BTA TO BTC EVT #define C2A_GATTS_EVT(_btc_event) (_btc_event) //BTC TO BTA EVT typedef struct { future_t *complete_future; uint16_t svc_start_hdl; esp_bt_uuid_t svc_uuid; bool is_tab_creat_svc; bool is_use_svc; uint8_t num_handle; uint8_t handle_idx; uint16_t handles[ESP_GATT_ATTR_HANDLE_MAX]; } esp_btc_creat_tab_t; static esp_btc_creat_tab_t btc_creat_tab_env; static esp_gatt_status_t btc_gatts_check_valid_attr_tab(esp_gatts_attr_db_t *gatts_attr_db, uint8_t max_nb_attr); static inline void btc_gatts_cb_to_app(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) { esp_gatts_cb_t btc_gatts_cb = (esp_gatts_cb_t)btc_profile_cb_get(BTC_PID_GATTS); if (btc_gatts_cb) { btc_gatts_cb(event, gatts_if, param); } } static inline void btc_gatts_uuid_format_convert(esp_bt_uuid_t* dest_uuid, uint16_t src_uuid_len, uint8_t* src_uuid_p) { dest_uuid->len = src_uuid_len; if(src_uuid_len == ESP_UUID_LEN_16){ dest_uuid->uuid.uuid16 = src_uuid_p[0] + (src_uuid_p[1]<<8); } else if(src_uuid_len == ESP_UUID_LEN_32){ dest_uuid->uuid.uuid32 = src_uuid_p[0] + (src_uuid_p[1]<<8) + (src_uuid_p[2]<<16) + (src_uuid_p[3]<<24); } else if(src_uuid_len == ESP_UUID_LEN_128){ memcpy(dest_uuid->uuid.uuid128, src_uuid_p, src_uuid_len); } else{ BTC_TRACE_ERROR("%s wrong uuid length %d\n", __func__, src_uuid_len); } } void btc_gatts_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src) { btc_ble_gatts_args_t *dst = (btc_ble_gatts_args_t *) p_dest; btc_ble_gatts_args_t *src = (btc_ble_gatts_args_t *)p_src; switch (msg->act) { case BTC_GATTS_ACT_SEND_INDICATE: { if (src->send_ind.value && (src->send_ind.value_len > 0)) { dst->send_ind.value = (uint8_t *) osi_malloc(src->send_ind.value_len); if (dst->send_ind.value) { memcpy(dst->send_ind.value, src->send_ind.value, src->send_ind.value_len); } else { BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act); } } else { dst->send_ind.value = NULL; if (src->send_ind.value) { BTC_TRACE_ERROR("%s %d, invalid length", __func__, msg->act); } } break; } case BTC_GATTS_ACT_SEND_RESPONSE: { if (src->send_rsp.rsp) { dst->send_rsp.rsp = (esp_gatt_rsp_t *) osi_malloc(sizeof(esp_gatt_rsp_t)); if (dst->send_rsp.rsp) { memcpy(dst->send_rsp.rsp, src->send_rsp.rsp, sizeof(esp_gatt_rsp_t)); } else { BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act); } } break; } case BTC_GATTS_ACT_ADD_CHAR: { if (src->add_char.char_val.attr_value && (src->add_char.char_val.attr_len > 0)) { dst->add_char.char_val.attr_value = (uint8_t *) osi_malloc(src->add_char.char_val.attr_len); if (dst->add_char.char_val.attr_value) { memcpy(dst->add_char.char_val.attr_value, src->add_char.char_val.attr_value, src->add_char.char_val.attr_len); } else { BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act); } } else { dst->add_char.char_val.attr_value = NULL; if (src->add_char.char_val.attr_value) { BTC_TRACE_ERROR("%s %d, invalid length", __func__, msg->act); } } break; } case BTC_GATTS_ACT_ADD_CHAR_DESCR: { if (src->add_descr.descr_val.attr_value && (src->add_descr.descr_val.attr_len > 0)) { dst->add_descr.descr_val.attr_value = (uint8_t *) osi_malloc(src->add_descr.descr_val.attr_len); if (dst->add_descr.descr_val.attr_value) { memcpy(dst->add_descr.descr_val.attr_value, src->add_descr.descr_val.attr_value, src->add_descr.descr_val.attr_len); } else { BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act); } } else { dst->add_descr.descr_val.attr_value = NULL; if (src->add_descr.descr_val.attr_value) { BTC_TRACE_ERROR("%s %d, invalid length", __func__, msg->act); } } break; } case BTC_GATTS_ACT_CREATE_ATTR_TAB: { uint8_t num_attr = src->create_attr_tab.max_nb_attr; if (src->create_attr_tab.gatts_attr_db && (num_attr > 0)) { dst->create_attr_tab.gatts_attr_db = (esp_gatts_attr_db_t *) osi_malloc(sizeof(esp_gatts_attr_db_t) * num_attr); if (dst->create_attr_tab.gatts_attr_db) { memcpy(dst->create_attr_tab.gatts_attr_db, src->create_attr_tab.gatts_attr_db, sizeof(esp_gatts_attr_db_t) * num_attr); } else { BTC_TRACE_ERROR("%s %d no mem\n",__func__, msg->act); } } else { BTC_TRACE_ERROR("%s %d, NULL data", __func__, msg->act); } break; } case BTC_GATTS_ACT_SET_ATTR_VALUE: { if (src->set_attr_val.value && (src->set_attr_val.length > 0)) { dst->set_attr_val.value = (uint8_t *) osi_malloc(src->set_attr_val.length); if (dst->set_attr_val.value) { memcpy(dst->set_attr_val.value, src->set_attr_val.value, src->set_attr_val.length); } else { BTC_TRACE_ERROR("%s %d no mem\n",__func__, msg->act); } } else { dst->set_attr_val.value = NULL; if (src->set_attr_val.value) { BTC_TRACE_ERROR("%s %d, invalid length", __func__, msg->act); } else { BTC_TRACE_WARNING("%s %d, NULL value", __func__, msg->act); } } break; } default: BTC_TRACE_DEBUG("%s Unhandled deep copy %d\n", __func__, msg->act); break; } } void btc_gatts_arg_deep_free(btc_msg_t *msg) { btc_ble_gatts_args_t *arg = (btc_ble_gatts_args_t *)msg->arg; switch (msg->act) { case BTC_GATTS_ACT_SEND_INDICATE: { if (arg->send_ind.value) { osi_free(arg->send_ind.value); } break; } case BTC_GATTS_ACT_SEND_RESPONSE: { if (arg->send_rsp.rsp) { osi_free(arg->send_rsp.rsp); } break; } case BTC_GATTS_ACT_ADD_CHAR:{ if (arg->add_char.char_val.attr_value != NULL) { osi_free(arg->add_char.char_val.attr_value); } break; } case BTC_GATTS_ACT_ADD_CHAR_DESCR:{ if (arg->add_descr.descr_val.attr_value != NULL){ osi_free(arg->add_descr.descr_val.attr_value); } break; } case BTC_GATTS_ACT_CREATE_ATTR_TAB:{ if (arg->create_attr_tab.gatts_attr_db != NULL){ osi_free(arg->create_attr_tab.gatts_attr_db); } break; } case BTC_GATTS_ACT_SET_ATTR_VALUE:{ if (arg->set_attr_val.value != NULL){ osi_free(arg->set_attr_val.value); } } break; default: BTC_TRACE_DEBUG("%s Unhandled deep free %d\n", __func__, msg->act); break; } } static void btc_gatts_act_create_attr_tab(esp_gatts_attr_db_t *gatts_attr_db, esp_gatt_if_t gatts_if, uint8_t max_nb_attr, uint8_t srvc_inst_id) { uint16_t uuid = 0; future_t *future_p; esp_ble_gatts_cb_param_t param; param.add_attr_tab.status = ESP_GATT_OK; param.add_attr_tab.num_handle = max_nb_attr; if (param.add_attr_tab.status != ESP_GATT_OK) { btc_gatts_cb_to_app(ESP_GATTS_CREAT_ATTR_TAB_EVT, gatts_if, ¶m); //reset the env after sent the data to app memset(&btc_creat_tab_env, 0, sizeof(esp_btc_creat_tab_t)); return; } // Check the attribute table is valid or not if ((param.add_attr_tab.status = btc_gatts_check_valid_attr_tab(gatts_attr_db, max_nb_attr)) != ESP_GATT_OK) { //sent the callback event to the application btc_gatts_cb_to_app(ESP_GATTS_CREAT_ATTR_TAB_EVT, gatts_if, ¶m); return; } //set the attribute table create service flag to true btc_creat_tab_env.is_tab_creat_svc = true; btc_creat_tab_env.num_handle = max_nb_attr; for(int i = 0; i < max_nb_attr; i++){ if(gatts_attr_db[i].att_desc.uuid_length == ESP_UUID_LEN_16){ uuid = (gatts_attr_db[i].att_desc.uuid_p[1] << 8) + (gatts_attr_db[i].att_desc.uuid_p[0]); } else{ continue; } future_p = future_new(); if (future_p == NULL) { BTC_TRACE_ERROR("%s failed:no mem\n", __func__); return ; } btc_creat_tab_env.complete_future = future_p; btc_creat_tab_env.handle_idx = i; switch(uuid) { case ESP_GATT_UUID_PRI_SERVICE:{ tBTA_GATT_SRVC_ID srvc_id; esp_gatt_srvc_id_t esp_srvc_id; esp_srvc_id.id.inst_id = srvc_inst_id; btc_gatts_uuid_format_convert(&esp_srvc_id.id.uuid,gatts_attr_db[i].att_desc.length, gatts_attr_db[i].att_desc.value); btc_to_bta_srvc_id(&srvc_id, &esp_srvc_id); if (btc_creat_tab_env.is_use_svc != true) { BTA_GATTS_CreateService(gatts_if, &srvc_id.id.uuid, srvc_inst_id, max_nb_attr, true); btc_creat_tab_env.is_use_svc = true; } else { BTC_TRACE_ERROR("Each service table can only created one primary service."); param.add_attr_tab.status = ESP_GATT_ERROR; btc_gatts_cb_to_app(ESP_GATTS_CREAT_ATTR_TAB_EVT, gatts_if, ¶m); //reset the env after sent the data to app memset(&btc_creat_tab_env, 0, sizeof(esp_btc_creat_tab_t)); return; } if (future_await(future_p) == FUTURE_FAIL) { BTC_TRACE_ERROR("%s failed\n", __func__); return; } break; } case ESP_GATT_UUID_SEC_SERVICE:{ tBTA_GATT_SRVC_ID srvc_id; esp_gatt_srvc_id_t esp_srvc_id; esp_srvc_id.id.inst_id = srvc_inst_id; btc_gatts_uuid_format_convert(&esp_srvc_id.id.uuid,gatts_attr_db[i].att_desc.length, gatts_attr_db[i].att_desc.value); btc_to_bta_srvc_id(&srvc_id, &esp_srvc_id); if (btc_creat_tab_env.is_use_svc != true) { BTA_GATTS_CreateService(gatts_if, &srvc_id.id.uuid, srvc_inst_id, max_nb_attr, false); btc_creat_tab_env.is_use_svc = true; } else { BTC_TRACE_ERROR("Each service table can only created one secondary service."); param.add_attr_tab.status = ESP_GATT_ERROR; btc_gatts_cb_to_app(ESP_GATTS_CREAT_ATTR_TAB_EVT, gatts_if, ¶m); //reset the env after sent the data to app memset(&btc_creat_tab_env, 0, sizeof(esp_btc_creat_tab_t)); return; } if (future_await(future_p) == FUTURE_FAIL) { BTC_TRACE_ERROR("%s failed\n", __func__); return; } break; } case ESP_GATT_UUID_INCLUDE_SERVICE:{ esp_gatts_incl_svc_desc_t *incl_svc_desc = (esp_gatts_incl_svc_desc_t *)gatts_attr_db[i].att_desc.value; if(incl_svc_desc!= NULL){ if(btc_creat_tab_env.svc_start_hdl != 0){ BTA_GATTS_AddIncludeService(btc_creat_tab_env.svc_start_hdl, incl_svc_desc->start_hdl); if (future_await(future_p) == FUTURE_FAIL) { BTC_TRACE_ERROR("%s failed\n", __func__); return; } } } break; } case ESP_GATT_UUID_CHAR_DECLARE:{ uint16_t svc_hal = 0; tBT_UUID bta_char_uuid; tGATT_ATTR_VAL attr_val; esp_bt_uuid_t uuid_temp; tBTA_GATT_PERM perm; tBTA_GATTS_ATTR_CONTROL control; uint8_t char_property; if(btc_creat_tab_env.svc_start_hdl != 0){ svc_hal = btc_creat_tab_env.svc_start_hdl; if((gatts_attr_db[i].att_desc.value) == NULL){ BTC_TRACE_ERROR("%s Characteristic declaration should not be NULL\n", __func__); } else{ char_property = (uint8_t)(*(uint8_t*)(gatts_attr_db[i].att_desc.value)); perm = gatts_attr_db[i+1].att_desc.perm; attr_val.attr_len = gatts_attr_db[i+1].att_desc.length; attr_val.attr_max_len = gatts_attr_db[i+1].att_desc.max_length; btc_gatts_uuid_format_convert(&uuid_temp, gatts_attr_db[i+1].att_desc.uuid_length,gatts_attr_db[i+1].att_desc.uuid_p); btc_to_bta_uuid(&bta_char_uuid, &uuid_temp); attr_val.attr_val = gatts_attr_db[i+1].att_desc.value; control.auto_rsp = gatts_attr_db[i+1].attr_control.auto_rsp; BTA_GATTS_AddCharacteristic (svc_hal, &bta_char_uuid, perm, char_property, &attr_val, &control); if (future_await(future_p) == FUTURE_FAIL) { BTC_TRACE_ERROR("%s failed\n", __func__); return; } } } break; } case ESP_GATT_UUID_CHAR_EXT_PROP: case ESP_GATT_UUID_CHAR_DESCRIPTION: case ESP_GATT_UUID_CHAR_CLIENT_CONFIG: case ESP_GATT_UUID_CHAR_SRVR_CONFIG: case ESP_GATT_UUID_CHAR_PRESENT_FORMAT: case ESP_GATT_UUID_CHAR_AGG_FORMAT: case ESP_GATT_UUID_CHAR_VALID_RANGE: case ESP_GATT_UUID_EXT_RPT_REF_DESCR: case ESP_GATT_UUID_RPT_REF_DESCR:{ uint16_t svc_hal = btc_creat_tab_env.svc_start_hdl; tBT_UUID bta_char_uuid; esp_bt_uuid_t uuid_temp; tGATT_ATTR_VAL attr_val; tBTA_GATT_PERM perm = gatts_attr_db[i].att_desc.perm; tBTA_GATTS_ATTR_CONTROL control; if(svc_hal != 0){ attr_val.attr_len = gatts_attr_db[i].att_desc.length; attr_val.attr_max_len = gatts_attr_db[i].att_desc.max_length; attr_val.attr_val = gatts_attr_db[i].att_desc.value; btc_gatts_uuid_format_convert(&uuid_temp, gatts_attr_db[i].att_desc.uuid_length, gatts_attr_db[i].att_desc.uuid_p); btc_to_bta_uuid(&bta_char_uuid, &uuid_temp); control.auto_rsp = gatts_attr_db[i].attr_control.auto_rsp; BTA_GATTS_AddCharDescriptor(svc_hal, perm, &bta_char_uuid, &attr_val, &control); if (future_await(future_p) == FUTURE_FAIL) { BTC_TRACE_ERROR("%s failed\n", __func__); return; } } break; } default: future_free(future_p); break; } } param.add_attr_tab.handles = btc_creat_tab_env.handles; memcpy(¶m.add_attr_tab.svc_uuid, &btc_creat_tab_env.svc_uuid, sizeof(esp_bt_uuid_t)); param.add_attr_tab.svc_inst_id = srvc_inst_id; btc_gatts_cb_to_app(ESP_GATTS_CREAT_ATTR_TAB_EVT, gatts_if, ¶m); //reset the env after sent the data to app memset(&btc_creat_tab_env, 0, sizeof(esp_btc_creat_tab_t)); //set the flag value to false after the service is created. btc_creat_tab_env.is_tab_creat_svc = false; } static esp_gatt_status_t btc_gatts_check_valid_attr_tab(esp_gatts_attr_db_t *gatts_attr_db, uint8_t max_nb_attr) { uint8_t svc_num = 0; uint16_t uuid = 0; for(int i = 0; i < max_nb_attr; i++) { if(gatts_attr_db[i].att_desc.uuid_length != ESP_UUID_LEN_16) { continue; } uuid = (gatts_attr_db[i].att_desc.uuid_p[1] << 8) + (gatts_attr_db[i].att_desc.uuid_p[0]); switch(uuid) { case ESP_GATT_UUID_PRI_SERVICE: case ESP_GATT_UUID_SEC_SERVICE: if (++svc_num > 1) { BTC_TRACE_ERROR("Each service table can only created one primary service or secondly service."); return ESP_GATT_ERROR; } break; case ESP_GATT_UUID_INCLUDE_SERVICE: { esp_gatts_incl_svc_desc_t *svc_desc = (esp_gatts_incl_svc_desc_t *)gatts_attr_db[i].att_desc.value; if(svc_desc == NULL) { BTC_TRACE_ERROR("%s, The include service attribute should not be NULL.", __func__); return ESP_GATT_INVALID_PDU; } else if((svc_desc->start_hdl == 0) || (svc_desc->end_hdl == 0) || (svc_desc->start_hdl == svc_desc->end_hdl)) { BTC_TRACE_ERROR("%s, The include service attribute handle is invalid, start_hanlde = %d, end_handle = %d",\ __func__, svc_desc->start_hdl, svc_desc->end_hdl); return ESP_GATT_INVALID_HANDLE; } break; } case ESP_GATT_UUID_CHAR_DECLARE: if((gatts_attr_db[i].att_desc.value) == NULL) { BTC_TRACE_ERROR("%s, Characteristic declaration should not be NULL.", __func__); return ESP_GATT_INVALID_PDU; } if(gatts_attr_db[i+1].att_desc.uuid_length != ESP_UUID_LEN_16 && gatts_attr_db[i+1].att_desc.uuid_length != ESP_UUID_LEN_32 && gatts_attr_db[i+1].att_desc.uuid_length != ESP_UUID_LEN_128) { BTC_TRACE_ERROR("%s, The Charateristic uuid length = %d is invalid", __func__,\ gatts_attr_db[i+1].att_desc.uuid_length); return ESP_GATT_INVALID_ATTR_LEN; } if(gatts_attr_db[i+1].att_desc.uuid_length == ESP_UUID_LEN_16) { uuid = (gatts_attr_db[i+1].att_desc.uuid_p[1] << 8) + (gatts_attr_db[i+1].att_desc.uuid_p[0]); if(uuid == ESP_GATT_UUID_CHAR_DECLARE || uuid == ESP_GATT_UUID_CHAR_EXT_PROP || uuid == ESP_GATT_UUID_CHAR_DESCRIPTION || uuid == ESP_GATT_UUID_CHAR_CLIENT_CONFIG || uuid == ESP_GATT_UUID_CHAR_SRVR_CONFIG || uuid == ESP_GATT_UUID_CHAR_PRESENT_FORMAT || uuid == ESP_GATT_UUID_CHAR_AGG_FORMAT || uuid == ESP_GATT_UUID_CHAR_VALID_RANGE || uuid == ESP_GATT_UUID_EXT_RPT_REF_DESCR || uuid == ESP_GATT_UUID_RPT_REF_DESCR) { BTC_TRACE_ERROR("%s, The charateristic value uuid = %d is invalid", __func__, uuid); return ESP_GATT_INVALID_PDU; } } break; default: break; } } return ESP_GATT_OK; } esp_gatt_status_t btc_gatts_get_attr_value(uint16_t attr_handle, uint16_t *length, uint8_t **value) { return BTA_GetAttributeValue(attr_handle, length, value); } static void btc_gatts_cb_param_copy_req(btc_msg_t *msg, void *p_dest, void *p_src) { uint16_t event = msg->act; tBTA_GATTS *p_dest_data = (tBTA_GATTS *) p_dest; tBTA_GATTS *p_src_data = (tBTA_GATTS *) p_src; if (!p_src_data || !p_dest_data) { return; } // Copy basic structure first memcpy(p_dest_data, p_src_data, sizeof(tBTA_GATTS)); // Allocate buffer for request data if necessary switch (event) { case BTA_GATTS_READ_EVT: case BTA_GATTS_WRITE_EVT: case BTA_GATTS_EXEC_WRITE_EVT: case BTA_GATTS_MTU_EVT: p_dest_data->req_data.p_data = osi_malloc(sizeof(tBTA_GATTS_REQ_DATA)); if (p_dest_data->req_data.p_data != NULL) { memcpy(p_dest_data->req_data.p_data, p_src_data->req_data.p_data, sizeof(tBTA_GATTS_REQ_DATA)); } else { BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act); } break; default: break; } } static void btc_gatts_cb_param_copy_free(btc_msg_t *msg, tBTA_GATTS *p_data) { uint16_t event = msg->act; switch (event) { case BTA_GATTS_READ_EVT: case BTA_GATTS_WRITE_EVT: case BTA_GATTS_EXEC_WRITE_EVT: case BTA_GATTS_MTU_EVT: if (p_data && p_data->req_data.p_data) { osi_free(p_data->req_data.p_data); } break; case BTA_GATTS_CONF_EVT: break; default: break; } } static void btc_gatts_inter_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data) { bt_status_t status; btc_msg_t msg; msg.sig = BTC_SIG_API_CB; msg.pid = BTC_PID_GATTS; msg.act = event; if(btc_creat_tab_env.is_tab_creat_svc && btc_creat_tab_env.complete_future) { switch(event) { case BTA_GATTS_CREATE_EVT: { //save the service handle to the btc module after used //the attribute table method to creat a service bta_to_btc_uuid(&btc_creat_tab_env.svc_uuid, &p_data->create.uuid); uint8_t index = btc_creat_tab_env.handle_idx; btc_creat_tab_env.svc_start_hdl = p_data->create.service_id; btc_creat_tab_env.handles[index] = p_data->create.service_id; break; } case BTA_GATTS_ADD_INCL_SRVC_EVT: { uint8_t index = btc_creat_tab_env.handle_idx; btc_creat_tab_env.handles[index] = p_data->add_result.attr_id; break; } case BTA_GATTS_ADD_CHAR_EVT: { uint8_t index = btc_creat_tab_env.handle_idx; btc_creat_tab_env.handles[index] = p_data->add_result.attr_id - 1; btc_creat_tab_env.handles[index+1] = p_data->add_result.attr_id; break; } case BTA_GATTS_ADD_CHAR_DESCR_EVT: { uint8_t index = btc_creat_tab_env.handle_idx; btc_creat_tab_env.handles[index] = p_data->add_result.attr_id; break; } default: break; } future_ready(btc_creat_tab_env.complete_future, FUTURE_SUCCESS); return; } status = btc_transfer_context(&msg, p_data, sizeof(tBTA_GATTS), btc_gatts_cb_param_copy_req); if (status != BT_STATUS_SUCCESS) { BTC_TRACE_ERROR("%s btc_transfer_context failed\n", __func__); } } void btc_gatts_call_handler(btc_msg_t *msg) { btc_ble_gatts_args_t *arg = (btc_ble_gatts_args_t *)msg->arg; switch (msg->act) { case BTC_GATTS_ACT_APP_REGISTER: { tBT_UUID uuid; uuid.len = LEN_UUID_16; uuid.uu.uuid16 = arg->app_reg.app_id; BTA_GATTS_AppRegister(&uuid, btc_gatts_inter_cb); break; } case BTC_GATTS_ACT_APP_UNREGISTER: BTA_GATTS_AppDeregister(arg->app_unreg.gatts_if); break; case BTC_GATTS_ACT_CREATE_SERVICE: { tBTA_GATT_SRVC_ID srvc_id; btc_to_bta_srvc_id(&srvc_id, &arg->create_srvc.service_id); BTA_GATTS_CreateService(arg->create_srvc.gatts_if, &srvc_id.id.uuid, srvc_id.id.inst_id, arg->create_srvc.num_handle, srvc_id.is_primary); break; } case BTC_GATTS_ACT_CREATE_ATTR_TAB: btc_gatts_act_create_attr_tab(arg->create_attr_tab.gatts_attr_db, arg->create_attr_tab.gatts_if, arg->create_attr_tab.max_nb_attr, arg->create_attr_tab.srvc_inst_id); break; case BTC_GATTS_ACT_DELETE_SERVICE: BTA_GATTS_DeleteService(arg->delete_srvc.service_handle); break; case BTC_GATTS_ACT_START_SERVICE: BTA_GATTS_StartService(arg->start_srvc.service_handle, BTA_GATT_TRANSPORT_LE); break; case BTC_GATTS_ACT_STOP_SERVICE: BTA_GATTS_StopService(arg->stop_srvc.service_handle); break; case BTC_GATTS_ACT_ADD_INCLUDE_SERVICE: BTA_GATTS_AddIncludeService(arg->add_incl_srvc.service_handle, arg->add_incl_srvc.included_service_handle); break; case BTC_GATTS_ACT_ADD_CHAR: { tBT_UUID uuid; btc_to_bta_uuid(&uuid, &arg->add_char.char_uuid); BTA_GATTS_AddCharacteristic(arg->add_char.service_handle, &uuid, arg->add_char.perm, arg->add_char.property, (tGATT_ATTR_VAL *)&arg->add_char.char_val, (tBTA_GATTS_ATTR_CONTROL *)&arg->add_char.attr_control); break; } case BTC_GATTS_ACT_ADD_CHAR_DESCR: { tBT_UUID uuid; btc_to_bta_uuid(&uuid, &arg->add_descr.descr_uuid); BTA_GATTS_AddCharDescriptor(arg->add_descr.service_handle, arg->add_descr.perm, &uuid, (tBTA_GATT_ATTR_VAL *)&arg->add_descr.descr_val, (tBTA_GATTS_ATTR_CONTROL *)&arg->add_descr.attr_control); break; } case BTC_GATTS_ACT_SEND_INDICATE: BTA_GATTS_HandleValueIndication(arg->send_ind.conn_id, arg->send_ind.attr_handle, arg->send_ind.value_len, arg->send_ind.value, arg->send_ind.need_confirm); break; case BTC_GATTS_ACT_SEND_RESPONSE: { esp_ble_gatts_cb_param_t param; esp_gatt_rsp_t *p_rsp = arg->send_rsp.rsp; if (p_rsp) { tBTA_GATTS_RSP rsp_struct; btc_to_bta_response(&rsp_struct, p_rsp); BTA_GATTS_SendRsp(arg->send_rsp.conn_id, arg->send_rsp.trans_id, arg->send_rsp.status, &rsp_struct); param.rsp.handle = rsp_struct.attr_value.handle; } else { BTA_GATTS_SendRsp(arg->send_rsp.conn_id, arg->send_rsp.trans_id, arg->send_rsp.status, NULL); } param.rsp.status = 0; btc_gatts_cb_to_app(ESP_GATTS_RESPONSE_EVT, BTC_GATT_GET_GATT_IF(arg->send_rsp.conn_id), ¶m); break; } case BTC_GATTS_ACT_SET_ATTR_VALUE: BTA_SetAttributeValue(arg->set_attr_val.handle, arg->set_attr_val.length, arg->set_attr_val.value); break; case BTC_GATTS_ACT_OPEN: { // Ensure device is in inquiry database tBTA_GATT_TRANSPORT transport = BTA_GATT_TRANSPORT_LE; //TODO : implement address type and device type #if 0 if (_get_address_type(arg->remote_bda, &addr_type) && btif_get_device_type(arg->remote_bda, &device_type) && device_type != BT_DEVICE_TYPE_BREDR) { BTA_DmAddBleDevice(p_cb->bd_addr.address, addr_type, device_type); } #else //BTA_DmAddBleDevice(p_cb->bd_addr.address, addr_type, device_type); #endif /* not support background connection // Mark background connections if (!arg->open.is_direct) { BTA_DmBleSetBgConnType(BTM_BLE_CONN_AUTO, NULL); } */ transport = BTA_GATT_TRANSPORT_LE; // Connect! BTA_GATTS_Open(arg->open.gatts_if, arg->open.remote_bda, arg->open.is_direct, transport); break; } case BTC_GATTS_ACT_CLOSE: // TODO : implement cancel open // Cancel pending foreground/background connections //BTA_GATTS_CancelOpen(p_cb->server_if, p_cb->bd_addr.address, TRUE); //BTA_GATTS_CancelOpen(p_cb->server_if, p_cb->bd_addr.address, FALSE); // Close active connection if (arg->close.conn_id != 0) { BTA_GATTS_Close(arg->close.conn_id); } break; case BTC_GATTS_ACT_SEND_SERVICE_CHANGE: { BD_ADDR remote_bda; memcpy(remote_bda, arg->send_service_change.remote_bda, BD_ADDR_LEN); BTA_GATTS_SendServiceChangeIndication(arg->send_service_change.gatts_if, remote_bda); break; } default: break; } btc_gatts_arg_deep_free(msg); } void btc_gatts_cb_handler(btc_msg_t *msg) { esp_ble_gatts_cb_param_t param; tBTA_GATTS *p_data = (tBTA_GATTS *)msg->arg; esp_gatt_if_t gatts_if; switch (msg->act) { case BTA_GATTS_REG_EVT: { gatts_if = p_data->reg_oper.server_if; param.reg.status = p_data->reg_oper.status; param.reg.app_id = p_data->reg_oper.uuid.uu.uuid16; btc_gatts_cb_to_app(ESP_GATTS_REG_EVT, gatts_if, ¶m); break; } case BTA_GATTS_DEREG_EVT: { gatts_if = p_data->reg_oper.server_if; btc_gatts_cb_to_app(ESP_GATTS_UNREG_EVT, gatts_if, NULL); break; } case BTA_GATTS_READ_EVT: { gatts_if = BTC_GATT_GET_GATT_IF(p_data->req_data.conn_id); param.read.conn_id = BTC_GATT_GET_CONN_ID(p_data->req_data.conn_id); param.read.trans_id = p_data->req_data.trans_id; memcpy(param.read.bda, p_data->req_data.remote_bda, ESP_BD_ADDR_LEN); param.read.handle = p_data->req_data.p_data->read_req.handle; param.read.offset = p_data->req_data.p_data->read_req.offset; param.read.is_long = p_data->req_data.p_data->read_req.is_long; param.read.need_rsp = p_data->req_data.p_data->read_req.need_rsp; btc_gatts_cb_to_app(ESP_GATTS_READ_EVT, gatts_if, ¶m); break; } case BTA_GATTS_WRITE_EVT: { gatts_if = BTC_GATT_GET_GATT_IF(p_data->req_data.conn_id); param.write.conn_id = BTC_GATT_GET_CONN_ID(p_data->req_data.conn_id); param.write.trans_id = p_data->req_data.trans_id; memcpy(param.write.bda, p_data->req_data.remote_bda, ESP_BD_ADDR_LEN); if (p_data->req_data.p_data == NULL) { break; } param.write.handle = p_data->req_data.p_data->write_req.handle; param.write.offset = p_data->req_data.p_data->write_req.offset; param.write.need_rsp = p_data->req_data.p_data->write_req.need_rsp; param.write.is_prep = p_data->req_data.p_data->write_req.is_prep; param.write.len = p_data->req_data.p_data->write_req.len; param.write.value = p_data->req_data.p_data->write_req.value; btc_gatts_cb_to_app(ESP_GATTS_WRITE_EVT, gatts_if, ¶m); break; } case BTA_GATTS_EXEC_WRITE_EVT: { gatts_if = BTC_GATT_GET_GATT_IF(p_data->req_data.conn_id); param.exec_write.conn_id = BTC_GATT_GET_CONN_ID(p_data->req_data.conn_id); param.exec_write.trans_id = p_data->req_data.trans_id; memcpy(param.exec_write.bda, p_data->req_data.remote_bda, ESP_BD_ADDR_LEN); if (p_data->req_data.p_data == NULL) { break; } param.exec_write.exec_write_flag = p_data->req_data.p_data->exec_write; btc_gatts_cb_to_app(ESP_GATTS_EXEC_WRITE_EVT, gatts_if, ¶m); break; } case BTA_GATTS_MTU_EVT: gatts_if = BTC_GATT_GET_GATT_IF(p_data->req_data.conn_id); param.mtu.conn_id = BTC_GATT_GET_CONN_ID(p_data->req_data.conn_id); param.mtu.mtu = p_data->req_data.p_data->mtu; btc_gatts_cb_to_app(ESP_GATTS_MTU_EVT, gatts_if, ¶m); break; case BTA_GATTS_CONF_EVT: gatts_if = BTC_GATT_GET_GATT_IF(p_data->req_data.conn_id); param.conf.conn_id = BTC_GATT_GET_CONN_ID(p_data->req_data.conn_id); param.conf.status = p_data->req_data.status; param.conf.handle = p_data->req_data.handle; if (p_data->req_data.status != ESP_GATT_OK && p_data->req_data.value){ param.conf.len = p_data->req_data.data_len; param.conf.value = p_data->req_data.value; }else{ param.conf.len = 0; } btc_gatts_cb_to_app(ESP_GATTS_CONF_EVT, gatts_if, ¶m); break; case BTA_GATTS_CREATE_EVT: gatts_if = p_data->create.server_if; param.create.status = p_data->create.status; param.create.service_handle = p_data->create.service_id; param.create.service_id.is_primary = p_data->create.is_primary; param.create.service_id.id.inst_id = p_data->create.svc_instance; bta_to_btc_uuid(¶m.create.service_id.id.uuid, &p_data->create.uuid); btc_gatts_cb_to_app(ESP_GATTS_CREATE_EVT, gatts_if, ¶m); break; case BTA_GATTS_ADD_INCL_SRVC_EVT: gatts_if = p_data->add_result.server_if; param.add_incl_srvc.status = p_data->add_result.status; param.add_incl_srvc.attr_handle = p_data->add_result.attr_id; param.add_incl_srvc.service_handle = p_data->add_result.service_id; btc_gatts_cb_to_app(ESP_GATTS_ADD_INCL_SRVC_EVT, gatts_if, ¶m); break; case BTA_GATTS_ADD_CHAR_EVT: gatts_if = p_data->add_result.server_if; param.add_char.status = p_data->add_result.status; param.add_char.attr_handle = p_data->add_result.attr_id; param.add_char.service_handle = p_data->add_result.service_id; bta_to_btc_uuid(¶m.add_char.char_uuid, &p_data->add_result.char_uuid); btc_gatts_cb_to_app(ESP_GATTS_ADD_CHAR_EVT, gatts_if, ¶m); break; case BTA_GATTS_ADD_CHAR_DESCR_EVT: gatts_if = p_data->add_result.server_if; param.add_char_descr.status = p_data->add_result.status; param.add_char_descr.attr_handle = p_data->add_result.attr_id; param.add_char_descr.service_handle = p_data->add_result.service_id; bta_to_btc_uuid(¶m.add_char_descr.descr_uuid, &p_data->add_result.char_uuid); btc_gatts_cb_to_app(ESP_GATTS_ADD_CHAR_DESCR_EVT, gatts_if, ¶m); break; case BTA_GATTS_DELELTE_EVT: gatts_if = p_data->srvc_oper.server_if; param.del.status = p_data->srvc_oper.status; param.del.service_handle = p_data->srvc_oper.service_id; btc_gatts_cb_to_app(ESP_GATTS_DELETE_EVT, gatts_if, ¶m); break; case BTA_GATTS_START_EVT: gatts_if = p_data->srvc_oper.server_if; param.start.status = p_data->srvc_oper.status; param.start.service_handle = p_data->srvc_oper.service_id; btc_gatts_cb_to_app(ESP_GATTS_START_EVT, gatts_if, ¶m); break; case BTA_GATTS_STOP_EVT: gatts_if = p_data->srvc_oper.server_if; param.stop.status = p_data->srvc_oper.status; param.stop.service_handle = p_data->srvc_oper.service_id; btc_gatts_cb_to_app(ESP_GATTS_STOP_EVT, gatts_if, ¶m); break; case BTA_GATTS_CONNECT_EVT: gatts_if = p_data->conn.server_if; param.connect.conn_id = BTC_GATT_GET_CONN_ID(p_data->conn.conn_id); memcpy(param.connect.remote_bda, p_data->conn.remote_bda, ESP_BD_ADDR_LEN); btc_gatts_cb_to_app(ESP_GATTS_CONNECT_EVT, gatts_if, ¶m); break; case BTA_GATTS_DISCONNECT_EVT: gatts_if = p_data->conn.server_if; param.disconnect.conn_id = BTC_GATT_GET_CONN_ID(p_data->conn.conn_id); param.disconnect.reason = p_data->conn.reason; memcpy(param.disconnect.remote_bda, p_data->conn.remote_bda, ESP_BD_ADDR_LEN); btc_gatts_cb_to_app(ESP_GATTS_DISCONNECT_EVT, gatts_if, ¶m); break; case BTA_GATTS_OPEN_EVT: gatts_if = p_data->open.server_if; param.open.status = p_data->open.status; btc_gatts_cb_to_app(BTA_GATTS_OPEN_EVT, gatts_if, ¶m); break; case BTA_GATTS_CANCEL_OPEN_EVT: gatts_if = p_data->cancel_open.server_if; param.cancel_open.status = p_data->cancel_open.status; btc_gatts_cb_to_app(BTA_GATTS_CANCEL_OPEN_EVT, gatts_if, ¶m); break; case BTA_GATTS_CLOSE_EVT: gatts_if = BTC_GATT_GET_GATT_IF(p_data->close.conn_id); param.close.status = p_data->close.status; param.close.conn_id = BTC_GATT_GET_CONN_ID(p_data->close.conn_id); btc_gatts_cb_to_app(BTA_GATTS_CLOSE_EVT, gatts_if, ¶m); break; case BTA_GATTS_SEND_SERVICE_CHANGE_EVT: gatts_if = p_data->service_change.server_if; param.service_change.status = p_data->service_change.status; btc_gatts_cb_to_app(ESP_GATTS_SEND_SERVICE_CHANGE_EVT, gatts_if, ¶m); break; case BTA_GATTS_LISTEN_EVT: // do nothing break; case BTA_GATTS_CONGEST_EVT: gatts_if = BTC_GATT_GET_GATT_IF(p_data->congest.conn_id); param.congest.conn_id = BTC_GATT_GET_CONN_ID(p_data->congest.conn_id); param.congest.congested = p_data->congest.congested; btc_gatts_cb_to_app(ESP_GATTS_CONGEST_EVT, gatts_if, ¶m); break; case BTA_GATTS_SET_ATTR_VAL_EVT: gatts_if = p_data->attr_val.server_if; param.set_attr_val.srvc_handle = p_data->attr_val.service_id; param.set_attr_val.attr_handle = p_data->attr_val.attr_id; param.set_attr_val.status = p_data->attr_val.status; btc_gatts_cb_to_app(ESP_GATTS_SET_ATTR_VAL_EVT, gatts_if, ¶m); break; default: // do nothing break; } btc_gatts_cb_param_copy_free(msg, p_data); } #endif ///GATTS_INCLUDED