/****************************************************************************** * * Copyright (C) 2009-2013 Broadcom Corporation * * 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. * ******************************************************************************/ /******************************************************************************* * * Filename: btif_gatt_client.c * * Description: GATT client implementation * *******************************************************************************/ #include #include #include #include #include #include #define LOG_TAG "BtGatt.btif" #include "btif_common.h" #include "btif_util.h" #if (defined(BLE_INCLUDED) && (BLE_INCLUDED == TRUE)) #include "bta_api.h" #include "bta_gatt_api.h" #include "bd.h" #include "btif_storage.h" #include "btif_config.h" #include "btif_gatt.h" #include "btif_gatt_util.h" #include "btif_dm.h" #include "btif_storage.h" /******************************************************************************* ** Constants & Macros ********************************************************************************/ #define CHECK_BTGATT_INIT() if (bt_gatt_callbacks == NULL)\ {\ ALOGW("%s: BTGATT not initialized", __FUNCTION__);\ return BT_STATUS_NOT_READY;\ } else {\ ALOGD("%s", __FUNCTION__);\ } typedef enum { BTIF_GATTC_REGISTER_APP = 1000, BTIF_GATTC_UNREGISTER_APP, BTIF_GATTC_SCAN_START, BTIF_GATTC_SCAN_STOP, BTIF_GATTC_OPEN, BTIF_GATTC_CLOSE, BTIF_GATTC_SEARCH_SERVICE, BTIF_GATTC_GET_FIRST_CHAR, BTIF_GATTC_GET_NEXT_CHAR, BTIF_GATTC_GET_FIRST_CHAR_DESCR, BTIF_GATTC_GET_NEXT_CHAR_DESCR, BTIF_GATTC_GET_FIRST_INCL_SERVICE, BTIF_GATTC_GET_NEXT_INCL_SERVICE, BTIF_GATTC_READ_CHAR, BTIF_GATTC_READ_CHAR_DESCR, BTIF_GATTC_WRITE_CHAR, BTIF_GATTC_WRITE_CHAR_DESCR, BTIF_GATTC_EXECUTE_WRITE, BTIF_GATTC_REG_FOR_NOTIFICATION, BTIF_GATTC_DEREG_FOR_NOTIFICATION, BTIF_GATTC_REFRESH, BTIF_GATTC_READ_RSSI } btif_gattc_event_t; #define BTIF_GATT_MAX_OBSERVED_DEV 40 #define BTIF_GATT_OBSERVE_EVT 0x1000 #define BTIF_GATTC_RSSI_EVT 0x1001 /******************************************************************************* ** Local type definitions ********************************************************************************/ typedef struct { uint8_t value[BTGATT_MAX_ATTR_LEN]; bt_bdaddr_t bd_addr; btgatt_srvc_id_t srvc_id; btgatt_srvc_id_t incl_srvc_id; btgatt_char_id_t char_id; bt_uuid_t uuid; uint16_t conn_id; uint16_t len; uint8_t client_if; uint8_t action; uint8_t is_direct; uint8_t search_all; uint8_t auth_req; uint8_t write_type; uint8_t status; uint8_t addr_type; int8_t rssi; tBT_DEVICE_TYPE device_type; } __attribute__((packed)) btif_gattc_cb_t; typedef struct { bt_bdaddr_t bd_addr; BOOLEAN in_use; }__attribute__((packed)) btif_gattc_dev_t; typedef struct { btif_gattc_dev_t remote_dev[BTIF_GATT_MAX_OBSERVED_DEV]; uint8_t addr_type; uint8_t next_storage_idx; }__attribute__((packed)) btif_gattc_dev_cb_t; /******************************************************************************* ** Static variables ********************************************************************************/ extern const btgatt_callbacks_t *bt_gatt_callbacks; static btif_gattc_dev_cb_t btif_gattc_dev_cb; static btif_gattc_dev_cb_t *p_dev_cb = &btif_gattc_dev_cb; static uint8_t rssi_request_client_if; /******************************************************************************* ** Static functions ********************************************************************************/ static void btif_gattc_init_dev_cb(void) { memset(p_dev_cb, 0, sizeof(btif_gattc_dev_cb_t)); } static void btif_gattc_add_remote_bdaddr (BD_ADDR p_bda, uint8_t addr_type) { BOOLEAN found=FALSE; uint8_t i; for (i = 0; i < BTIF_GATT_MAX_OBSERVED_DEV; i++) { if (!p_dev_cb->remote_dev[i].in_use ) { memcpy(p_dev_cb->remote_dev[i].bd_addr.address, p_bda, BD_ADDR_LEN); p_dev_cb->addr_type = addr_type; p_dev_cb->remote_dev[i].in_use = TRUE; ALOGD("%s device added idx=%d", __FUNCTION__, i ); break; } } if ( i == BTIF_GATT_MAX_OBSERVED_DEV) { i= p_dev_cb->next_storage_idx; memcpy(p_dev_cb->remote_dev[i].bd_addr.address, p_bda, BD_ADDR_LEN); p_dev_cb->addr_type = addr_type; p_dev_cb->remote_dev[i].in_use = TRUE; ALOGD("%s device overwrite idx=%d", __FUNCTION__, i ); p_dev_cb->next_storage_idx++; if(p_dev_cb->next_storage_idx >= BTIF_GATT_MAX_OBSERVED_DEV) p_dev_cb->next_storage_idx = 0; } } static BOOLEAN btif_gattc_find_bdaddr (BD_ADDR p_bda) { uint8_t i; for (i = 0; i < BTIF_GATT_MAX_OBSERVED_DEV; i++) { if (p_dev_cb->remote_dev[i].in_use && !memcmp(p_dev_cb->remote_dev[i].bd_addr.address, p_bda, BD_ADDR_LEN)) { return TRUE; } } return FALSE; } static void btif_gattc_update_properties ( btif_gattc_cb_t *p_btif_cb ) { uint8_t remote_name_len; uint8_t *p_eir_remote_name=NULL; bt_bdname_t bdname; p_eir_remote_name = BTA_CheckEirData(p_btif_cb->value, BTM_EIR_COMPLETE_LOCAL_NAME_TYPE, &remote_name_len); if(p_eir_remote_name == NULL) { p_eir_remote_name = BTA_CheckEirData(p_btif_cb->value, BT_EIR_SHORTENED_LOCAL_NAME_TYPE, &remote_name_len); } if(p_eir_remote_name) { memcpy(bdname.name, p_eir_remote_name, remote_name_len); bdname.name[remote_name_len]='\0'; ALOGD("%s BLE device name=%s len=%d dev_type=%d", __FUNCTION__, bdname.name, remote_name_len, p_btif_cb->device_type ); btif_dm_update_ble_remote_properties( p_btif_cb->bd_addr.address, bdname.name, p_btif_cb->device_type); } btif_storage_set_remote_addr_type( &p_btif_cb->bd_addr, p_btif_cb->addr_type); } static void btif_gattc_upstreams_evt(uint16_t event, char* p_param) { ALOGD("%s: Event %d", __FUNCTION__, event); tBTA_GATTC *p_data = (tBTA_GATTC*)p_param; switch (event) { case BTA_GATTC_REG_EVT: { bt_uuid_t app_uuid; bta_to_btif_uuid(&app_uuid, &p_data->reg_oper.app_uuid); HAL_CBACK(bt_gatt_callbacks, client->register_client_cb , p_data->reg_oper.status , p_data->reg_oper.client_if , &app_uuid ); break; } case BTA_GATTC_DEREG_EVT: break; case BTA_GATTC_READ_CHAR_EVT: { btgatt_read_params_t data; set_read_value(&data, &p_data->read); HAL_CBACK(bt_gatt_callbacks, client->read_characteristic_cb , p_data->read.conn_id, p_data->read.status, &data); break; } case BTA_GATTC_WRITE_CHAR_EVT: case BTA_GATTC_PREP_WRITE_EVT: { btgatt_write_params_t data; bta_to_btif_srvc_id(&data.srvc_id, &p_data->write.srvc_id); bta_to_btif_char_id(&data.char_id, &p_data->write.char_id); HAL_CBACK(bt_gatt_callbacks, client->write_characteristic_cb , p_data->write.conn_id, p_data->write.status, &data ); break; } case BTA_GATTC_EXEC_EVT: { HAL_CBACK(bt_gatt_callbacks, client->execute_write_cb , p_data->exec_cmpl.conn_id, p_data->exec_cmpl.status ); break; } case BTA_GATTC_SEARCH_CMPL_EVT: { HAL_CBACK(bt_gatt_callbacks, client->search_complete_cb , p_data->search_cmpl.conn_id, p_data->search_cmpl.status); break; } case BTA_GATTC_SEARCH_RES_EVT: { btgatt_srvc_id_t data; bta_to_btif_srvc_id(&data, &(p_data->srvc_res.service_uuid)); HAL_CBACK(bt_gatt_callbacks, client->search_result_cb , p_data->srvc_res.conn_id, &data); break; } case BTA_GATTC_READ_DESCR_EVT: { btgatt_read_params_t data; set_read_value(&data, &p_data->read); HAL_CBACK(bt_gatt_callbacks, client->read_descriptor_cb , p_data->read.conn_id, p_data->read.status, &data); break; } case BTA_GATTC_WRITE_DESCR_EVT: { btgatt_write_params_t data; bta_to_btif_srvc_id(&data.srvc_id, &p_data->write.srvc_id); bta_to_btif_char_id(&data.char_id, &p_data->write.char_id); bta_to_btif_uuid(&data.descr_id, &p_data->write.descr_type); HAL_CBACK(bt_gatt_callbacks, client->write_descriptor_cb , p_data->write.conn_id, p_data->write.status, &data); break; } case BTA_GATTC_NOTIF_EVT: { btgatt_notify_params_t data; bdcpy(data.bda.address, p_data->notify.bda); bta_to_btif_srvc_id(&data.srvc_id, &p_data->notify.char_id.srvc_id); bta_to_btif_char_id(&data.char_id, &p_data->notify.char_id.char_id); memcpy(data.value, p_data->notify.value, p_data->notify.len); data.is_notify = p_data->notify.is_notify; data.len = p_data->notify.len; HAL_CBACK(bt_gatt_callbacks, client->notify_cb , p_data->notify.conn_id, &data); if (p_data->notify.is_notify == FALSE) { BTA_GATTC_SendIndConfirm(p_data->notify.conn_id, &p_data->notify.char_id); } break; } case BTA_GATTC_OPEN_EVT: { bt_bdaddr_t bda; bdcpy(bda.address, p_data->open.remote_bda); if (p_data->open.status == BTA_GATT_OK) btif_gatt_check_encrypted_link(p_data->open.remote_bda); HAL_CBACK(bt_gatt_callbacks, client->open_cb, p_data->open.conn_id , p_data->open.status, p_data->open.client_if, &bda); break; } case BTA_GATTC_CLOSE_EVT: { bt_bdaddr_t bda; bdcpy(bda.address, p_data->close.remote_bda); HAL_CBACK(bt_gatt_callbacks, client->close_cb, p_data->close.conn_id , p_data->status, p_data->close.client_if, &bda); if(p_data->status == BTA_GATT_OK) btif_gatt_remove_encrypted_link(p_data->close.remote_bda); break; } case BTA_GATTC_ACL_EVT: ALOGD("BTA_GATTC_ACL_EVT: status = %d", p_data->status); /* Ignore for now */ break; case BTA_GATTC_CANCEL_OPEN_EVT: break; case BTIF_GATT_OBSERVE_EVT: { btif_gattc_cb_t *p_btif_cb = (btif_gattc_cb_t*)p_param; if (!btif_gattc_find_bdaddr(p_btif_cb->bd_addr.address)) { btif_gattc_add_remote_bdaddr(p_btif_cb->bd_addr.address, p_btif_cb->addr_type); btif_gattc_update_properties(p_btif_cb); } HAL_CBACK(bt_gatt_callbacks, client->scan_result_cb, &p_btif_cb->bd_addr, p_btif_cb->rssi, p_btif_cb->value); break; } case BTIF_GATTC_RSSI_EVT: { btif_gattc_cb_t *p_btif_cb = (btif_gattc_cb_t*)p_param; HAL_CBACK(bt_gatt_callbacks, client->read_remote_rssi_cb, p_btif_cb->client_if, &p_btif_cb->bd_addr, p_btif_cb->rssi, p_btif_cb->status); break; } default: ALOGE("%s: Unhandled event (%d)!", __FUNCTION__, event); break; } } static void bte_gattc_cback(tBTA_GATTC_EVT event, tBTA_GATTC *p_data) { bt_status_t status = btif_transfer_context(btif_gattc_upstreams_evt, (uint16_t) event, (void*)p_data, sizeof(tBTA_GATTC), NULL); ASSERTC(status == BT_STATUS_SUCCESS, "Context transfer failed!", status); } static void bte_scan_results_cb (tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_data) { btif_gattc_cb_t btif_cb; uint8_t len; switch (event) { case BTA_DM_INQ_RES_EVT: { bdcpy(btif_cb.bd_addr.address, p_data->inq_res.bd_addr); btif_cb.device_type = p_data->inq_res.device_type; btif_cb.rssi = p_data->inq_res.rssi; btif_cb.addr_type = p_data->inq_res.ble_addr_type; if (p_data->inq_res.p_eir) { memcpy(btif_cb.value, p_data->inq_res.p_eir, 62); if (BTA_CheckEirData(p_data->inq_res.p_eir, BTM_EIR_COMPLETE_LOCAL_NAME_TYPE, &len)) { p_data->inq_res.remt_name_not_required = TRUE; } } } break; case BTA_DM_INQ_CMPL_EVT: { BTIF_TRACE_DEBUG2("%s BLE observe complete. Num Resp %d", __FUNCTION__,p_data->inq_cmpl.num_resps); return; } default: BTIF_TRACE_WARNING2("%s : Unknown event 0x%x", __FUNCTION__, event); return; } btif_transfer_context(btif_gattc_upstreams_evt, BTIF_GATT_OBSERVE_EVT, (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); } static void btm_read_rssi_cb (tBTM_RSSI_RESULTS *p_result) { btif_gattc_cb_t btif_cb; bdcpy(btif_cb.bd_addr.address, p_result->rem_bda); btif_cb.rssi = p_result->rssi; btif_cb.status = p_result->status; btif_cb.client_if = rssi_request_client_if; btif_transfer_context(btif_gattc_upstreams_evt, BTIF_GATTC_RSSI_EVT, (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); } static void btgattc_handle_event(uint16_t event, char* p_param) { tBTA_GATT_STATUS status; tBT_UUID uuid; tBTA_GATT_SRVC_ID srvc_id; tGATT_CHAR_PROP out_char_prop; tBTA_GATTC_CHAR_ID in_char_id; tBTA_GATTC_CHAR_ID out_char_id; tBTA_GATTC_CHAR_DESCR_ID in_char_descr_id; tBTA_GATTC_CHAR_DESCR_ID out_char_descr_id; tBTA_GATTC_INCL_SVC_ID in_incl_svc_id; tBTA_GATTC_INCL_SVC_ID out_incl_svc_id; tBTA_GATT_UNFMT descr_val; btif_gattc_cb_t* p_cb = (btif_gattc_cb_t*)p_param; if (!p_cb) return; ALOGD("%s: Event %d", __FUNCTION__, event); switch (event) { case BTIF_GATTC_REGISTER_APP: btif_to_bta_uuid(&uuid, &p_cb->uuid); BTA_GATTC_AppRegister(&uuid, bte_gattc_cback); break; case BTIF_GATTC_UNREGISTER_APP: BTA_GATTC_AppDeregister(p_cb->client_if); break; case BTIF_GATTC_SCAN_START: btif_gattc_init_dev_cb(); BTA_DmBleObserve(TRUE, 0, bte_scan_results_cb); break; case BTIF_GATTC_SCAN_STOP: BTA_DmBleObserve(FALSE, 0, 0); break; case BTIF_GATTC_OPEN: if (!p_cb->is_direct) BTA_DmBleSetBgConnType(BTM_BLE_CONN_AUTO, NULL); BTA_GATTC_Open(p_cb->client_if, p_cb->bd_addr.address, p_cb->is_direct); break; case BTIF_GATTC_CLOSE: // Disconnect establiched connections if (p_cb->conn_id != 0) BTA_GATTC_Close(p_cb->conn_id); else BTA_GATTC_CancelOpen(p_cb->client_if, p_cb->bd_addr.address, TRUE); // Cancel pending background connections (remove from whitelist) BTA_GATTC_CancelOpen(p_cb->client_if, p_cb->bd_addr.address, FALSE); break; case BTIF_GATTC_SEARCH_SERVICE: { if (p_cb->search_all) { BTA_GATTC_ServiceSearchRequest(p_cb->conn_id, NULL); } else { btif_to_bta_uuid(&uuid, &p_cb->uuid); BTA_GATTC_ServiceSearchRequest(p_cb->conn_id, &uuid); } break; } case BTIF_GATTC_GET_FIRST_CHAR: { btgatt_char_id_t char_id; btif_to_bta_srvc_id(&srvc_id, &p_cb->srvc_id); status = BTA_GATTC_GetFirstChar(p_cb->conn_id, &srvc_id, NULL, &out_char_id, &out_char_prop); if (status == 0) bta_to_btif_char_id(&char_id, &out_char_id.char_id); HAL_CBACK(bt_gatt_callbacks, client->get_characteristic_cb, p_cb->conn_id, status, &p_cb->srvc_id, &char_id, out_char_prop); break; } case BTIF_GATTC_GET_NEXT_CHAR: { btgatt_char_id_t char_id; btif_to_bta_srvc_id(&in_char_id.srvc_id, &p_cb->srvc_id); btif_to_bta_char_id(&in_char_id.char_id, &p_cb->char_id); status = BTA_GATTC_GetNextChar(p_cb->conn_id, &in_char_id, NULL, &out_char_id, &out_char_prop); if (status == 0) bta_to_btif_char_id(&char_id, &out_char_id.char_id); HAL_CBACK(bt_gatt_callbacks, client->get_characteristic_cb, p_cb->conn_id, status, &p_cb->srvc_id, &char_id, out_char_prop); break; } case BTIF_GATTC_GET_FIRST_CHAR_DESCR: { bt_uuid_t descr_id; btif_to_bta_srvc_id(&in_char_id.srvc_id, &p_cb->srvc_id); btif_to_bta_char_id(&in_char_id.char_id, &p_cb->char_id); status = BTA_GATTC_GetFirstCharDescr(p_cb->conn_id, &in_char_id, NULL, &out_char_descr_id); if (status == 0) bta_to_btif_uuid(&descr_id, &out_char_descr_id.descr_type); HAL_CBACK(bt_gatt_callbacks, client->get_descriptor_cb, p_cb->conn_id, status, &p_cb->srvc_id, &p_cb->char_id, &descr_id); break; } case BTIF_GATTC_GET_NEXT_CHAR_DESCR: { bt_uuid_t descr_id; btif_to_bta_srvc_id(&in_char_descr_id.char_id.srvc_id, &p_cb->srvc_id); btif_to_bta_char_id(&in_char_descr_id.char_id.char_id, &p_cb->char_id); btif_to_bta_uuid(&in_char_descr_id.descr_type, &p_cb->uuid); status = BTA_GATTC_GetNextCharDescr(p_cb->conn_id, &in_char_descr_id , NULL, &out_char_descr_id); if (status == 0) bta_to_btif_uuid(&descr_id, &out_char_descr_id.descr_type); HAL_CBACK(bt_gatt_callbacks, client->get_descriptor_cb, p_cb->conn_id, status, &p_cb->srvc_id, &p_cb->char_id, &descr_id); break; } case BTIF_GATTC_GET_FIRST_INCL_SERVICE: { btgatt_srvc_id_t incl_srvc_id; btif_to_bta_srvc_id(&srvc_id, &p_cb->srvc_id); status = BTA_GATTC_GetFirstIncludedService(p_cb->conn_id, &srvc_id, NULL, &out_incl_svc_id); bta_to_btif_srvc_id(&incl_srvc_id, &out_incl_svc_id.incl_svc_id); HAL_CBACK(bt_gatt_callbacks, client->get_included_service_cb, p_cb->conn_id, status, &p_cb->srvc_id, &incl_srvc_id); break; } case BTIF_GATTC_GET_NEXT_INCL_SERVICE: { btgatt_srvc_id_t incl_srvc_id; btif_to_bta_srvc_id(&in_incl_svc_id.srvc_id, &p_cb->srvc_id); btif_to_bta_srvc_id(&in_incl_svc_id.incl_svc_id, &p_cb->incl_srvc_id); status = BTA_GATTC_GetNextIncludedService(p_cb->conn_id, &in_incl_svc_id, NULL, &out_incl_svc_id); bta_to_btif_srvc_id(&incl_srvc_id, &out_incl_svc_id.incl_svc_id); HAL_CBACK(bt_gatt_callbacks, client->get_included_service_cb, p_cb->conn_id, status, &p_cb->srvc_id, &incl_srvc_id); break; } case BTIF_GATTC_READ_CHAR: btif_to_bta_srvc_id(&in_char_id.srvc_id, &p_cb->srvc_id); btif_to_bta_char_id(&in_char_id.char_id, &p_cb->char_id); BTA_GATTC_ReadCharacteristic(p_cb->conn_id, &in_char_id, p_cb->auth_req); break; case BTIF_GATTC_READ_CHAR_DESCR: btif_to_bta_srvc_id(&in_char_descr_id.char_id.srvc_id, &p_cb->srvc_id); btif_to_bta_char_id(&in_char_descr_id.char_id.char_id, &p_cb->char_id); btif_to_bta_uuid(&in_char_descr_id.descr_type, &p_cb->uuid); BTA_GATTC_ReadCharDescr(p_cb->conn_id, &in_char_descr_id, p_cb->auth_req); break; case BTIF_GATTC_WRITE_CHAR: btif_to_bta_srvc_id(&in_char_id.srvc_id, &p_cb->srvc_id); btif_to_bta_char_id(&in_char_id.char_id, &p_cb->char_id); BTA_GATTC_WriteCharValue(p_cb->conn_id, &in_char_id, p_cb->write_type, p_cb->len, p_cb->value, p_cb->auth_req); break; case BTIF_GATTC_WRITE_CHAR_DESCR: btif_to_bta_srvc_id(&in_char_descr_id.char_id.srvc_id, &p_cb->srvc_id); btif_to_bta_char_id(&in_char_descr_id.char_id.char_id, &p_cb->char_id); btif_to_bta_uuid(&in_char_descr_id.descr_type, &p_cb->uuid); descr_val.len = p_cb->len; descr_val.p_value = p_cb->value; BTA_GATTC_WriteCharDescr(p_cb->conn_id, &in_char_descr_id, p_cb->write_type, &descr_val, p_cb->auth_req); break; case BTIF_GATTC_EXECUTE_WRITE: BTA_GATTC_ExecuteWrite(p_cb->conn_id, p_cb->action); break; case BTIF_GATTC_REG_FOR_NOTIFICATION: btif_to_bta_srvc_id(&in_char_id.srvc_id, &p_cb->srvc_id); btif_to_bta_char_id(&in_char_id.char_id, &p_cb->char_id); status = BTA_GATTC_RegisterForNotifications(p_cb->client_if, p_cb->bd_addr.address, &in_char_id); HAL_CBACK(bt_gatt_callbacks, client->register_for_notification_cb, p_cb->conn_id, 1, status, &p_cb->srvc_id, &p_cb->char_id); break; case BTIF_GATTC_DEREG_FOR_NOTIFICATION: btif_to_bta_srvc_id(&in_char_id.srvc_id, &p_cb->srvc_id); btif_to_bta_char_id(&in_char_id.char_id, &p_cb->char_id); status = BTA_GATTC_DeregisterForNotifications(p_cb->client_if, p_cb->bd_addr.address, &in_char_id); HAL_CBACK(bt_gatt_callbacks, client->register_for_notification_cb, p_cb->conn_id, 0, status, &p_cb->srvc_id, &p_cb->char_id); break; case BTIF_GATTC_REFRESH: BTA_GATTC_Refresh(p_cb->bd_addr.address); break; case BTIF_GATTC_READ_RSSI: rssi_request_client_if = p_cb->client_if; BTM_ReadRSSI (p_cb->bd_addr.address, (tBTM_CMPL_CB *)btm_read_rssi_cb); break; default: ALOGE("%s: Unknown event (%d)!", __FUNCTION__, event); break; } } /******************************************************************************* ** Client API Functions ********************************************************************************/ static bt_status_t btif_gattc_register_app(bt_uuid_t *uuid) { CHECK_BTGATT_INIT(); btif_gattc_cb_t btif_cb; memcpy(&btif_cb.uuid, uuid, sizeof(bt_uuid_t)); return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_REGISTER_APP, (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); } static bt_status_t btif_gattc_unregister_app(int client_if ) { CHECK_BTGATT_INIT(); btif_gattc_cb_t btif_cb; btif_cb.client_if = (uint8_t) client_if; return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_UNREGISTER_APP, (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); } static bt_status_t btif_gattc_scan( int client_if, bool start ) { CHECK_BTGATT_INIT(); btif_gattc_cb_t btif_cb; btif_cb.client_if = (uint8_t) client_if; return btif_transfer_context(btgattc_handle_event, start ? BTIF_GATTC_SCAN_START : BTIF_GATTC_SCAN_STOP, (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); } static bt_status_t btif_gattc_open(int client_if, const bt_bdaddr_t *bd_addr, bool is_direct ) { CHECK_BTGATT_INIT(); btif_gattc_cb_t btif_cb; btif_cb.client_if = (uint8_t) client_if; btif_cb.is_direct = is_direct ? 1 : 0; bdcpy(btif_cb.bd_addr.address, bd_addr->address); return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_OPEN, (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); } static bt_status_t btif_gattc_close( int client_if, const bt_bdaddr_t *bd_addr, int conn_id) { CHECK_BTGATT_INIT(); btif_gattc_cb_t btif_cb; btif_cb.client_if = (uint8_t) client_if; btif_cb.conn_id = (uint16_t) conn_id; bdcpy(btif_cb.bd_addr.address, bd_addr->address); return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_CLOSE, (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); } static bt_status_t btif_gattc_refresh( int client_if, const bt_bdaddr_t *bd_addr ) { CHECK_BTGATT_INIT(); btif_gattc_cb_t btif_cb; btif_cb.client_if = (uint8_t) client_if; bdcpy(btif_cb.bd_addr.address, bd_addr->address); return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_REFRESH, (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); } static bt_status_t btif_gattc_search_service(int conn_id, bt_uuid_t *filter_uuid ) { CHECK_BTGATT_INIT(); btif_gattc_cb_t btif_cb; btif_cb.conn_id = (uint16_t) conn_id; btif_cb.search_all = filter_uuid ? 0 : 1; if (filter_uuid) memcpy(&btif_cb.uuid, filter_uuid, sizeof(bt_uuid_t)); return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_SEARCH_SERVICE, (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); } static bt_status_t btif_gattc_get_characteristic( int conn_id , btgatt_srvc_id_t *srvc_id, btgatt_char_id_t *start_char_id) { CHECK_BTGATT_INIT(); btif_gattc_cb_t btif_cb; btif_cb.conn_id = (uint16_t) conn_id; memcpy(&btif_cb.srvc_id, srvc_id, sizeof(btgatt_srvc_id_t)); if (start_char_id) { memcpy(&btif_cb.char_id, start_char_id, sizeof(btgatt_char_id_t)); return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_GET_NEXT_CHAR, (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); } return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_GET_FIRST_CHAR, (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); } static bt_status_t btif_gattc_get_descriptor( int conn_id , btgatt_srvc_id_t *srvc_id, btgatt_char_id_t *char_id , bt_uuid_t *start_descr_id) { CHECK_BTGATT_INIT(); btif_gattc_cb_t btif_cb; btif_cb.conn_id = (uint16_t) conn_id; memcpy(&btif_cb.srvc_id, srvc_id, sizeof(btgatt_srvc_id_t)); memcpy(&btif_cb.char_id, char_id, sizeof(btgatt_char_id_t)); if (start_descr_id) { memcpy(&btif_cb.uuid, start_descr_id, sizeof(bt_uuid_t)); return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_GET_NEXT_CHAR_DESCR, (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); } return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_GET_FIRST_CHAR_DESCR, (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); } static bt_status_t btif_gattc_get_included_service(int conn_id, btgatt_srvc_id_t *srvc_id, btgatt_srvc_id_t *start_incl_srvc_id) { CHECK_BTGATT_INIT(); btif_gattc_cb_t btif_cb; btif_cb.conn_id = (uint16_t) conn_id; memcpy(&btif_cb.srvc_id, srvc_id, sizeof(btgatt_srvc_id_t)); if (start_incl_srvc_id) { memcpy(&btif_cb.incl_srvc_id, start_incl_srvc_id, sizeof(btgatt_srvc_id_t)); return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_GET_NEXT_INCL_SERVICE, (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); } return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_GET_FIRST_INCL_SERVICE, (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); } static bt_status_t btif_gattc_read_char(int conn_id, btgatt_srvc_id_t* srvc_id, btgatt_char_id_t* char_id, int auth_req ) { CHECK_BTGATT_INIT(); btif_gattc_cb_t btif_cb; btif_cb.conn_id = (uint16_t) conn_id; btif_cb.auth_req = (uint8_t) auth_req; memcpy(&btif_cb.srvc_id, srvc_id, sizeof(btgatt_srvc_id_t)); memcpy(&btif_cb.char_id, char_id, sizeof(btgatt_char_id_t)); return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_READ_CHAR, (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); } static bt_status_t btif_gattc_read_char_descr(int conn_id, btgatt_srvc_id_t* srvc_id, btgatt_char_id_t* char_id, bt_uuid_t* descr_id, int auth_req ) { CHECK_BTGATT_INIT(); btif_gattc_cb_t btif_cb; btif_cb.conn_id = (uint16_t) conn_id; btif_cb.auth_req = (uint8_t) auth_req; memcpy(&btif_cb.srvc_id, srvc_id, sizeof(btgatt_srvc_id_t)); memcpy(&btif_cb.char_id, char_id, sizeof(btgatt_char_id_t)); memcpy(&btif_cb.uuid, descr_id, sizeof(bt_uuid_t)); return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_READ_CHAR_DESCR, (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); } static bt_status_t btif_gattc_write_char(int conn_id, btgatt_srvc_id_t* srvc_id, btgatt_char_id_t* char_id, int write_type, int len, int auth_req, char* p_value) { CHECK_BTGATT_INIT(); btif_gattc_cb_t btif_cb; btif_cb.conn_id = (uint16_t) conn_id; btif_cb.auth_req = (uint8_t) auth_req; btif_cb.write_type = (uint8_t) write_type; btif_cb.len = len > BTGATT_MAX_ATTR_LEN ? BTGATT_MAX_ATTR_LEN : len; memcpy(&btif_cb.srvc_id, srvc_id, sizeof(btgatt_srvc_id_t)); memcpy(&btif_cb.char_id, char_id, sizeof(btgatt_char_id_t)); memcpy(btif_cb.value, p_value, btif_cb.len); return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_WRITE_CHAR, (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); } static bt_status_t btif_gattc_write_char_descr(int conn_id, btgatt_srvc_id_t* srvc_id, btgatt_char_id_t* char_id, bt_uuid_t* descr_id, int write_type, int len, int auth_req, char* p_value) { CHECK_BTGATT_INIT(); btif_gattc_cb_t btif_cb; btif_cb.conn_id = (uint16_t) conn_id; btif_cb.auth_req = (uint8_t) auth_req; btif_cb.write_type = (uint8_t) write_type; btif_cb.len = len > BTGATT_MAX_ATTR_LEN ? BTGATT_MAX_ATTR_LEN : len; memcpy(&btif_cb.srvc_id, srvc_id, sizeof(btgatt_srvc_id_t)); memcpy(&btif_cb.char_id, char_id, sizeof(btgatt_char_id_t)); memcpy(&btif_cb.uuid, descr_id, sizeof(bt_uuid_t)); memcpy(btif_cb.value, p_value, btif_cb.len); return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_WRITE_CHAR_DESCR, (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); } static bt_status_t btif_gattc_execute_write(int conn_id, int execute) { CHECK_BTGATT_INIT(); btif_gattc_cb_t btif_cb; btif_cb.conn_id = (uint16_t) conn_id; btif_cb.action = (uint8_t) execute; return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_EXECUTE_WRITE, (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); } static bt_status_t btif_gattc_reg_for_notification(int client_if, const bt_bdaddr_t *bd_addr, btgatt_srvc_id_t* srvc_id, btgatt_char_id_t* char_id) { CHECK_BTGATT_INIT(); btif_gattc_cb_t btif_cb; btif_cb.client_if = (uint8_t) client_if; bdcpy(btif_cb.bd_addr.address, bd_addr->address); memcpy(&btif_cb.srvc_id, srvc_id, sizeof(btgatt_srvc_id_t)); memcpy(&btif_cb.char_id, char_id, sizeof(btgatt_char_id_t)); return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_REG_FOR_NOTIFICATION, (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); } static bt_status_t btif_gattc_dereg_for_notification(int client_if, const bt_bdaddr_t *bd_addr, btgatt_srvc_id_t* srvc_id, btgatt_char_id_t* char_id) { CHECK_BTGATT_INIT(); btif_gattc_cb_t btif_cb; btif_cb.client_if = (uint8_t) client_if; bdcpy(btif_cb.bd_addr.address, bd_addr->address); memcpy(&btif_cb.srvc_id, srvc_id, sizeof(btgatt_srvc_id_t)); memcpy(&btif_cb.char_id, char_id, sizeof(btgatt_char_id_t)); return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_DEREG_FOR_NOTIFICATION, (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); } static bt_status_t btif_gattc_read_remote_rssi(int client_if, const bt_bdaddr_t *bd_addr) { CHECK_BTGATT_INIT(); btif_gattc_cb_t btif_cb; btif_cb.client_if = (uint8_t) client_if; bdcpy(btif_cb.bd_addr.address, bd_addr->address); return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_READ_RSSI, (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); } static int btif_gattc_get_device_type( const bt_bdaddr_t *bd_addr ) { int device_type = 0; char bd_addr_str[18] = {0}; bd2str(bd_addr, &bd_addr_str); if (btif_config_get_int("Remote", bd_addr_str, "DevType", &device_type)) return device_type; return 0; } extern bt_status_t btif_gattc_test_command_impl(int command, btgatt_test_params_t* params); static bt_status_t btif_gattc_test_command(int command, btgatt_test_params_t* params) { return btif_gattc_test_command_impl(command, params); } const btgatt_client_interface_t btgattClientInterface = { btif_gattc_register_app, btif_gattc_unregister_app, btif_gattc_scan, btif_gattc_open, btif_gattc_close, btif_gattc_refresh, btif_gattc_search_service, btif_gattc_get_included_service, btif_gattc_get_characteristic, btif_gattc_get_descriptor, btif_gattc_read_char, btif_gattc_write_char, btif_gattc_read_char_descr, btif_gattc_write_char_descr, btif_gattc_execute_write, btif_gattc_reg_for_notification, btif_gattc_dereg_for_notification, btif_gattc_read_remote_rssi, btif_gattc_get_device_type, btif_gattc_test_command }; #endif