/****************************************************************************** * * 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. * ******************************************************************************/ #define LOG_TAG "bt_btif_gatt" #include #include #include #include #include #include #include "btif_common.h" #include "btif_util.h" #if (defined(BLE_INCLUDED) && (BLE_INCLUDED == TRUE)) #include "bta_gatt_api.h" #include "bte_appl.h" #include "btif_dm.h" #include "btif_gatt.h" #include "btif_gatt_util.h" #include "btif_storage.h" #include "gatt_api.h" #include "osi/include/log.h" /******************************************************************************* * Typedefs & Macros *******************************************************************************/ typedef struct { tGATT_IF gatt_if; UINT16 conn_id; } btif_test_cb_t; /******************************************************************************* * Static variables *******************************************************************************/ static const char * disc_name[GATT_DISC_MAX] = { "Unknown", "GATT_DISC_SRVC_ALL", "GATT_DISC_SRVC_BY_UUID", "GATT_DISC_INC_SRVC", "GATT_DISC_CHAR", "GATT_DISC_CHAR_DSCPT" }; static btif_test_cb_t test_cb; /******************************************************************************* * Callback functions *******************************************************************************/ static char * format_uuid(tBT_UUID bt_uuid, char *str_buf) { int x = 0; if (bt_uuid.len == LEN_UUID_16) { sprintf(str_buf, "0x%04x", bt_uuid.uu.uuid16); } else if (bt_uuid.len == LEN_UUID_128) { x += sprintf(&str_buf[x], "%02x%02x%02x%02x-%02x%02x-%02x%02x", bt_uuid.uu.uuid128[15], bt_uuid.uu.uuid128[14], bt_uuid.uu.uuid128[13], bt_uuid.uu.uuid128[12], bt_uuid.uu.uuid128[11], bt_uuid.uu.uuid128[10], bt_uuid.uu.uuid128[9], bt_uuid.uu.uuid128[8]); sprintf(&str_buf[x], "%02x%02x-%02x%02x%02x%02x%02x%02x", bt_uuid.uu.uuid128[7], bt_uuid.uu.uuid128[6], bt_uuid.uu.uuid128[5], bt_uuid.uu.uuid128[4], bt_uuid.uu.uuid128[3], bt_uuid.uu.uuid128[2], bt_uuid.uu.uuid128[1], bt_uuid.uu.uuid128[0]); } else sprintf(str_buf, "Unknown (len=%d)", bt_uuid.len); return str_buf; } static void btif_test_connect_cback(tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id, BOOLEAN connected, tGATT_DISCONN_REASON reason, tBT_TRANSPORT transport) { UNUSED(gatt_if); UNUSED(bda); UNUSED(reason); UNUSED (transport); LOG_DEBUG(LOG_TAG, "%s: conn_id=%d, connected=%d", __FUNCTION__, conn_id, connected); test_cb.conn_id = connected ? conn_id : 0; } static void btif_test_command_complete_cback(UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, tGATT_CL_COMPLETE *p_data) { LOG_DEBUG(LOG_TAG, "%s: op_code=0x%02x, conn_id=0x%x. status=0x%x", __FUNCTION__, op, conn_id, status); switch (op) { case GATTC_OPTYPE_READ: case GATTC_OPTYPE_WRITE: case GATTC_OPTYPE_CONFIG: case GATTC_OPTYPE_EXE_WRITE: case GATTC_OPTYPE_NOTIFICATION: break; case GATTC_OPTYPE_INDICATION: GATTC_SendHandleValueConfirm(conn_id, p_data->handle); break; default: LOG_DEBUG(LOG_TAG, "%s: Unknown op_code (0x%02x)", __FUNCTION__, op); break; } } static void btif_test_discovery_result_cback(UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT_DISC_RES *p_data) { char str_buf[50]; UNUSED(conn_id); LOG_DEBUG(LOG_TAG, "------ GATT Discovery result %-22s -------", disc_name[disc_type]); LOG_DEBUG(LOG_TAG, " Attribute handle: 0x%04x (%d)", p_data->handle, p_data->handle); if (disc_type != GATT_DISC_CHAR_DSCPT) { LOG_DEBUG(LOG_TAG, " Attribute type: %s", format_uuid(p_data->type, str_buf)); } switch (disc_type) { case GATT_DISC_SRVC_ALL: LOG_DEBUG(LOG_TAG, " Handle range: 0x%04x ~ 0x%04x (%d ~ %d)", p_data->handle, p_data->value.group_value.e_handle, p_data->handle, p_data->value.group_value.e_handle); LOG_DEBUG(LOG_TAG, " Service UUID: %s", format_uuid(p_data->value.group_value.service_type, str_buf)); break; case GATT_DISC_SRVC_BY_UUID: LOG_DEBUG(LOG_TAG, " Handle range: 0x%04x ~ 0x%04x (%d ~ %d)", p_data->handle, p_data->value.handle, p_data->handle, p_data->value.handle); break; case GATT_DISC_INC_SRVC: LOG_DEBUG(LOG_TAG, " Handle range: 0x%04x ~ 0x%04x (%d ~ %d)", p_data->value.incl_service.s_handle, p_data->value.incl_service.e_handle, p_data->value.incl_service.s_handle, p_data->value.incl_service.e_handle); LOG_DEBUG(LOG_TAG, " Service UUID: %s", format_uuid(p_data->value.incl_service.service_type, str_buf)); break; case GATT_DISC_CHAR: LOG_DEBUG(LOG_TAG, " Properties: 0x%02x", p_data->value.dclr_value.char_prop); LOG_DEBUG(LOG_TAG, " Characteristic UUID: %s", format_uuid(p_data->value.dclr_value.char_uuid, str_buf)); break; case GATT_DISC_CHAR_DSCPT: LOG_DEBUG(LOG_TAG, " Descriptor UUID: %s", format_uuid(p_data->type, str_buf)); break; } LOG_DEBUG(LOG_TAG, "-----------------------------------------------------------"); } static void btif_test_discovery_complete_cback(UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT_STATUS status) { UNUSED(conn_id); UNUSED(disc_type); LOG_DEBUG(LOG_TAG, "%s: status=%d", __FUNCTION__, status); } static tGATT_CBACK btif_test_callbacks = { btif_test_connect_cback , btif_test_command_complete_cback, btif_test_discovery_result_cback, btif_test_discovery_complete_cback, NULL, NULL, NULL }; /******************************************************************************* * Implementation *******************************************************************************/ bt_status_t btif_gattc_test_command_impl(uint16_t command, btgatt_test_params_t* params) { switch(command) { case 0x01: /* Enable */ { LOG_DEBUG(LOG_TAG, "%s: ENABLE - enable=%d", __FUNCTION__, params->u1); if (params->u1) { tBT_UUID app_uuid = {LEN_UUID_128,{0xAE}}; test_cb.gatt_if = GATT_Register(&app_uuid, &btif_test_callbacks); GATT_StartIf(test_cb.gatt_if); } else { GATT_Deregister(test_cb.gatt_if); test_cb.gatt_if = 0; } break; } case 0x02: /* Connect */ { LOG_DEBUG(LOG_TAG, "%s: CONNECT - device=%02x:%02x:%02x:%02x:%02x:%02x (dev_type=%d, addr_type=%d)", __FUNCTION__, params->bda1->address[0], params->bda1->address[1], params->bda1->address[2], params->bda1->address[3], params->bda1->address[4], params->bda1->address[5], params->u1, params->u2); if (params->u1 == BT_DEVICE_TYPE_BLE) BTM_SecAddBleDevice(params->bda1->address, NULL, BT_DEVICE_TYPE_BLE, params->u2); if ( !GATT_Connect(test_cb.gatt_if, params->bda1->address, TRUE, BT_TRANSPORT_LE) ) { LOG_ERROR(LOG_TAG, "%s: GATT_Connect failed!", __FUNCTION__); } break; } case 0x03: /* Disconnect */ { LOG_DEBUG(LOG_TAG, "%s: DISCONNECT - conn_id=%d", __FUNCTION__, test_cb.conn_id); GATT_Disconnect(test_cb.conn_id); break; } case 0x04: /* Discover */ { char buf[50] = {0}; tGATT_DISC_PARAM param; memset(¶m, 0, sizeof(tGATT_DISC_PARAM)); if (params->u1 >= GATT_DISC_MAX) { LOG_ERROR(LOG_TAG, "%s: DISCOVER - Invalid type (%d)!", __FUNCTION__, params->u1); return 0; } param.s_handle = params->u2; param.e_handle = params->u3; btif_to_bta_uuid(¶m.service, params->uuid1); LOG_DEBUG(LOG_TAG, "%s: DISCOVER (%s), conn_id=%d, uuid=%s, handles=0x%04x-0x%04x", __FUNCTION__, disc_name[params->u1], test_cb.conn_id, format_uuid(param.service, buf), params->u2, params->u3); GATTC_Discover(test_cb.conn_id, params->u1, ¶m); break; } case 0xF0: /* Pairing configuration */ LOG_DEBUG(LOG_TAG, "%s: Setting pairing config auth=%d, iocaps=%d, keys=%d/%d/%d", __FUNCTION__, params->u1, params->u2, params->u3, params->u4, params->u5); bte_appl_cfg.ble_auth_req = params->u1; bte_appl_cfg.ble_io_cap = params->u2; bte_appl_cfg.ble_init_key = params->u3; bte_appl_cfg.ble_resp_key = params->u4; bte_appl_cfg.ble_max_key_size = params->u5; break; default: LOG_ERROR(LOG_TAG, "%s: UNKNOWN TEST COMMAND 0x%02x", __FUNCTION__, command); break; } return 0; } #endif