diff options
author | Andre Eisenbach <andre@broadcom.com> | 2012-02-22 13:18:21 -0800 |
---|---|---|
committer | Matthew Xie <mattx@google.com> | 2012-07-14 11:19:11 -0700 |
commit | e448862a47c08eb23185aaed574b39264f5005fc (patch) | |
tree | 2bc6246e3091315e77224fd798ea2fe8074ef972 /bta/gatt | |
parent | a2ca4b83ab8bbbfd8d5f6693e927ed4b82094624 (diff) | |
download | external_bluetooth_bluedroid-e448862a47c08eb23185aaed574b39264f5005fc.zip external_bluetooth_bluedroid-e448862a47c08eb23185aaed574b39264f5005fc.tar.gz external_bluetooth_bluedroid-e448862a47c08eb23185aaed574b39264f5005fc.tar.bz2 |
Initial Bluedroid stack commit
Diffstat (limited to 'bta/gatt')
-rw-r--r-- | bta/gatt/bta_gattc_act.c | 1789 | ||||
-rw-r--r-- | bta/gatt/bta_gattc_api.c | 922 | ||||
-rw-r--r-- | bta/gatt/bta_gattc_cache.c | 1584 | ||||
-rw-r--r-- | bta/gatt/bta_gattc_ci.c | 125 | ||||
-rw-r--r-- | bta/gatt/bta_gattc_int.h | 452 | ||||
-rw-r--r-- | bta/gatt/bta_gattc_main.c | 474 | ||||
-rw-r--r-- | bta/gatt/bta_gattc_utils.c | 652 | ||||
-rw-r--r-- | bta/gatt/bta_gatts_act.c | 785 | ||||
-rw-r--r-- | bta/gatt/bta_gatts_api.c | 500 | ||||
-rw-r--r-- | bta/gatt/bta_gatts_int.h | 233 | ||||
-rw-r--r-- | bta/gatt/bta_gatts_main.c | 122 | ||||
-rw-r--r-- | bta/gatt/bta_gatts_utils.c | 223 |
12 files changed, 7861 insertions, 0 deletions
diff --git a/bta/gatt/bta_gattc_act.c b/bta/gatt/bta_gattc_act.c new file mode 100644 index 0000000..ce0c209 --- /dev/null +++ b/bta/gatt/bta_gattc_act.c @@ -0,0 +1,1789 @@ +/***************************************************************************** +** +** Name: bta_gattc_act.c +** +** Description: This file contains the GATT client action +** functions for the state machine. +** +** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved. +** Broadcom Bluetooth Core. Proprietary and confidential. +** +*****************************************************************************/ + +#include "bt_target.h" + +#if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE) + + +#include "utl.h" +#include "gki.h" +#include "bd.h" +#include "bta_sys.h" + +#include "bta_gattc_int.h" +#include "l2c_api.h" + + +#include <string.h> + +/***************************************************************************** +** Constants +*****************************************************************************/ +static void bta_gattc_conn_cback(tGATT_IF gattc_if, BD_ADDR bda, UINT16 conn_id, + BOOLEAN connected, tGATT_DISCONN_REASON reason); + +static void bta_gattc_cmpl_cback(UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, + tGATT_CL_COMPLETE *p_data); + +static tGATT_CBACK bta_gattc_cl_cback = +{ + bta_gattc_conn_cback, + bta_gattc_cmpl_cback, + bta_gattc_disc_res_cback, + bta_gattc_disc_cmpl_cback, + NULL +}; + +/* opcode(tGATTC_OPTYPE) order has to be comply with internal event order */ +static UINT16 bta_gattc_opcode_to_int_evt[] = +{ + BTA_GATTC_API_READ_EVT, + BTA_GATTC_API_WRITE_EVT, + BTA_GATTC_API_EXEC_EVT +}; + +#if (BT_TRACE_VERBOSE == TRUE) +static const char *bta_gattc_op_code_name[] = +{ + "Unknown", + "Discovery", + "Read", + "Write", + "Exec", + "Config", + "Notification", + "Indication" +}; +#endif +/***************************************************************************** +** Action Functions +*****************************************************************************/ + +/******************************************************************************* +** +** Function bta_gattc_register +** +** Description Register a GATT client application with BTA. +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_register(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_data) +{ + tBTA_GATTC cb_data; + UINT8 i; + tBT_UUID *p_app_uuid = &p_data->api_reg.app_uuid; + tBTA_GATTC_INT_START_IF *p_buf; + + + /* todo need to check duplicate uuid */ + for (i = 0; i < BTA_GATTC_CL_MAX; i ++) + { + if (!p_cb->cl_rcb[i].in_use) + { + if ((p_app_uuid == NULL) || (p_cb->cl_rcb[i].client_if = GATT_Register(p_app_uuid, &bta_gattc_cl_cback)) == 0) + { + APPL_TRACE_ERROR0("Register with GATT stack failed."); + cb_data.reg_oper.status = BTA_GATT_ERROR; + } + else + + { + p_cb->cl_rcb[i].in_use = TRUE; + p_cb->cl_rcb[i].p_cback = p_data->api_reg.p_cback; + memcpy(&p_cb->cl_rcb[i].app_uuid, p_app_uuid, sizeof(tBT_UUID)); + + /* BTA use the same client interface as BTE GATT statck */ + cb_data.reg_oper.client_if = p_cb->cl_rcb[i].client_if; +// btla-specific ++ + memcpy(&(cb_data.reg_oper.app_uuid),p_app_uuid,sizeof(tBT_UUID)); +// btla-specific -- + + cb_data.reg_oper.status = BTA_GATT_OK; + + if ((p_buf = (tBTA_GATTC_INT_START_IF *) GKI_getbuf(sizeof(tBTA_GATTC_INT_START_IF))) != NULL) + { + p_buf->hdr.event = BTA_GATTC_INT_START_IF_EVT; + p_buf->client_if = p_cb->cl_rcb[i].client_if; + + bta_sys_sendmsg(p_buf); + } + else + { + cb_data.reg_oper.status = BTA_GATT_NO_RESOURCES; + memset( &p_cb->cl_rcb[i], 0 , sizeof(tBTA_GATTC_RCB)); + } + break; + } + } + } + /* callback with register event */ + if (p_data->api_reg.p_cback) + { + (*p_data->api_reg.p_cback)(BTA_GATTC_REG_EVT, (tBTA_GATTC *)&cb_data); + } +} + +/******************************************************************************* +** +** Function bta_gattc_start_if +** +** Description start an application interface. +** +** Returns none. +** +*******************************************************************************/ +void bta_gattc_start_if(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_msg) +{ + if (bta_gattc_cl_get_regcb(p_msg->int_start_if.client_if) !=NULL ) + { + GATT_StartIf(p_msg->int_start_if.client_if); + } + else + { + APPL_TRACE_ERROR1("Unable to start app.: Unknown interface =%d",p_msg->int_start_if.client_if ); + } +} + + +/******************************************************************************* +** +** Function bta_gattc_deregister_cmpl +** +** Description De-Register a GATT client application with BTA completed. +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_int_deregister_cmpl(tBTA_GATTC_RCB *p_clreg, tBTA_GATTC_IF client_if) +{ + tBTA_GATTC_CBACK *p_cback = p_clreg->p_cback; + tBTA_GATTC cb_data; + + + APPL_TRACE_DEBUG1("bta_gattc_int_deregister_cmpl client_if=%d", client_if ); + + GATT_Deregister(p_clreg->client_if); + memset(p_clreg, 0, sizeof(tBTA_GATTC_RCB)); + + cb_data.reg_oper.client_if = client_if; + cb_data.reg_oper.status = BTA_GATT_OK; + + if (p_cback) + /* callback with de-register event */ + (*p_cback)(BTA_GATTC_DEREG_EVT, (tBTA_GATTC *)&cb_data); +} + + +/******************************************************************************* +** +** Function bta_gattc_deregister_cmpl +** +** Description De-Register a GATT client application with BTA completed. +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_deregister_cmpl(tBTA_GATTC_RCB *p_clreg, tBTA_GATTC_IF client_if) +{ + tBTA_GATTC_INT_DEREG *p_buf; + + APPL_TRACE_DEBUG1("bta_gattc_deregister_cmpl client_if=%d", client_if ); + + if ((p_buf = (tBTA_GATTC_INT_DEREG *) GKI_getbuf(sizeof(tBTA_GATTC_INT_DEREG))) != NULL) + { + p_buf->hdr.event = BTA_GATTC_INT_DEREG_EVT; + p_buf->client_if = client_if; + bta_sys_sendmsg(p_buf); + } + else + { + APPL_TRACE_ERROR1("bta_gattc_deregister_cmpl unable to allocate buffer to complete dereg=%d", client_if); + } + +} + +/******************************************************************************* +** +** Function bta_gattc_deregister +** +** Description De-Register a GATT client application with BTA. +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_int_deregister(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_data) +{ + + tBTA_GATTC_IF client_if = p_data->int_dereg.client_if; + tBTA_GATTC_CBACK *p_cback; + tBTA_GATTC cb_data; + tBTA_GATTC_RCB *p_clreg; + + + APPL_TRACE_DEBUG1("bta_gattc_int_deregister_cmpl client_if=%d", client_if ); + + if ((p_clreg = bta_gattc_cl_get_regcb(client_if)) != NULL) + { + p_cback = p_clreg->p_cback; + GATT_Deregister(client_if); + memset(p_clreg, 0, sizeof(tBTA_GATTC_RCB)); + cb_data.reg_oper.client_if = client_if; + cb_data.reg_oper.status = BTA_GATT_OK; + + if (p_cback) + /* callback with de-register event */ + (*p_cback)(BTA_GATTC_DEREG_EVT, (tBTA_GATTC *)&cb_data); + } + else + { + APPL_TRACE_ERROR1("bta_gattc_int_deregister Deregister Failed, unknown client_if: %d", p_data->int_dereg.client_if); + } +} + + +/******************************************************************************* +** +** Function bta_gattc_deregister +** +** Description De-Register a GATT client application with BTA. +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_deregister(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_data) +{ + tBTA_GATTC_RCB *p_clreg; + UINT8 i; + BT_HDR buf; + + if ((p_clreg = bta_gattc_cl_get_regcb(p_data->api_dereg.client_if)) != NULL) + { + if (p_clreg->num_clcb > 0) + { + /* close all CLCB related to this app */ + for (i= 0; i < BTA_GATTC_CLCB_MAX; i ++) + { + if (p_cb->clcb[i].in_use && (p_cb->clcb[i].p_rcb == p_clreg)) + { + p_clreg->dereg_pending = TRUE; + + buf.event = BTA_GATTC_API_CLOSE_EVT; + buf.layer_specific = p_cb->clcb[i].bta_conn_id; + bta_gattc_close(&p_cb->clcb[i], (tBTA_GATTC_DATA *)&buf) ; + } + } + } + else + bta_gattc_deregister_cmpl(p_clreg, p_clreg->client_if); + } + else + { + APPL_TRACE_ERROR1("bta_gattc_deregister Deregister Failed, unknown client_if: %d", p_data->api_dereg.client_if); + } +} +/******************************************************************************* +** +** Function bta_gattc_process_api_open +** +** Description process connect API request. +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_process_api_open (tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA * p_msg) +{ + UINT16 event = ((BT_HDR *)p_msg)->event; + tBTA_GATTC_CLCB *p_clcb = NULL; + tBTA_GATTC_RCB *p_clreg = bta_gattc_cl_get_regcb(p_msg->api_conn.client_if); + + if (p_clreg != NULL) + { + if (p_msg->api_conn.is_direct) + { + if ((p_clcb = bta_gattc_find_alloc_clcb(p_msg->api_conn.client_if, + p_msg->api_conn.remote_bda)) != NULL) + { + bta_gattc_sm_execute(p_clcb, event, p_msg); + } + else + { + APPL_TRACE_ERROR0("No resources to open a new connection."); + + bta_gattc_send_open_cback(p_clreg, + BTA_GATT_NO_RESOURCES, + p_msg->api_conn.remote_bda, + BTA_GATT_INVALID_CONN_ID); + } + } + else + { + bta_gattc_init_bk_conn(&p_msg->api_conn, p_clreg); + } + } + else + { + APPL_TRACE_ERROR1("bta_gattc_process_api_open Failed, unknown client_if: %d", + p_msg->api_conn.client_if); + } +} +/******************************************************************************* +** +** Function bta_gattc_process_api_open_cancel +** +** Description process connect API request. +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_process_api_open_cancel (tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA * p_msg) +{ + UINT16 event = ((BT_HDR *)p_msg)->event; + tBTA_GATTC_CLCB *p_clcb = NULL; + tBTA_GATTC_RCB *p_clreg; + tBTA_GATT_STATUS status = BTA_GATT_ERROR; + + if (p_msg->api_cancel_conn.is_direct) + { + if ((p_clcb = bta_gattc_find_clcb_by_cif(p_msg->api_cancel_conn.client_if, + p_msg->api_cancel_conn.remote_bda)) != NULL) + { + bta_gattc_sm_execute(p_clcb, event, p_msg); + } + else + { + APPL_TRACE_ERROR0("No such connection need to be cancelled"); + + p_clreg = bta_gattc_cl_get_regcb(p_msg->api_cancel_conn.client_if); + + if (p_clreg && p_clreg->p_cback) + { + (*p_clreg->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, (tBTA_GATTC *)&status); + } + } + } + else + { + bta_gattc_cancel_bk_conn(&p_msg->api_cancel_conn); + + } +} + +/******************************************************************************* +** +** Function bta_gattc_cancel_open_error +** +** Description +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_cancel_open_error(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + tBTA_GATT_STATUS status=BTA_GATT_ERROR; + + if ( p_clcb->p_rcb->p_cback ) + (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, (tBTA_GATTC *)&status); +} + +/******************************************************************************* +** +** Function bta_gattc_open_error +** +** Description +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_open_error(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + APPL_TRACE_ERROR0("Connection already opened. wrong state"); + + bta_gattc_send_open_cback(p_clcb->p_rcb, + BTA_GATT_ALREADY_OPEN, + p_clcb->bda, + p_clcb->bta_conn_id); +} +/******************************************************************************* +** +** Function bta_gattc_open_fail +** +** Description +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_open_fail(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + bta_gattc_open_error(p_clcb, p_data); + /* open failure, remove clcb */ + bta_gattc_clcb_dealloc(p_clcb); +} + +/******************************************************************************* +** +** Function bta_gattc_open +** +** Description Process API connection function. +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_open(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + tBTA_GATTC_DATA gattc_data; + + /* open/hold a connection */ + if (!GATT_Connect(p_clcb->p_rcb->client_if, p_data->api_conn.remote_bda, TRUE)) + { + APPL_TRACE_ERROR0("Connection open failure"); + + bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_OPEN_FAIL_EVT, p_data); + } + else + { + /* a connected remote device */ + if (GATT_GetConnIdIfConnected(p_clcb->p_rcb->client_if, + p_data->api_conn.remote_bda, + &p_clcb->bta_conn_id)) + { + gattc_data.hdr.layer_specific = p_clcb->bta_conn_id; + + bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_CONN_EVT, &gattc_data); + } + /* else wait for the callback event */ + } +} +/******************************************************************************* +** +** Function bta_gattc_init_bk_conn +** +** Description Process API Open for a background connection +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_init_bk_conn(tBTA_GATTC_API_OPEN *p_data, tBTA_GATTC_RCB *p_clreg) +{ + tBTA_GATT_STATUS status = BTA_GATT_NO_RESOURCES; + UINT16 conn_id; + tBTA_GATTC_CLCB *p_clcb; + tBTA_GATTC_DATA gattc_data; + + if (bta_gattc_mark_bg_conn(p_data->client_if, p_data->remote_bda, TRUE)) + { + /* alwaya call open to hold a connection */ + if (!GATT_Connect(p_data->client_if, p_data->remote_bda, FALSE)) + { + status = BTA_GATT_ERROR; + APPL_TRACE_ERROR0("bta_gattc_init_bk_conn failed"); + } + else + { + status = BTA_GATT_OK; + + /* if is a connected remote device */ + if (GATT_GetConnIdIfConnected(p_data->client_if, + p_data->remote_bda, + &conn_id)) + { + if ((p_clcb = bta_gattc_clcb_alloc(p_data->client_if, p_data->remote_bda)) != NULL) + { + gattc_data.hdr.layer_specific = p_clcb->bta_conn_id = conn_id; + + /* open connection */ + bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_CONN_EVT, &gattc_data); + status = BTA_GATT_OK; + } + } + } + } + + /* open failure, report OPEN_EVT */ + if (status != BTA_GATT_OK) + { + bta_gattc_send_open_cback(p_clreg, status, p_data->remote_bda, BTA_GATT_INVALID_CONN_ID); + } +} +/******************************************************************************* +** +** Function bta_gattc_cancel_bk_conn +** +** Description Process API Cancel Open for a background connection +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_cancel_bk_conn(tBTA_GATTC_API_CANCEL_OPEN *p_data) +{ + tBTA_GATTC_RCB *p_clreg; + tBTA_GATT_STATUS status = BTA_GATT_ERROR; + + /* remove the device from the bg connection mask */ + if (bta_gattc_mark_bg_conn(p_data->client_if, p_data->remote_bda, FALSE)) + { + if (GATT_CancelConnect(p_data->client_if, p_data->remote_bda, FALSE)) + { + status = BTA_GATT_OK; + } + else + { + APPL_TRACE_ERROR0("bta_gattc_cancel_bk_conn failed"); + } + } + p_clreg = bta_gattc_cl_get_regcb(p_data->client_if); + + if (p_clreg && p_clreg->p_cback) + { + (*p_clreg->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, (tBTA_GATTC *)&status); + } + +} +/******************************************************************************* +** +** Function bta_gattc_int_cancel_open_ok +** +** Description +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_cancel_open_ok(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + tBTA_GATT_STATUS status = BTA_GATT_OK; + + if ( p_clcb->p_rcb->p_cback ) + { + (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, (tBTA_GATTC *)&status); + } + + bta_gattc_clcb_dealloc(p_clcb); +} + +/******************************************************************************* +** +** Function bta_gattc_cancel_open +** +** Description +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_cancel_open(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + tBTA_GATT_STATUS status=BTA_GATT_ERROR; + + if (GATT_CancelConnect(p_clcb->p_rcb->client_if, p_data->api_cancel_conn.remote_bda, TRUE)) + { + bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_CANCEL_OPEN_OK_EVT, p_data); + } + else + { + if ( p_clcb->p_rcb->p_cback ) + { + (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, (tBTA_GATTC *)&status); + } + } +} +/******************************************************************************* +** +** Function bta_gattc_conn +** +** Description receive connection callback from stack +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_conn(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + tBTA_GATTC_IF gatt_if; + APPL_TRACE_DEBUG1("bta_gattc_conn server cache state=%d",p_clcb->p_srcb->state); + + if (p_data != NULL) + { + APPL_TRACE_DEBUG1("bta_gattc_conn conn_id=%d",p_data->hdr.layer_specific); + + p_clcb->p_srcb->connected = TRUE; + p_clcb->bta_conn_id = p_data->hdr.layer_specific; + GATT_GetConnectionInfor(p_data->hdr.layer_specific, &gatt_if, p_clcb->bda); + + /* start database cache if needed */ + if (p_clcb->p_srcb->p_srvc_cache == NULL) + { + if (p_clcb->p_srcb->state == BTA_GATTC_SERV_IDLE) + { + p_clcb->p_srcb->state = BTA_GATTC_SERV_LOAD; + bta_gattc_sm_execute(p_clcb, BTA_GATTC_START_CACHE_EVT, p_data); + } + else /* cache is building */ + p_clcb->state = BTA_GATTC_DISCOVER_ST; + } + + else + { + /* a pending service handle change indication */ + if (p_clcb->p_srcb->srvc_hdl_chg) + { + p_clcb->p_srcb->srvc_hdl_chg = FALSE; + /* start discovery */ + bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_DISCOVER_EVT, NULL); + } + } + + if (p_clcb->p_rcb) + { + bta_gattc_send_open_cback(p_clcb->p_rcb, + BTA_GATT_OK, + p_clcb->bda, + p_clcb->bta_conn_id); + } + } +} + +/******************************************************************************* +** +** Function bta_gattc_close_fail +** +** Description close a connection. +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_close_fail(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + tBTA_GATTC cb_data; + + if ( p_clcb->p_rcb->p_cback ) + { + memset(&cb_data, 0, sizeof(tBTA_GATTC)); + cb_data.close.client_if = p_clcb->p_rcb->client_if; + cb_data.close.conn_id = p_data->hdr.layer_specific; + bdcpy(cb_data.close.remote_bda, p_clcb->bda); + cb_data.close.status = BTA_GATT_ERROR; + cb_data.close.reason = BTA_GATT_CONN_NONE; + + + (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CLOSE_EVT, &cb_data); + } +} +/******************************************************************************* +** +** Function bta_gattc_api_close +** +** Description close a GATTC connection. +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_close(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + tBTA_GATTC_CBACK *p_cback = p_clcb->p_rcb->p_cback; + tBTA_GATTC_RCB *p_clreg = p_clcb->p_rcb; + tBTA_GATTC cb_data; + + APPL_TRACE_DEBUG1("bta_gattc_close conn_id=%d",p_clcb->bta_conn_id); + + if (p_data->hdr.event == BTA_GATTC_API_CLOSE_EVT) + p_clcb->status = GATT_Disconnect(p_clcb->bta_conn_id); + + cb_data.close.client_if = p_clcb->p_rcb->client_if; + cb_data.close.conn_id = p_clcb->bta_conn_id; + cb_data.close.status = p_clcb->status; + cb_data.close.reason = p_clcb->reason; + bdcpy(cb_data.close.remote_bda, p_clcb->bda); + + if (p_clcb->status == BTA_GATT_OK) + { + /* if the srcb is no longer needed, reset the state */ + if ( -- p_clcb->p_srcb->num_clcb == 0) + { + APPL_TRACE_DEBUG0("Update srcb connection status"); + p_clcb->p_srcb->connected = FALSE; + p_clcb->p_srcb->state = BTA_GATTC_SERV_IDLE; + } + + bta_gattc_clcb_dealloc(p_clcb); + } + + ( * p_cback)(BTA_GATTC_CLOSE_EVT, (tBTA_GATTC *)&cb_data); + + if (-- p_clreg->num_clcb == 0 && p_clreg->dereg_pending) + { + bta_gattc_deregister_cmpl(p_clreg, p_clreg->client_if); + } + +} + +/******************************************************************************* +** +** Function bta_gattc_reset_discover_st +** +** Description when a SRCB finished discovery, tell all related clcb. +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_reset_discover_st(tBTA_GATTC_SERV *p_srcb) +{ + tBTA_GATTC_CB *p_cb = &bta_gattc_cb; + UINT8 i; + + for (i = 0; i < BTA_GATTC_CLCB_MAX; i ++) + { + if (p_cb->clcb[i].p_srcb == p_srcb) + { + bta_gattc_sm_execute(&p_cb->clcb[i], BTA_GATTC_DISCOVER_CMPL_EVT, NULL); + } + } +} +/******************************************************************************* +** +** Function bta_gattc_set_discover_st +** +** Description when a SRCB start discovery, tell all related clcb and set +** the state. +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_set_discover_st(tBTA_GATTC_SERV *p_srcb) +{ + tBTA_GATTC_CB *p_cb = &bta_gattc_cb; + UINT8 i; + +#if BLE_INCLUDED == TRUE + L2CA_EnableUpdateBleConnParams(p_srcb->server_bda, FALSE); +#endif + for (i = 0; i < BTA_GATTC_CLCB_MAX; i ++) + { + if (p_cb->clcb[i].p_srcb == p_srcb) + { + p_cb->clcb[i].state = BTA_GATTC_DISCOVER_ST; + } + } +} +/******************************************************************************* +** +** Function bta_gattc_start_discover +** +** Description Start a discovery on server. +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_start_discover(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + /* pending operation, wait until it finishes */ + + APPL_TRACE_DEBUG1("bta_gattc_start_discover conn_id=%d",p_clcb->bta_conn_id); + if (p_clcb->p_q_cmd != NULL && p_clcb->auto_update == BTA_GATTC_NO_SCHEDULE && + p_clcb->p_srcb->state == BTA_GATTC_SERV_IDLE) + { + p_clcb->auto_update = BTA_GATTC_DISC_WAITING; + p_clcb->state = BTA_GATTC_CONN_ST; /* set clcb state */ + } + else /* no pending operation, start discovery right away */ + { + p_clcb->auto_update = BTA_GATTC_NO_SCHEDULE; + + if (p_clcb->p_srcb != NULL) + { + /* clear the service change mask */ + p_clcb->p_srcb->srvc_hdl_chg = FALSE; + p_clcb->p_srcb->update_count = 0; + + /* set all srcb related clcb into discovery ST */ + bta_gattc_set_discover_st(p_clcb->p_srcb); + + if ( bta_gattc_init_cache(p_clcb->p_srcb) || + bta_gattc_discover_pri_service(p_clcb->bta_conn_id, p_clcb->p_srcb, GATT_DISC_SRVC_ALL) != BTA_GATT_OK) + { + APPL_TRACE_ERROR0("discovery on server failed"); + bta_gattc_reset_discover_st(p_clcb->p_srcb); + } + } + else + { + APPL_TRACE_ERROR0("unknown device, can not start discovery"); + } + } +} +/******************************************************************************* +** +** Function bta_gattc_disc_cmpl +** +** Description discovery on server is finished +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_disc_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + tBTA_GATTC_DATA *p_q_cmd = p_clcb->p_q_cmd; + APPL_TRACE_DEBUG1("bta_gattc_disc_cmpl conn_id=%d",p_clcb->bta_conn_id); + +#if BLE_INCLUDED == TRUE + L2CA_EnableUpdateBleConnParams(p_clcb->p_srcb->server_bda, TRUE); +#endif + p_clcb->p_srcb->state = BTA_GATTC_SERV_IDLE; + + /* release pending attribute list buffer */ + utl_freebuf((void **)&p_clcb->p_srcb->p_srvc_list); + + /* get any queued command to proceed */ + if (p_q_cmd != NULL) + { + p_clcb->p_q_cmd = NULL; + + bta_gattc_sm_execute(p_clcb, p_q_cmd->hdr.event, p_q_cmd); + + utl_freebuf((void **)&p_q_cmd); + + } +} +/******************************************************************************* +** +** Function bta_gattc_read +** +** Description Read an attribute +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_read(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + UINT16 handle = 0; + tGATT_READ_PARAM read_param; + tBTA_GATTC_OP_CMPL op_cmpl; + + memset (&read_param, 0 ,sizeof(tGATT_READ_PARAM)); + memset (&op_cmpl, 0 ,sizeof(tBTA_GATTC_OP_CMPL)); + + if (bta_gattc_enqueue(p_clcb, p_data)) + { + if ((handle = bta_gattc_id2handle(p_clcb->p_srcb, + &p_data->api_read.srvc_id, + &p_data->api_read.char_id, + p_data->api_read.descr_type)) == 0) + { + op_cmpl.status = BTA_GATT_ERROR; + } + else + { + read_param.by_handle.handle = handle; + read_param.by_handle.auth_req = p_data->api_read.auth_req; + + op_cmpl.status = GATTC_Read(p_clcb->bta_conn_id, GATT_READ_BY_HANDLE, &read_param); + } + + /* read fail */ + if (op_cmpl.status != BTA_GATT_OK) + { + op_cmpl.op_code = GATTC_OPTYPE_READ; + op_cmpl.p_cmpl = NULL; + + bta_gattc_sm_execute(p_clcb, BTA_GATTC_OP_CMPL_EVT, (tBTA_GATTC_DATA *)&op_cmpl); + } + } +} +/******************************************************************************* +** +** Function bta_gattc_read_multi +** +** Description read multiple +** +** Returns None. +*********************************************************************************/ +void bta_gattc_read_multi(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + UINT16 i, handle; + tBTA_GATT_STATUS status = BTA_GATT_OK; + tGATT_READ_PARAM read_param; + tBTA_GATTC_OP_CMPL op_cmpl; + tBTA_GATTC_ATTR_ID *p_id; + tBT_UUID dummy_uuid; + + if (bta_gattc_enqueue(p_clcb, p_data)) + { + memset(&dummy_uuid, 0, sizeof(tBT_UUID)); + memset(&read_param, 0, sizeof(tGATT_READ_PARAM)); + + p_id = p_data->api_read_multi.p_id_list; + + for (i = 0; i < p_data->api_read_multi.num_attr && p_id; i ++, p_id ++) + { + handle = 0; + + if (p_id->id_type == BTA_GATT_TYPE_CHAR) + { + handle = bta_gattc_id2handle(p_clcb->p_srcb, + &p_id->id_value.char_id.srvc_id, + &p_id->id_value.char_id.char_id, + dummy_uuid); + } + else if (p_id->id_type == BTA_GATT_TYPE_CHAR_DESCR) + { + handle = bta_gattc_id2handle(p_clcb->p_srcb, + &p_id->id_value.char_descr_id.char_id.srvc_id, + &p_id->id_value.char_descr_id.char_id.char_id, + p_id->id_value.char_descr_id.descr_type); + } + else + { + APPL_TRACE_ERROR1("invalud ID type: %d", p_id->id_type); + } + + if (handle == 0) + { + status = BTA_GATT_ERROR; + break; + } + } + if (status == BTA_GATT_OK) + { + read_param.read_multiple.num_handles = p_data->api_read_multi.num_attr; + read_param.read_multiple.auth_req = p_data->api_read_multi.auth_req; + + status = GATTC_Read(p_clcb->bta_conn_id, GATT_READ_MULTIPLE, &read_param); + } + + /* read fail */ + if (status != BTA_GATT_OK) + { + memset(&op_cmpl, 0, sizeof(tBTA_GATTC_OP_CMPL)); + + op_cmpl.status = status; + op_cmpl.op_code = GATTC_OPTYPE_READ; + op_cmpl.p_cmpl = NULL; + + bta_gattc_sm_execute(p_clcb, BTA_GATTC_OP_CMPL_EVT, (tBTA_GATTC_DATA *)&op_cmpl); + } + } +} +/******************************************************************************* +** +** Function bta_gattc_write +** +** Description Write an attribute +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_write(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + UINT16 handle = 0; + tGATT_VALUE attr = {0}; + tBTA_GATTC_OP_CMPL op_cmpl; + tBTA_GATT_STATUS status = BTA_GATT_OK; + + if (bta_gattc_enqueue(p_clcb, p_data)) + { + if ((handle = bta_gattc_id2handle(p_clcb->p_srcb, + &p_data->api_write.srvc_id, + &p_data->api_write.char_id, + p_data->api_write.descr_type)) == 0) + { + status = BTA_GATT_ERROR; + } + else + { + attr.handle= handle; + attr.offset = p_data->api_write.offset; + attr.len = p_data->api_write.len; + attr.auth_req = p_data->api_write.auth_req; + + if (p_data->api_write.p_value) + memcpy(attr.value, p_data->api_write.p_value, p_data->api_write.len); + + status = GATTC_Write(p_clcb->bta_conn_id, p_data->api_write.write_type, &attr); + } + + /* write fail */ + if (status != BTA_GATT_OK) + { + memset(&op_cmpl, 0, sizeof(tBTA_GATTC_OP_CMPL)); + + op_cmpl.status = status; + op_cmpl.op_code = GATTC_OPTYPE_WRITE; + op_cmpl.p_cmpl = NULL; + + bta_gattc_sm_execute(p_clcb, BTA_GATTC_OP_CMPL_EVT, (tBTA_GATTC_DATA *)&op_cmpl); + } + } +} +/******************************************************************************* +** +** Function bta_gattc_execute +** +** Description send execute write +** +** Returns None. +*********************************************************************************/ +void bta_gattc_execute(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + tBTA_GATTC_OP_CMPL op_cmpl; + tBTA_GATT_STATUS status; + + if (bta_gattc_enqueue(p_clcb, p_data)) + { + status = GATTC_ExecuteWrite(p_clcb->bta_conn_id, p_data->api_exec.is_execute); + + if (status != BTA_GATT_OK) + { + memset(&op_cmpl, 0, sizeof(tBTA_GATTC_OP_CMPL)); + + op_cmpl.status = status; + op_cmpl.op_code = GATTC_OPTYPE_EXE_WRITE; + op_cmpl.p_cmpl = NULL; + + bta_gattc_sm_execute(p_clcb, BTA_GATTC_OP_CMPL_EVT, (tBTA_GATTC_DATA *)&op_cmpl); + } + } +} + +/******************************************************************************* +** +** Function bta_gattc_confirm +** +** Description send handle value confirmation +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_confirm(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + UINT16 handle; + tBT_UUID null_uuid = {0}; + + if ((handle = bta_gattc_id2handle(p_clcb->p_srcb, + &p_data->api_confirm.srvc_id, + &p_data->api_confirm.char_id, + null_uuid)) == 0) + { + APPL_TRACE_ERROR0("Can not map service/char ID into valid handle"); + } + else + { + if (GATTC_SendHandleValueConfirm(p_data->api_confirm.hdr.layer_specific, handle) + != GATT_SUCCESS) + { + APPL_TRACE_ERROR1("bta_gattc_confirm to handle [0x%04x] failed", handle); + } + } +} +/******************************************************************************* +** +** Function bta_gattc_read_cmpl +** +** Description read complete +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_read_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_OP_CMPL *p_data) +{ + UINT8 event; + tBTA_GATTC cb_data; + tBTA_GATT_READ_VAL read_value; + + memset(&cb_data, 0, sizeof(tBTA_GATTC)); + memset(&read_value, 0, sizeof(tBTA_GATT_READ_VAL)); + + cb_data.read.status = p_data->status; + + if (p_data->p_cmpl != NULL && p_data->status == BTA_GATT_OK) + { + if (bta_gattc_handle2id(p_clcb->p_srcb, + p_data->p_cmpl->att_value.handle, + &cb_data.read.srvc_id, + &cb_data.read.char_id, + &cb_data.read.descr_type) == FALSE) + { + cb_data.read.status = BTA_GATT_INTERNAL_ERROR; + APPL_TRACE_ERROR1("can not map to GATT ID. handle = 0x%04x", p_data->p_cmpl->att_value.handle); + } + else + { + cb_data.read.status = bta_gattc_pack_read_cb_data(p_clcb->p_srcb, + cb_data.read.descr_type, + &p_data->p_cmpl->att_value, + &read_value); + cb_data.read.p_value = &read_value; + } + } + else + { + cb_data.read.srvc_id = p_clcb->p_q_cmd->api_read.srvc_id; + cb_data.read.char_id = p_clcb->p_q_cmd->api_read.char_id; + cb_data.read.descr_type = p_clcb->p_q_cmd->api_read.descr_type; + } + + event = (p_clcb->p_q_cmd->api_read.descr_type.len == 0) ? BTA_GATTC_READ_CHAR_EVT: BTA_GATTC_READ_DESCR_EVT; + cb_data.read.conn_id = p_clcb->bta_conn_id; + + utl_freebuf((void **)&p_clcb->p_q_cmd); + /* read complete, callback */ + ( *p_clcb->p_rcb->p_cback)(event, (tBTA_GATTC *)&cb_data); + +} +/******************************************************************************* +** +** Function bta_gattc_write_cmpl +** +** Description read complete +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_write_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_OP_CMPL *p_data) +{ + tBTA_GATTC cb_data = {0}; + UINT8 event; + + cb_data.write.status = p_data->status; + + if (p_data->p_cmpl != NULL) + { + bta_gattc_handle2id(p_clcb->p_srcb, p_data->p_cmpl->handle, + &cb_data.write.srvc_id, &cb_data.write.char_id, + &cb_data.write.descr_type); + } + else + { + cb_data.write.srvc_id = p_clcb->p_q_cmd->api_write.srvc_id; + cb_data.write.char_id = p_clcb->p_q_cmd->api_write.char_id; + cb_data.write.descr_type = p_clcb->p_q_cmd->api_write.descr_type; + } + + if (p_clcb->p_q_cmd->api_write.hdr.event == BTA_GATTC_API_WRITE_EVT && + p_clcb->p_q_cmd->api_write.write_type == BTA_GATTC_WRITE_PREPARE) + + event = BTA_GATTC_PREP_WRITE_EVT; + + else if (p_clcb->p_q_cmd->api_write.descr_type.len == 0) + + event = BTA_GATTC_WRITE_CHAR_EVT; + + else + event = BTA_GATTC_WRITE_DESCR_EVT; + + utl_freebuf((void **)&p_clcb->p_q_cmd); + cb_data.write.conn_id = p_clcb->bta_conn_id; + /* write complete, callback */ + ( *p_clcb->p_rcb->p_cback)(event, (tBTA_GATTC *)&cb_data); + +} +/******************************************************************************* +** +** Function bta_gattc_exec_cmpl +** +** Description execute write complete +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_exec_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_OP_CMPL *p_data) +{ + tBTA_GATTC cb_data; + + utl_freebuf((void **)&p_clcb->p_q_cmd); + + p_clcb->status = BTA_GATT_OK; + + /* execute complete, callback */ + cb_data.exec_cmpl.conn_id = p_clcb->bta_conn_id; + cb_data.exec_cmpl.status = p_data->status; + + ( *p_clcb->p_rcb->p_cback)(BTA_GATTC_EXEC_EVT, &cb_data); + +} + + +/******************************************************************************* +** +** Function bta_gattc_op_cmpl +** +** Description operation completed. +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_op_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + UINT8 op = (UINT8)p_data->op_cmpl.op_code; + UINT8 mapped_op = 0; + + APPL_TRACE_DEBUG1("bta_gattc_op_cmpl op = %d", op); + + if (op == GATTC_OPTYPE_INDICATION || op == GATTC_OPTYPE_NOTIFICATION) + { + APPL_TRACE_ERROR0("unexpected operation, ignored"); + } + else if (op >= GATTC_OPTYPE_READ) + { + if (p_clcb->p_q_cmd == NULL) + { + APPL_TRACE_ERROR0("No pending command"); + return; + } + if (p_clcb->p_q_cmd->hdr.event != bta_gattc_opcode_to_int_evt[op - GATTC_OPTYPE_READ]) + { + mapped_op = p_clcb->p_q_cmd->hdr.event - BTA_GATTC_API_READ_EVT + GATTC_OPTYPE_READ; + if ( mapped_op > GATTC_OPTYPE_INDICATION) mapped_op = 0; + +#if (BT_TRACE_VERBOSE == TRUE) + APPL_TRACE_ERROR3("expect op:(%s :0x%04x), receive unexpected operation (%s).", + bta_gattc_op_code_name[mapped_op] , p_clcb->p_q_cmd->hdr.event, + bta_gattc_op_code_name[op]); +#else + APPL_TRACE_ERROR3("expect op:(%u :0x%04x), receive unexpected operation (%u).", + mapped_op , p_clcb->p_q_cmd->hdr.event, op); +#endif + return; + } + + /* service handle change void the response, discard it */ + if (p_clcb->auto_update == BTA_GATTC_DISC_WAITING) + { + p_clcb->auto_update = BTA_GATTC_REQ_WAITING; + bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_DISCOVER_EVT, NULL); + } + else if (op == GATTC_OPTYPE_READ) + bta_gattc_read_cmpl(p_clcb, &p_data->op_cmpl); + + else if (op == GATTC_OPTYPE_WRITE) + bta_gattc_write_cmpl(p_clcb, &p_data->op_cmpl); + + else if (op == GATTC_OPTYPE_EXE_WRITE) + bta_gattc_exec_cmpl(p_clcb, &p_data->op_cmpl); + /* + else if (op == GATTC_OPTYPE_CONFIG) // API to be added + { + } + */ + } +} +/******************************************************************************* +** +** Function bta_gattc_op_cmpl +** +** Description operation completed. +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_ignore_op_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + /* receive op complete when discovery is started, ignore the response, + and wait for discovery finish and resent */ + APPL_TRACE_DEBUG1("bta_gattc_ignore_op_cmpl op = %d", p_data->hdr.layer_specific); + +} +/******************************************************************************* +** +** Function bta_gattc_search +** +** Description start a search in the local server cache +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_search(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + tBTA_GATT_STATUS status = GATT_INTERNAL_ERROR; + tBTA_GATTC cb_data; + APPL_TRACE_DEBUG1("bta_gattc_search conn_id=%d",p_clcb->bta_conn_id); + if (p_clcb->p_srcb && p_clcb->p_srcb->p_srvc_cache) + { + status = BTA_GATT_OK; + /* search the local cache of a server device */ + bta_gattc_search_service(p_clcb, p_data->api_search.srvc_uuid); + } + cb_data.search_cmpl.status = status; + cb_data.search_cmpl.conn_id = p_clcb->bta_conn_id; + + /* end of search or no server cache available */ + ( *p_clcb->p_rcb->p_cback)(BTA_GATTC_SEARCH_CMPL_EVT, &cb_data); +} +/******************************************************************************* +** +** Function bta_gattc_q_cmd +** +** Description enqueue a command into control block, usually because discovery +** operation is busy. +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_q_cmd(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + bta_gattc_enqueue(p_clcb, p_data); +} +/******************************************************************************* +** +** Function bta_gattc_cache_open +** +** Description open a NV cache for loading +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_cache_open(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + bta_gattc_set_discover_st(p_clcb->p_srcb); + + APPL_TRACE_DEBUG1("bta_gattc_cache_open conn_id=%d",p_clcb->bta_conn_id); + bta_gattc_co_cache_open(p_clcb->p_srcb->server_bda, BTA_GATTC_CI_CACHE_OPEN_EVT, + p_clcb->bta_conn_id, FALSE); +} +/******************************************************************************* +** +** Function bta_gattc_start_load +** +** Description start cache loading by sending callout open cache +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_ci_open(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + APPL_TRACE_DEBUG2("bta_gattc_ci_open conn_id=%d server state=%d" , + p_clcb->bta_conn_id, p_clcb->p_srcb->state); + if (p_clcb->p_srcb->state == BTA_GATTC_SERV_LOAD) + { + if (p_data->ci_open.status == BTA_GATT_OK) + { + p_clcb->p_srcb->attr_index = 0; + bta_gattc_co_cache_load(p_clcb->p_srcb->server_bda, + BTA_GATTC_CI_CACHE_LOAD_EVT, + p_clcb->p_srcb->attr_index, + p_clcb->bta_conn_id); + } + else + { + /* cache open failure, start discovery */ + bta_gattc_start_discover(p_clcb, NULL); + } + } + if (p_clcb->p_srcb->state == BTA_GATTC_SERV_SAVE) + { + if (p_data->ci_open.status == BTA_GATT_OK) + { + if (!bta_gattc_cache_save(p_clcb->p_srcb, p_clcb->bta_conn_id)) + { + p_data->ci_open.status = BTA_GATT_ERROR; + } + } + if (p_data->ci_open.status != BTA_GATT_OK) + { + p_clcb->p_srcb->attr_index = 0; + bta_gattc_co_cache_close(p_clcb->p_srcb->server_bda, p_clcb->bta_conn_id); + bta_gattc_reset_discover_st(p_clcb->p_srcb); + + } + } +} +/******************************************************************************* +** +** Function bta_gattc_ci_load +** +** Description cache loading received. +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_ci_load(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + + APPL_TRACE_DEBUG2("bta_gattc_ci_load conn_id=%d load status=%d" , + p_clcb->bta_conn_id, p_data->ci_load.status ); + bta_gattc_co_cache_close(p_clcb->p_srcb->server_bda, 0); + + if ((p_data->ci_load.status == BTA_GATT_OK || + p_data->ci_load.status == BTA_GATT_MORE) && + p_data->ci_load.num_attr > 0) + { + bta_gattc_rebuild_cache(p_clcb->p_srcb, p_data->ci_load.num_attr, p_data->ci_load.attr, p_clcb->p_srcb->attr_index); + + if (p_data->ci_load.status == BTA_GATT_OK) + { + p_clcb->p_srcb->attr_index = 0; + bta_gattc_reset_discover_st(p_clcb->p_srcb); + + } + else /* load more */ + { + p_clcb->p_srcb->attr_index += p_data->ci_load.num_attr; + + bta_gattc_co_cache_load(p_clcb->p_srcb->server_bda, + BTA_GATTC_CI_CACHE_LOAD_EVT, + p_clcb->p_srcb->attr_index, + p_clcb->bta_conn_id); + } + } + else + { + p_clcb->p_srcb->attr_index = 0; + /* cache open failure, start discovery */ + bta_gattc_start_discover(p_clcb, NULL); + } +} +/******************************************************************************* +** +** Function bta_gattc_ci_load +** +** Description cache loading received. +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_ci_save(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + APPL_TRACE_DEBUG1("bta_gattc_ci_save conn_id=%d " , + p_clcb->bta_conn_id ); + + if (!bta_gattc_cache_save(p_clcb->p_srcb, p_clcb->bta_conn_id)) + { + p_clcb->p_srcb->attr_index = 0; + bta_gattc_co_cache_close(p_clcb->p_srcb->server_bda, 0); + bta_gattc_reset_discover_st(p_clcb->p_srcb); + } +} + +/******************************************************************************* +** +** Function bta_gattc_fail +** +** Description report API call failure back to apps +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_fail(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + if (p_clcb->status == BTA_GATT_OK) + { + APPL_TRACE_ERROR1("operation not supported at current state [%d]", p_clcb->state); + } +} +/******************************************************************************* +** +** Function bta_gattc_conn_cback +** bta_gattc_cmpl_cback +** +** Description callback functions to GATT client stack. +** +** Returns void +** +*******************************************************************************/ +static void bta_gattc_conn_cback(tGATT_IF gattc_if, BD_ADDR bda, UINT16 conn_id, + BOOLEAN connected, tGATT_DISCONN_REASON reason) +{ + BT_HDR *p_buf; + tBTA_GATTC_CLCB *p_clcb = NULL; + + APPL_TRACE_DEBUG4("bta_gattc_conn_cback: cif = %d connected = %d conn_id = %d reaosn = 0x%04x", + gattc_if, connected, conn_id, reason); + + if (connected) + { + /* outgoing connection : locate a logic channel */ + if ((p_clcb = bta_gattc_find_clcb_by_cif(gattc_if, bda)) == NULL) + { + +#if BLE_INCLUDED == TRUE + /* for a background connection */ + if (L2CA_GetBleConnRole(bda)== HCI_ROLE_MASTER && + bta_gattc_check_bg_conn(gattc_if, bda)) + { + /* allocate a new channel */ + p_clcb = bta_gattc_clcb_alloc(gattc_if, bda); + } +#endif + } + if (p_clcb != NULL) + { + p_clcb->bta_conn_id = conn_id; + + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = BTA_GATTC_INT_CONN_EVT; + p_buf->layer_specific = conn_id; + + bta_sys_sendmsg(p_buf); + } + } + } + else + { + /* connection attempt timeout, send connection callback event */ + if (reason == GATT_CONN_CANCEL ) + { + p_clcb = bta_gattc_clcb_alloc(gattc_if, bda); + p_clcb->bta_conn_id = conn_id; + } + if ((p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id)) != NULL) + { + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = BTA_GATTC_INT_DISCONN_EVT; + p_buf->layer_specific = conn_id; + p_clcb->reason = reason; + + bta_sys_sendmsg(p_buf); + } + } + else + { + APPL_TRACE_DEBUG1(" connection ID: [%d] not used by BTA", conn_id); + } + } +} +/******************************************************************************* +** +** Function bta_gattc_process_srvc_chg_ind +** +** Description process service change indication. +** +** Returns None. +** +*******************************************************************************/ +BOOLEAN bta_gattc_process_srvc_chg_ind(UINT16 conn_id, + tBTA_GATTC_RCB *p_clrcb, + tBTA_GATTC_SERV *p_srcb, + tBTA_GATTC_CLCB *p_clcb, + tBTA_GATTC_NOTIFY *p_notify, + UINT16 handle) +{ + tBT_UUID gattp_uuid, srvc_chg_uuid; + BOOLEAN processed = FALSE; + UINT8 i; + + gattp_uuid.len = 2; + gattp_uuid.uu.uuid16 = UUID_SERVCLASS_GATT_SERVER; + + srvc_chg_uuid.len = 2; + srvc_chg_uuid.uu.uuid16 = GATT_UUID_GATT_SRV_CHGD; + + if (bta_gattc_uuid_compare(p_notify->char_id.srvc_id.id.uuid, gattp_uuid, TRUE) && + bta_gattc_uuid_compare(p_notify->char_id.char_id.uuid, srvc_chg_uuid, TRUE)) + { + processed = TRUE; + /* mark service handle change pending */ + p_srcb->srvc_hdl_chg = TRUE; + /* clear up all notification/indication registration */ + bta_gattc_clear_notif_registration(conn_id); + /* service change indication all received, do discovery update */ + if ( ++ p_srcb->update_count == bta_gattc_num_reg_app()) + { + /* not an opened connection; or connection busy */ + /* search for first available clcb and start discovery */ + if (p_clcb == NULL || (p_clcb && p_clcb->p_q_cmd != NULL)) + { + for (i = 0 ; i < BTA_GATTC_CLCB_MAX; i ++) + { + if (bta_gattc_cb.clcb[i].in_use && + bta_gattc_cb.clcb[i].p_srcb == p_srcb && + bta_gattc_cb.clcb[i].p_q_cmd == NULL) + { + p_clcb = &bta_gattc_cb.clcb[i]; + break; + } + } + } + /* send confirmation here if this is an indication, it should always be */ + GATTC_SendHandleValueConfirm(conn_id, handle); + + /* if connection available, refresh cache by doing discovery now */ + if (p_clcb != NULL) + bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_DISCOVER_EVT, NULL); + } + /* notify applicationf or service change */ + if (p_clrcb->p_cback != NULL) + { + APPL_TRACE_ERROR0("bta_gattc_process_srvc_chg_ind 2"); + (* p_clrcb->p_cback)(BTA_GATTC_SRVC_CHG_EVT, (tBTA_GATTC *)p_srcb->server_bda); + } + + } + + return processed; + +} +/******************************************************************************* +** +** Function bta_gattc_proc_other_indication +** +** Description process all non-service change indication/notification. +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_proc_other_indication(tBTA_GATTC_CLCB *p_clcb, UINT8 op, + tGATT_CL_COMPLETE *p_data, + tBTA_GATTC_NOTIFY *p_notify) +{ + APPL_TRACE_DEBUG2("bta_gattc_proc_other_indication check \ + p_data->att_value.handle=%d p_data->handle=%d", + p_data->att_value.handle, p_data->handle); + APPL_TRACE_DEBUG1("is_notify", p_notify->is_notify); + + p_notify->is_notify = (op == GATTC_OPTYPE_INDICATION) ? FALSE : TRUE; + p_notify->len = p_data->att_value.len; + bdcpy(p_notify->bda, p_clcb->bda); + memcpy(p_notify->value, p_data->att_value.value, p_data->att_value.len); + p_notify->conn_id = p_clcb->bta_conn_id; + + if (p_clcb->p_rcb->p_cback) + (*p_clcb->p_rcb->p_cback)(BTA_GATTC_NOTIF_EVT, (tBTA_GATTC *)p_notify); + +} +/******************************************************************************* +** +** Function bta_gattc_process_indicate +** +** Description process indication/notification. +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_process_indicate(UINT16 conn_id, tGATTC_OPTYPE op, tGATT_CL_COMPLETE *p_data) +{ + UINT16 handle = p_data->att_value.handle; + tBTA_GATTC_CLCB *p_clcb ; + tBTA_GATTC_RCB *p_clrcb = NULL; + tBTA_GATTC_SERV *p_srcb = NULL; + tBTA_GATTC_NOTIFY notify; + BD_ADDR remote_bda; + tBTA_GATTC_IF gatt_if; + + if (!GATT_GetConnectionInfor(conn_id, &gatt_if, remote_bda)) + { + APPL_TRACE_ERROR0("indication/notif for unknown app"); + return; + } + + if ((p_clrcb = bta_gattc_cl_get_regcb(gatt_if)) == NULL) + { + APPL_TRACE_ERROR0("indication/notif for unregistered app"); + return; + } + + if ((p_srcb = bta_gattc_find_srcb(remote_bda)) == NULL) + { + APPL_TRACE_ERROR0("indication/notif for unknown device, ignore"); + return; + } + + p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id); + + if (bta_gattc_handle2id(p_srcb, handle, + ¬ify.char_id.srvc_id, + ¬ify.char_id.char_id, + ¬ify.descr_type)) + { + /* if non-service change indication/notification, forward to application */ + if (!bta_gattc_process_srvc_chg_ind(conn_id, p_clrcb, p_srcb, p_clcb, ¬ify, handle)) + { + /* if app registered for the notification */ + if (bta_gattc_check_notif_registry(p_clrcb, p_srcb, ¬ify)) + { + /* connection not open yet */ + if (p_clcb == NULL) + { + if ((p_clcb = bta_gattc_clcb_alloc(gatt_if, remote_bda)) != NULL) + { + p_clcb->bta_conn_id = conn_id; + + /* send connection event */ + bta_gattc_send_open_cback(p_clrcb, + BTA_GATT_OK, + remote_bda, + conn_id); + } + else + { + APPL_TRACE_ERROR0("No resources"); + } + } + + if (p_clcb != NULL) + bta_gattc_proc_other_indication(p_clcb, op, p_data, ¬ify); + } + /* no one intersted and need ack? */ + else if (op == GATTC_OPTYPE_INDICATION) + { + APPL_TRACE_DEBUG0("no one interested, ack now"); + GATTC_SendHandleValueConfirm(conn_id, handle); + } + } + } + else + { + APPL_TRACE_ERROR1("Indi/Notif for Unknown handle[0x%04x], can not find in local cache.", handle); + } +} + +/******************************************************************************* +** +** Function bta_gattc_cmpl_cback +** +** Description client operation complete callback register with BTE GATT. +** +** Returns None. +** +*******************************************************************************/ +static void bta_gattc_cmpl_cback(UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, + tGATT_CL_COMPLETE *p_data) +{ + tBTA_GATTC_CLCB *p_clcb ; + tBTA_GATTC_OP_CMPL *p_buf; + UINT16 len = sizeof(tBTA_GATTC_OP_CMPL) + sizeof(tGATT_CL_COMPLETE); + + APPL_TRACE_DEBUG3("bta_gattc_cmpl_cback: conn_id = %d op = %d status = %d", + conn_id, op, status); + + /* notification and indication processed right away */ + if (op == GATTC_OPTYPE_NOTIFICATION || op == GATTC_OPTYPE_INDICATION) + { + bta_gattc_process_indicate(conn_id, op, p_data); + return; + } + /* for all other operation, not expected if w/o connection */ + else if ((p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id)) == NULL) + { + APPL_TRACE_ERROR1("bta_gattc_cmpl_cback unknown conn_id = %d, ignore data", conn_id); + return; + } + + + if ((p_buf = (tBTA_GATTC_OP_CMPL *) GKI_getbuf(len)) != NULL) + { + memset(p_buf, 0, len); + p_buf->hdr.event = BTA_GATTC_OP_CMPL_EVT; + p_buf->hdr.layer_specific = conn_id; + p_buf->status = status; + p_buf->op_code = op; + + if (p_data != NULL) + { + p_buf->p_cmpl = (tGATT_CL_COMPLETE *)(p_buf + 1); + memcpy(p_buf->p_cmpl, p_data, sizeof(tGATT_CL_COMPLETE)); + } + + bta_sys_sendmsg(p_buf); + } + + return; +} +#endif /* BTA_GATT_INCLUDED */ diff --git a/bta/gatt/bta_gattc_api.c b/bta/gatt/bta_gattc_api.c new file mode 100644 index 0000000..4a87ddf --- /dev/null +++ b/bta/gatt/bta_gattc_api.c @@ -0,0 +1,922 @@ +/***************************************************************************** +** +** Name: bta_gattc_api.c +** +** Description: This is the implementation of the API for GATT module +** of BTA. +** +** Copyright (c) 2010-2011, Broadcom Corp., All Rights Reserved. +** Broadcom Bluetooth Core. Proprietary and confidential. +** +*****************************************************************************/ + +#include "bt_target.h" + +#if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE) + +#include <string.h> +#include "gki.h" +#include "bta_sys.h" +#include "bta_gatt_api.h" +#include "bta_gattc_int.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ + +static const tBTA_SYS_REG bta_gatt_reg = +{ + bta_gattc_hdl_event, + NULL /* need a disable functino to be called when BT is disabled */ +}; + +/******************************************************************************* +** +** Function BTA_GATTC_AppRegister +** +** Description This function is called to register application callbacks +** with BTA GATTC module. +** +** Parameters p_app_uuid - applicaiton UUID +** p_client_cb - pointer to the application callback function. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTC_AppRegister(tBT_UUID *p_app_uuid, tBTA_GATTC_CBACK *p_client_cb) +{ + tBTA_GATTC_API_REG *p_buf; + + /* register with BTA system manager */ + GKI_sched_lock(); + bta_sys_register(BTA_ID_GATTC, &bta_gatt_reg); + GKI_sched_unlock(); + + if ((p_buf = (tBTA_GATTC_API_REG *) GKI_getbuf(sizeof(tBTA_GATTC_API_REG))) != NULL) + { + p_buf->hdr.event = BTA_GATTC_API_REG_EVT; + if (p_app_uuid != NULL) + memcpy(&p_buf->app_uuid, p_app_uuid, sizeof(tBT_UUID)); + p_buf->p_cback = p_client_cb; + + bta_sys_sendmsg(p_buf); + } + return; +} + +/******************************************************************************* +** +** Function BTA_GATTC_AppDeregister +** +** Description This function is called to deregister an application +** from BTA GATTC module. +** +** Parameters client_if - client interface identifier. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTC_AppDeregister(tBTA_GATTC_IF client_if) +{ + tBTA_GATTC_API_DEREG *p_buf; + + if ((p_buf = (tBTA_GATTC_API_DEREG *) GKI_getbuf(sizeof(tBTA_GATTC_API_DEREG))) != NULL) + { + p_buf->hdr.event = BTA_GATTC_API_DEREG_EVT; + p_buf->client_if = client_if; + bta_sys_sendmsg(p_buf); + } + return; +} + +/******************************************************************************* +** +** Function BTA_GATTC_Open +** +** Description Open a direct connection or add a background auto connection +** bd address +** +** Parameters client_if: server interface. +** remote_bda: remote device BD address. +** is_direct: direct connection or background auto connection +** +** Returns void +** +*******************************************************************************/ +void BTA_GATTC_Open(tBTA_GATTC_IF client_if, BD_ADDR remote_bda, BOOLEAN is_direct) +{ + tBTA_GATTC_API_OPEN *p_buf; + + if ((p_buf = (tBTA_GATTC_API_OPEN *) GKI_getbuf(sizeof(tBTA_GATTC_API_OPEN))) != NULL) + { + p_buf->hdr.event = BTA_GATTC_API_OPEN_EVT; + + p_buf->client_if = client_if; + p_buf->is_direct = is_direct; + memcpy(p_buf->remote_bda, remote_bda, BD_ADDR_LEN); + + + bta_sys_sendmsg(p_buf); + } + return; +} + +/******************************************************************************* +** +** Function BTA_GATTC_CancelOpen +** +** Description Cancel a direct open connection or remove a background auto connection +** bd address +** +** Parameters client_if: server interface. +** remote_bda: remote device BD address. +** is_direct: direct connection or background auto connection +** +** Returns void +** +*******************************************************************************/ +void BTA_GATTC_CancelOpen(tBTA_GATTC_IF client_if, BD_ADDR remote_bda, BOOLEAN is_direct) +{ + tBTA_GATTC_API_CANCEL_OPEN *p_buf; + + if ((p_buf = (tBTA_GATTC_API_CANCEL_OPEN *) GKI_getbuf(sizeof(tBTA_GATTC_API_CANCEL_OPEN))) != NULL) + { + p_buf->hdr.event = BTA_GATTC_API_CANCEL_OPEN_EVT; + + p_buf->client_if = client_if; + p_buf->is_direct = is_direct; + memcpy(p_buf->remote_bda, remote_bda, BD_ADDR_LEN); + + bta_sys_sendmsg(p_buf); + } + return; +} + +/******************************************************************************* +** +** Function BTA_GATTC_Close +** +** Description Close a connection to a GATT server. +** +** Parameters conn_id: connectino ID to be closed. +** +** Returns void +** +*******************************************************************************/ +void BTA_GATTC_Close(UINT16 conn_id) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = BTA_GATTC_API_CLOSE_EVT; + + p_buf->layer_specific = conn_id; + + bta_sys_sendmsg(p_buf); + } + return; + +} +/******************************************************************************* +** +** Function BTA_GATTC_ServiceSearchRequest +** +** Description This function is called to request a GATT service discovery +** on a GATT server. This function report service search result +** by a callback event, and followed by a service search complete +** event. +** +** Parameters conn_id: connection ID. +** p_srvc_uuid: a UUID of the service application is interested in. +** If Null, discover for all services. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTC_ServiceSearchRequest (UINT16 conn_id, tBT_UUID *p_srvc_uuid) +{ + tBTA_GATTC_API_SEARCH *p_buf; + UINT16 len = sizeof(tBTA_GATTC_API_SEARCH) + sizeof(tBT_UUID); + + if ((p_buf = (tBTA_GATTC_API_SEARCH *) GKI_getbuf(len)) != NULL) + { + memset(p_buf, 0, len); + + p_buf->hdr.event = BTA_GATTC_API_SEARCH_EVT; + p_buf->hdr.layer_specific = conn_id; + + if (p_srvc_uuid) + { + memcpy(&p_buf->srvc_uuid, p_srvc_uuid, sizeof(tBT_UUID)); + } + bta_sys_sendmsg(p_buf); + } + return; +} + + +/******************************************************************************* +** +** Function BTA_GATTC_GetFirstChar +** +** Description This function is called to find the first charatceristic of the +** service on the given server. +** +** Parameters conn_id: connection ID which identify the server. +** p_srvc_id: the service ID of which the characteristic is belonged to. +** p_char_uuid_cond: Characteristic UUID, if NULL find the first available +** characteristic. +** p_char_result: output parameter which will store the GATT +** characteristic ID. +** p_property: output parameter to carry the characteristic property. +** +** Returns returns status. +** +*******************************************************************************/ +tBTA_GATT_STATUS BTA_GATTC_GetFirstChar (UINT16 conn_id, tBTA_GATT_SRVC_ID *p_srvc_id, + tBT_UUID *p_char_uuid_cond, + tBTA_GATTC_CHAR_ID *p_char_result, + tBTA_GATT_CHAR_PROP *p_property) +{ + tBTA_GATT_STATUS status; + + if (!p_srvc_id || !p_char_result) + return BTA_GATT_ILLEGAL_PARAMETER; + + if ((status = bta_gattc_query_cache(conn_id, BTA_GATTC_ATTR_TYPE_CHAR, p_srvc_id, NULL, + p_char_uuid_cond, &p_char_result->char_id, p_property)) + == BTA_GATT_OK) + { + memcpy(&p_char_result->srvc_id, p_srvc_id, sizeof(tBTA_GATT_SRVC_ID)); + } + + return status; + +} +/******************************************************************************* +** +** Function BTA_GATTC_GetNextChar +** +** Description This function is called to find the next charatceristic of the +** service on the given server. +** +** Parameters conn_id: connection ID which identify the server. +** p_start_char_id: start the characteristic search from the next record +** after the one identified by char_id. +** p_char_uuid_cond: Characteristic UUID, if NULL find the first available +** characteristic. +** p_char_result: output parameter which will store the GATT +** characteristic ID. +** p_property: output parameter to carry the characteristic property. +** +** Returns returns status. +** +*******************************************************************************/ +tBTA_GATT_STATUS BTA_GATTC_GetNextChar (UINT16 conn_id, + tBTA_GATTC_CHAR_ID *p_start_char_id, + tBT_UUID *p_char_uuid_cond, + tBTA_GATTC_CHAR_ID *p_char_result, + tBTA_GATT_CHAR_PROP *p_property) +{ + tBTA_GATT_STATUS status; + + if (!p_start_char_id || !p_char_result) + return BTA_GATT_ILLEGAL_PARAMETER; + + if ((status = bta_gattc_query_cache(conn_id, BTA_GATTC_ATTR_TYPE_CHAR, + &p_start_char_id->srvc_id, + &p_start_char_id->char_id, + p_char_uuid_cond, + &p_char_result->char_id, + p_property)) + == BTA_GATT_OK) + { + memcpy(&p_char_result->srvc_id, &p_start_char_id->srvc_id, sizeof(tBTA_GATT_SRVC_ID)); + } + + return status; +} + +/******************************************************************************* +** +** Function BTA_GATTC_GetFirstCharDescr +** +** Description This function is called to find the first charatceristic descriptor of the +** charatceristic on the given server. +** +** Parameters conn_id: connection ID which identify the server. +** p_char_id: the characteristic ID of which the descriptor is belonged to. +** p_descr_uuid_cond: Characteristic Descr UUID, if NULL find the first available +** characteristic. +** p_descr_result: output parameter which will store the GATT +** characteristic descriptor ID. +** +** Returns returns status. +** +*******************************************************************************/ +tBTA_GATT_STATUS BTA_GATTC_GetFirstCharDescr (UINT16 conn_id, tBTA_GATTC_CHAR_ID *p_char_id, + tBT_UUID *p_descr_uuid_cond, + tBTA_GATTC_CHAR_DESCR_ID *p_descr_result) +{ + tBTA_GATT_STATUS status; + + if (!p_char_id || !p_descr_result) + return BTA_GATT_ILLEGAL_PARAMETER; + + memset(p_descr_result, 0, sizeof(tBTA_GATTC_CHAR_DESCR_ID)); + + if ((status = bta_gattc_query_cache(conn_id, + BTA_GATTC_ATTR_TYPE_CHAR_DESCR, + &p_char_id->srvc_id, + &p_char_id->char_id, + p_descr_uuid_cond, + &p_descr_result->char_id.char_id, + NULL)) + == BTA_GATT_OK) + { + memcpy(&p_descr_result->descr_type, &p_descr_result->char_id.char_id.uuid, sizeof(tBT_UUID)); + memcpy(&p_descr_result->char_id, p_char_id, sizeof(tBTA_GATTC_CHAR_ID)); + } + + return status; + +} +/******************************************************************************* +** +** Function BTA_GATTC_GetNextCharDescr +** +** Description This function is called to find the next charatceristic of the +** service on the given server. +** +** Parameters conn_id: connection ID which identify the server. +** p_start_descr_id: start the characteristic search from the next record +** after the one identified by p_start_descr_id. +** p_descr_uuid_cond: Characteristic descriptor UUID, if NULL find +** the first available characteristic descriptor. +** p_descr_result: output parameter which will store the GATT +** characteristic descriptor ID. +** +** Returns returns status. +** +*******************************************************************************/ +tBTA_GATT_STATUS BTA_GATTC_GetNextCharDescr (UINT16 conn_id, + tBTA_GATTC_CHAR_DESCR_ID *p_start_descr_id, + tBT_UUID *p_descr_uuid_cond, + tBTA_GATTC_CHAR_DESCR_ID *p_descr_result) +{ + tBTA_GATT_STATUS status; + + if (!p_start_descr_id || !p_descr_result) + return BTA_GATT_ILLEGAL_PARAMETER; + + memset(p_descr_result, 0, sizeof(tBTA_GATTC_CHAR_DESCR_ID)); + + if ((status = bta_gattc_query_cache(conn_id, BTA_GATTC_ATTR_TYPE_CHAR_DESCR, + &p_start_descr_id->char_id.srvc_id, + &p_start_descr_id->char_id.char_id, + p_descr_uuid_cond, + &p_descr_result->char_id.char_id, + (void *)&p_start_descr_id->descr_type)) + == BTA_GATT_OK) + { + memcpy(&p_descr_result->descr_type, &p_descr_result->char_id.char_id.uuid, sizeof(tBT_UUID)); + memcpy(&p_descr_result->char_id, p_start_descr_id, sizeof(tBTA_GATTC_CHAR_ID)); + } + + return status; +} + + +/******************************************************************************* +** +** Function BTA_GATTC_GetFirstIncludedService +** +** Description This function is called to find the first included service of the +** service on the given server. +** +** Parameters conn_id: connection ID which identify the server. +** p_srvc_id: the service ID of which the characteristic is belonged to. +** p_uuid_cond: Characteristic UUID, if NULL find the first available +** characteristic. +** p_result: output parameter which will store the GATT ID +** of the included service found. +** +** Returns returns status. +** +*******************************************************************************/ +tBTA_GATT_STATUS BTA_GATTC_GetFirstIncludedService(UINT16 conn_id, tBTA_GATT_SRVC_ID *p_srvc_id, + tBT_UUID *p_uuid_cond, tBTA_GATTC_INCL_SVC_ID *p_result) +{ + tBTA_GATT_STATUS status; + + if (!p_srvc_id || !p_result) + return BTA_GATT_ILLEGAL_PARAMETER; + + if ((status = bta_gattc_query_cache(conn_id, + BTA_GATTC_ATTR_TYPE_INCL_SRVC, + p_srvc_id, + NULL, + p_uuid_cond, + &p_result->incl_svc_id.id, + (tBTA_GATT_CHAR_PROP *)&p_result->incl_svc_id.is_primary)) + == BTA_GATT_OK) + { + memcpy(&p_result->srvc_id, p_srvc_id, sizeof(tBTA_GATT_SRVC_ID)); + } + + return status; +} +/******************************************************************************* +** +** Function BTA_GATTC_GetNextIncludedService +** +** Description This function is called to find the next included service of the +** service on the given server. +** +** Parameters conn_id: connection ID which identify the server. +** p_start_id: start the search from the next record +** after the one identified by p_start_id. +** p_uuid_cond: Included service UUID, if NULL find the first available +** included service. +** p_result: output parameter which will store the GATT ID +** of the included service found. +** +** Returns returns status. +** +*******************************************************************************/ +tBTA_GATT_STATUS BTA_GATTC_GetNextIncludedService(UINT16 conn_id, + tBTA_GATTC_INCL_SVC_ID *p_start_id, + tBT_UUID *p_uuid_cond, + tBTA_GATTC_INCL_SVC_ID *p_result) +{ + tBTA_GATT_STATUS status; + + if (!p_start_id || !p_result) + return BTA_GATT_ILLEGAL_PARAMETER; + + if ((status = bta_gattc_query_cache(conn_id, + BTA_GATTC_ATTR_TYPE_INCL_SRVC, + &p_start_id->srvc_id, + &p_start_id->incl_svc_id.id, + p_uuid_cond, + &p_result->incl_svc_id.id, + (tBTA_GATT_CHAR_PROP *)&p_result->incl_svc_id.is_primary)) + == BTA_GATT_OK) + { + memcpy(&p_result->srvc_id, &p_start_id->srvc_id, sizeof(tBTA_GATT_SRVC_ID)); + } + + return status; +} + +/******************************************************************************* +** +** Function BTA_GATTC_ReadCharacteristic +** +** Description This function is called to read a service's characteristics of +** the given characteritisc ID. +** +** Parameters conn_id - connectino ID. +** p_char_id - characteritic ID to read. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTC_ReadCharacteristic(UINT16 conn_id, tBTA_GATTC_CHAR_ID *p_char_id, + tBTA_GATT_AUTH_REQ auth_req) +{ + tBTA_GATTC_API_READ *p_buf; + + if ((p_buf = (tBTA_GATTC_API_READ *) GKI_getbuf(sizeof(tBTA_GATTC_API_READ))) != NULL) + { + memset(p_buf, 0, sizeof(tBTA_GATTC_API_READ)); + + p_buf->hdr.event = BTA_GATTC_API_READ_EVT; + p_buf->hdr.layer_specific = conn_id; + p_buf->auth_req = auth_req; + + memcpy(&p_buf->srvc_id, &p_char_id->srvc_id, sizeof(tBTA_GATT_SRVC_ID)); + memcpy(&p_buf->char_id, &p_char_id->char_id, sizeof(tBTA_GATT_ID)); + + bta_sys_sendmsg(p_buf); + } + return; +} + +/******************************************************************************* +** +** Function BTA_GATTC_ReadCharDescr +** +** Description This function is called to read a characteristics descriptor. +** +** Parameters conn_id - connection ID. +** p_char_descr_id - characteritic descriptor ID to read. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTC_ReadCharDescr (UINT16 conn_id, + tBTA_GATTC_CHAR_DESCR_ID *p_descr_id, + tBTA_GATT_AUTH_REQ auth_req) +{ + tBTA_GATTC_API_READ *p_buf; + + if ((p_buf = (tBTA_GATTC_API_READ *) GKI_getbuf(sizeof(tBTA_GATTC_API_READ))) != NULL) + { + memset(p_buf, 0, sizeof(tBTA_GATTC_API_READ)); + + p_buf->hdr.event = BTA_GATTC_API_READ_EVT; + p_buf->hdr.layer_specific = conn_id; + p_buf->auth_req = auth_req; + + memcpy(&p_buf->srvc_id, &p_descr_id->char_id.srvc_id, sizeof(tBTA_GATT_SRVC_ID)); + memcpy(&p_buf->char_id, &p_descr_id->char_id.char_id, sizeof(tBTA_GATT_ID)); + memcpy(&p_buf->descr_type, &p_descr_id->descr_type, sizeof(tBT_UUID)); + + bta_sys_sendmsg(p_buf); + } + return; + +} +/******************************************************************************* +** +** Function BTA_GATTC_ReadMultiple +** +** Description This function is called to read multiple characteristic or +** characteristic descriptors. +** +** Parameters conn_id - connectino ID. +** p_read_multi - pointer to the read multiple parameter. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTC_ReadMultiple(UINT16 conn_id, tBTA_GATTC_MULTI *p_read_multi, + tBTA_GATT_AUTH_REQ auth_req) +{ + tBTA_GATTC_API_READ_MULTI *p_buf; + tBTA_GATTC_ATTR_ID *p_value; + UINT16 len = (UINT16)(sizeof(tBTA_GATTC_API_READ_MULTI) + + p_read_multi->num_attr * sizeof(tBTA_GATTC_ATTR_ID)); + UINT8 i; + + if ((p_buf = (tBTA_GATTC_API_READ_MULTI *) GKI_getbuf(len)) != NULL) + { + memset(p_buf, 0, len); + + p_buf->hdr.event = BTA_GATTC_API_READ_MULTI_EVT; + p_buf->hdr.layer_specific = conn_id; + p_buf->auth_req = auth_req; + + p_buf->num_attr = p_read_multi->num_attr; + + if (p_buf->num_attr > 0) + { + p_buf->p_id_list = p_value = (tBTA_GATTC_ATTR_ID *)(p_buf + 1); + + for (i = 0; i < p_buf->num_attr; i ++, p_value ++) + { + memcpy(p_value, &p_read_multi->id_list[i], sizeof(tBTA_GATTC_ATTR_ID)); + } + } + bta_sys_sendmsg(p_buf); + } + return; +} + + +/******************************************************************************* +** +** Function BTA_GATTC_WriteCharValue +** +** Description This function is called to write characteristic value. +** +** Parameters conn_id - connection ID. +** p_char_id - characteristic ID to write. +** write_type - type of write. +** len: length of the data to be written. +** p_value - the value to be written. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTC_WriteCharValue ( UINT16 conn_id, + tBTA_GATTC_CHAR_ID *p_char_id, + tBTA_GATTC_WRITE_TYPE write_type, + UINT16 len, + UINT8 *p_value, + tBTA_GATT_AUTH_REQ auth_req) +{ + tBTA_GATTC_API_WRITE *p_buf; + + if ((p_buf = (tBTA_GATTC_API_WRITE *) GKI_getbuf((UINT16)(sizeof(tBTA_GATTC_API_WRITE) + len))) != NULL) + { + memset(p_buf, 0, sizeof(tBTA_GATTC_API_WRITE) + len); + + p_buf->hdr.event = BTA_GATTC_API_WRITE_EVT; + p_buf->hdr.layer_specific = conn_id; + p_buf->auth_req = auth_req; + + memcpy(&p_buf->srvc_id, &p_char_id->srvc_id, sizeof(tBTA_GATT_SRVC_ID)); + memcpy(&p_buf->char_id, &p_char_id->char_id, sizeof(tBTA_GATT_ID)); + + p_buf->write_type = write_type; + p_buf->len = len; + + if (p_value && len > 0) + { + p_buf->p_value = (UINT8 *)(p_buf + 1); + memcpy(p_buf->p_value, p_value, len); + } + + bta_sys_sendmsg(p_buf); + } + return; +} +/******************************************************************************* +** +** Function BTA_GATTC_WriteCharDescr +** +** Description This function is called to write characteristic descriptor value. +** +** Parameters conn_id - connection ID +** p_char_descr_id - characteristic descriptor ID to write. +** write_type - write type. +** p_value - the value to be written. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTC_WriteCharDescr (UINT16 conn_id, + tBTA_GATTC_CHAR_DESCR_ID *p_char_descr_id, + tBTA_GATTC_WRITE_TYPE write_type, + tBTA_GATT_UNFMT *p_data, + tBTA_GATT_AUTH_REQ auth_req) +{ + tBTA_GATTC_API_WRITE *p_buf; + UINT16 len = sizeof(tBTA_GATTC_API_WRITE) + p_data->len; + + if ((p_buf = (tBTA_GATTC_API_WRITE *) GKI_getbuf(len)) != NULL) + { + memset(p_buf, 0, len); + + p_buf->hdr.event = BTA_GATTC_API_WRITE_EVT; + p_buf->hdr.layer_specific = conn_id; + p_buf->auth_req = auth_req; + + memcpy(&p_buf->srvc_id, &p_char_descr_id->char_id.srvc_id, sizeof(tBTA_GATT_SRVC_ID)); + memcpy(&p_buf->char_id, &p_char_descr_id->char_id.char_id, sizeof(tBTA_GATT_ID)); + memcpy(&p_buf->descr_type, &p_char_descr_id->descr_type, sizeof(tBT_UUID)); + p_buf->write_type = write_type; + + if (p_data && p_data->len != 0) + { + p_buf->p_value = (UINT8 *)(p_buf + 1); + p_buf->len = p_data->len; + /* pack the descr data */ + memcpy(p_buf->p_value, p_data->p_value, p_data->len); + } + + bta_sys_sendmsg(p_buf); + } + return; + +} +/******************************************************************************* +** +** Function BTA_GATTC_PrepareWrite +** +** Description This function is called to prepare write a characteristic value. +** +** Parameters conn_id - connection ID. +** p_char_id - GATT characteritic ID of the service. +** offset - offset of the write value. +** len: length of the data to be written. +** p_value - the value to be written. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTC_PrepareWrite (UINT16 conn_id, tBTA_GATTC_CHAR_ID *p_char_id, + UINT16 offset, UINT16 len, UINT8 *p_value, + tBTA_GATT_AUTH_REQ auth_req) +{ + tBTA_GATTC_API_WRITE *p_buf; + + if ((p_buf = (tBTA_GATTC_API_WRITE *) GKI_getbuf((UINT16)(sizeof(tBTA_GATTC_API_WRITE) + len))) != NULL) + { + memset(p_buf, 0, sizeof(tBTA_GATTC_API_WRITE) + len); + + p_buf->hdr.event = BTA_GATTC_API_WRITE_EVT; + p_buf->hdr.layer_specific = conn_id; + p_buf->auth_req = auth_req; + + memcpy(&p_buf->srvc_id, &p_char_id->srvc_id, sizeof(tBTA_GATT_SRVC_ID)); + memcpy(&p_buf->char_id, &p_char_id->char_id, sizeof(tBTA_GATT_ID)); + + p_buf->write_type = BTA_GATTC_WRITE_PREPARE; + p_buf->offset = offset; + p_buf->len = len; + + if (p_value && len > 0) + { + p_buf->p_value = (UINT8 *)(p_buf + 1); + memcpy(p_buf->p_value, p_value, len); + } + + bta_sys_sendmsg(p_buf); + } + return; + +} +/******************************************************************************* +** +** Function BTA_GATTC_ExecuteWrite +** +** Description This function is called to execute write a prepare write sequence. +** +** Parameters conn_id - connection ID. +** is_execute - execute or cancel. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTC_ExecuteWrite (UINT16 conn_id, BOOLEAN is_execute) +{ + tBTA_GATTC_API_EXEC *p_buf; + + if ((p_buf = (tBTA_GATTC_API_EXEC *) GKI_getbuf((UINT16)sizeof(tBTA_GATTC_API_EXEC))) != NULL) + { + memset(p_buf, 0, sizeof(tBTA_GATTC_API_EXEC)); + + p_buf->hdr.event = BTA_GATTC_API_EXEC_EVT; + p_buf->hdr.layer_specific = conn_id; + + p_buf->is_execute = is_execute; + + bta_sys_sendmsg(p_buf); + } + return; + +} +/******************************************************************************* +** +** Function BTA_GATTC_SendIndConfirm +** +** Description This function is called to send handle value confirmation. +** +** Parameters conn_id - connection ID. +** p_char_id - characteristic ID to confirm. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTC_SendIndConfirm (UINT16 conn_id, tBTA_GATTC_CHAR_ID *p_char_id) +{ + tBTA_GATTC_API_CONFIRM *p_buf; + + APPL_TRACE_API3("BTA_GATTC_SendIndConfirm conn_id=%d service uuid1=0x%x char uuid=0x%x", + conn_id, p_char_id->srvc_id.id.uuid.uu.uuid16, p_char_id->char_id.uuid.uu.uuid16); //toto + + if ((p_buf = (tBTA_GATTC_API_CONFIRM *) GKI_getbuf(sizeof(tBTA_GATTC_API_CONFIRM))) != NULL) + { + memset(p_buf, 0, sizeof(tBTA_GATTC_API_CONFIRM)); + + p_buf->hdr.event = BTA_GATTC_API_CONFIRM_EVT; + p_buf->hdr.layer_specific = conn_id; + + memcpy(&p_buf->srvc_id, &p_char_id->srvc_id, sizeof(tBTA_GATT_SRVC_ID)); + memcpy(&p_buf->char_id, &p_char_id->char_id, sizeof(tBTA_GATT_ID)); + + bta_sys_sendmsg(p_buf); + } + return; + +} + +/******************************************************************************* +** +** Function BTA_GATTC_RegisterForNotifications +** +** Description This function is called to register for notification of a service. +** +** Parameters client_if - client interface. +** bda - target GATT server. +** p_char_id - pointer to GATT characteristic ID. +** +** Returns OK if registration succeed, otherwise failed. +** +*******************************************************************************/ +tBTA_GATT_STATUS BTA_GATTC_RegisterForNotifications (tBTA_GATTC_IF client_if, + BD_ADDR bda, + tBTA_GATTC_CHAR_ID *p_char_id) +{ + tBTA_GATTC_RCB *p_clreg; + tBTA_GATT_STATUS status = BTA_GATT_ILLEGAL_PARAMETER; + UINT8 i; + + if (!p_char_id) + { + APPL_TRACE_ERROR0("deregistration failed, unknow char id"); + return status; + } + + /* lock other GKI task */ + GKI_sched_lock(); + + if ((p_clreg = bta_gattc_cl_get_regcb(client_if)) != NULL) + { + for (i = 0; i < BTA_GATTC_NOTIF_REG_MAX; i ++) + { + if (!p_clreg->notif_reg[i].in_use) + { + memset(&p_clreg->notif_reg, 0, sizeof(tBTA_GATTC_NOTIF_REG)); + + p_clreg->notif_reg[i].in_use = TRUE; + memcpy(p_clreg->notif_reg[i].remote_bda, bda, BD_ADDR_LEN); + memcpy(&p_clreg->notif_reg[i].char_id, p_char_id, sizeof(tBTA_GATTC_CHAR_ID)); + + status = BTA_GATT_OK; + break; + } + } + if (i == BTA_GATTC_NOTIF_REG_MAX) + { + status = BTA_GATT_NO_RESOURCES; + APPL_TRACE_ERROR0("Max Notification Reached, registration failed."); + } + } + else + { + APPL_TRACE_ERROR1("Client_if: %d Not Registered", client_if); + } + + GKI_sched_unlock(); + + return status; +} + +/******************************************************************************* +** +** Function BTA_GATTC_DeregisterForNotifications +** +** Description This function is called to de-register for notification of a service. +** +** Parameters client_if - client interface. +** bda - target GATT server. +** p_char_id - pointer to GATT characteristic ID. +** +** Returns OK if deregistration succeed, otherwise failed. +** +*******************************************************************************/ +tBTA_GATT_STATUS BTA_GATTC_DeregisterForNotifications (tBTA_GATTC_IF client_if, + BD_ADDR bda, + tBTA_GATTC_CHAR_ID *p_char_id) +{ + tBTA_GATTC_RCB *p_clreg; + tBTA_GATT_STATUS status = BTA_GATT_ILLEGAL_PARAMETER; + UINT8 i; + + if (!p_char_id) + { + APPL_TRACE_ERROR0("deregistration failed, unknow char id"); + return status; + } + + /* lock other GKI task */ + GKI_sched_lock(); + + if ((p_clreg = bta_gattc_cl_get_regcb(client_if)) != NULL) + { + for (i = 0; i < BTA_GATTC_NOTIF_REG_MAX; i ++) + { + if (p_clreg->notif_reg[i].in_use && + !memcmp(p_clreg->notif_reg[i].remote_bda, bda, BD_ADDR_LEN) && + !memcmp(&p_clreg->notif_reg[i].char_id, p_char_id, sizeof(tBTA_GATTC_CHAR_ID))) + { + APPL_TRACE_DEBUG0("Deregistered."); + + memset(&p_clreg->notif_reg[i], 0, sizeof(tBTA_GATTC_NOTIF_REG)); + status = BTA_GATT_OK; + break; + } + } + if (i == BTA_GATTC_NOTIF_REG_MAX) + { + status = BTA_GATT_ERROR; + + APPL_TRACE_ERROR0("registration not found"); + } + } + else + { + APPL_TRACE_ERROR1("Client_if: %d Not Registered", client_if); + } + + GKI_sched_unlock(); + + return status; +} + +#endif /* BTA_GATT_INCLUDED */ diff --git a/bta/gatt/bta_gattc_cache.c b/bta/gatt/bta_gattc_cache.c new file mode 100644 index 0000000..7234598 --- /dev/null +++ b/bta/gatt/bta_gattc_cache.c @@ -0,0 +1,1584 @@ +/***************************************************************************** +** +** Name: bta_gattc_cache.c +** +** Description: This file contains the GATT client discovery +** procedures and cache related functions. +** +** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved. +** Broadcom Bluetooth Core. Proprietary and confidential. +** +*****************************************************************************/ + +#include "bt_target.h" + +#if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE) + +#include <string.h> +#include "utl.h" +#include "gki.h" +#include "bta_sys.h" +#include "sdp_api.h" +#include "sdpdefs.h" +#include "bta_gattc_int.h" +#include "btm_api.h" + +static void bta_gattc_char_dscpt_disc_cmpl(UINT16 conn_id, tBTA_GATTC_SERV *p_srvc_cb); +static tBTA_GATT_STATUS bta_gattc_sdp_service_disc(UINT16 conn_id, tBTA_GATTC_SERV *p_server_cb); + +#define BTA_GATT_SDP_DB_SIZE 750 + +/***************************************************************************** +** Constants +*****************************************************************************/ + +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) +static char *bta_gattc_attr_type[] = +{ + "I", /* Included Service */ + "C", /* Characteristic */ + "D" /* Characteristic Descriptor */ +}; +/* utility functions */ + +/******************************************************************************* +** +** Function bta_gattc_display_cache_server +** +** Description debug function to display the server cache. +** +** Returns none. +** +*******************************************************************************/ +static void bta_gattc_display_cache_server(tBTA_GATTC_CACHE *p_cache) +{ + UINT8 i = 0, j; + tBTA_GATTC_CACHE *p_cur_srvc = p_cache; + tBTA_GATTC_CACHE_ATTR *p_attr; + + APPL_TRACE_ERROR0("<================Start Server Cache =============>"); + + while (p_cur_srvc) + { + APPL_TRACE_ERROR6("Service[%d]: handle[%d ~ %d] %s[0x%04x] inst[%d]", + i, p_cur_srvc->s_handle, p_cur_srvc->e_handle, + ((p_cur_srvc->service_uuid.id.uuid.len == 2) ? "uuid16" : "uuid128"), + p_cur_srvc->service_uuid.id.uuid.uu.uuid16, + p_cur_srvc->service_uuid.id.inst_id); + i ++; + + p_attr = p_cur_srvc->p_attr; + + for (j = 0; p_attr; j ++ ) + { + APPL_TRACE_ERROR6("\t Attr[0x%04x] handle[%d] uuid[0x%04x] inst[%d] type[%s] prop[0x%1x]", + j + 1, p_attr->attr_handle, p_attr->p_uuid->uuid16, p_attr->inst_id, + bta_gattc_attr_type[p_attr->attr_type], p_attr->property); + + p_attr = p_attr->p_next; + } + p_cur_srvc = p_cur_srvc->p_next; + } + + APPL_TRACE_ERROR0("<================End Server Cache =============>"); + APPL_TRACE_ERROR0(" "); +} + +/******************************************************************************* +** +** Function bta_gattc_display_explore_record +** +** Description debug function to display the exploration list +** +** Returns none. +** +*******************************************************************************/ +static void bta_gattc_display_explore_record(tBTA_GATTC_ATTR_REC *p_rec, UINT8 num_rec) +{ + UINT8 i; + tBTA_GATTC_ATTR_REC *pp = p_rec; + + APPL_TRACE_ERROR0("<================Start Explore Queue =============>"); + for (i = 0; i < num_rec; i ++, pp ++) + { + APPL_TRACE_ERROR5("\t rec[%d] uuid[0x%04x] s_handle[%d] e_handle[%d] is_primary[%d]", + i + 1, pp->uuid.uu.uuid16, pp->s_handle, pp->e_handle, pp->is_primary); + } + APPL_TRACE_ERROR0("<================ End Explore Queue =============>"); + APPL_TRACE_ERROR0(" "); + +} +#endif /* BTA_GATT_DEBUG == TRUE */ + + +/******************************************************************************* +** +** Function bta_gattc_alloc_cache_buf +** +** Description Allocate a GKI buffer for database cache. +** +** Returns status +** +*******************************************************************************/ +BT_HDR *bta_gattc_alloc_cache_buf(tBTA_GATTC_SERV *p_srvc_cb) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *)GKI_getpoolbuf(GATT_DB_POOL_ID)) == NULL) + { + APPL_TRACE_DEBUG0("No resources: GKI buffer allocation failed."); + utl_freebuf((void **)&p_srvc_cb->p_srvc_list); + p_srvc_cb->free_byte = 0; + } + else + { + memset(p_buf, 0, GKI_get_buf_size(p_buf)); + p_srvc_cb->p_free = (UINT8 *) p_buf; + p_srvc_cb->free_byte = GKI_get_buf_size(p_buf); + + /* link into buffer queue */ + GKI_enqueue(&p_srvc_cb->cache_buffer, p_buf); + } +#if BTA_GATT_DEBUG== TRUE + APPL_TRACE_DEBUG1("allocating new buffer: free byte = %d", p_srvc_cb->free_byte); +#endif + return p_buf; +} +/******************************************************************************* +** +** Function bta_gattc_init_cache +** +** Description Initialize the database cache and discovery related resources. +** +** Returns status +** +*******************************************************************************/ +tBTA_GATT_STATUS bta_gattc_init_cache(tBTA_GATTC_SERV *p_srvc_cb) +{ + tBTA_GATT_STATUS status = BTA_GATT_OK; + + while (p_srvc_cb->cache_buffer.p_first) + GKI_freebuf (GKI_dequeue (&p_srvc_cb->cache_buffer)); + + utl_freebuf((void **)&p_srvc_cb->p_srvc_list); + + if ((p_srvc_cb->p_srvc_list = (tBTA_GATTC_ATTR_REC*)GKI_getbuf(BTA_GATTC_ATTR_LIST_SIZE)) == NULL) + { + APPL_TRACE_DEBUG0("No resources: GKI buffer allocation failed."); + status = GATT_NO_RESOURCES; + } + else + { + p_srvc_cb->total_srvc = 0; + p_srvc_cb->cur_srvc_idx = + p_srvc_cb->cur_char_idx = + p_srvc_cb->next_avail_idx = 0; + + if (bta_gattc_alloc_cache_buf(p_srvc_cb) == NULL) + { + status = GATT_NO_RESOURCES; + } + else + { + p_srvc_cb->p_cur_srvc = p_srvc_cb->p_srvc_cache = NULL; + } + } + + return status; +} +/******************************************************************************* +** +** Function bta_gattc_get_srvc_inst_id +** +** Description get service instance number +** +** Returns instance ID of the service. +** +*******************************************************************************/ +static UINT8 bta_gattc_get_srvc_inst_id(tBTA_GATTC_SERV *p_srvc_cb, tBT_UUID uuid) +{ + UINT8 i = 0, inst = 0; + tBTA_GATTC_ATTR_REC *p_srvc_rec; + + for (i = 0; i < p_srvc_cb->total_srvc; i ++) + /* + for (; i < p_srvc_cb->cur_srvc_idx; i ++)*/ + { + p_srvc_rec = p_srvc_cb->p_srvc_list + i; + + if (bta_gattc_uuid_compare(p_srvc_rec->uuid, uuid, TRUE)) + inst ++; + } + return inst ; +} +/******************************************************************************* +** +** Function bta_gattc_get_char_inst_id +** +** Description get characteristic instance number +** +** Returns characteristic instance ID. +** +*******************************************************************************/ +static UINT8 bta_gattc_get_char_inst_id(tBTA_GATTC_CACHE *p_service_cache, tBT_UUID uuid) +{ + UINT8 inst = 0; + tBTA_GATTC_CACHE_ATTR *p_attr; + tBT_UUID attr_uuid; + + p_attr = p_service_cache->p_attr; + + while (p_attr) + { + bta_gattc_pack_attr_uuid(p_attr, &attr_uuid); + + if (bta_gattc_uuid_compare(attr_uuid, uuid, TRUE)) + inst ++; + + p_attr = p_attr->p_next; + } + return inst ; +} + +/******************************************************************************* +** +** Function bta_gattc_add_srvc_to_cache +** +** Description Add a service into database cache. +** +** Returns status +** +*******************************************************************************/ +static tBTA_GATT_STATUS bta_gattc_add_srvc_to_cache(tBTA_GATTC_SERV *p_srvc_cb, + UINT16 s_handle, UINT16 e_handle, + tBT_UUID *p_uuid, + BOOLEAN is_primary, UINT8 srvc_inst) +{ + tBTA_GATTC_CACHE *p_new_srvc = NULL; + tBTA_GATT_STATUS status = BTA_GATT_OK; + +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_DEBUG0("Add a service into Service"); + APPL_TRACE_DEBUG2("free byte = %d, req %d bytes.", p_srvc_cb->free_byte, sizeof(tBTA_GATTC_CACHE)) +#endif + + if (p_srvc_cb->free_byte < sizeof(tBTA_GATTC_CACHE)) + { + if (bta_gattc_alloc_cache_buf(p_srvc_cb) == NULL) + return GATT_NO_RESOURCES; + } + + p_new_srvc = (tBTA_GATTC_CACHE *)p_srvc_cb->p_free; + /* update service information */ + p_new_srvc->s_handle = s_handle; + p_new_srvc->e_handle = e_handle; + p_new_srvc->service_uuid.is_primary = is_primary; + memcpy(&p_new_srvc->service_uuid.id.uuid, p_uuid, sizeof(tBT_UUID)); + p_new_srvc->service_uuid.id.inst_id = srvc_inst; + p_new_srvc->p_next = NULL; + + if (p_srvc_cb->p_cur_srvc != NULL) + p_srvc_cb->p_cur_srvc->p_next = p_new_srvc; + p_srvc_cb->p_cur_srvc = p_new_srvc; + + /* first service */ + if (p_srvc_cb->p_srvc_cache == NULL) + p_srvc_cb->p_srvc_cache = p_new_srvc; + + /* update buffer managament info */ + p_srvc_cb->p_free += sizeof(tBTA_GATTC_CACHE); + p_srvc_cb->free_byte -= sizeof(tBTA_GATTC_CACHE); + + +#if 0 +//#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + bta_gattc_display_cache_server(p_srvc_cb->p_srvc_cache); +#endif + return status; +} +/******************************************************************************* +** +** Function bta_gattc_add_attr_to_cache +** +** Description Add an attribute into database cache buffer. +** +** Returns status +** +*******************************************************************************/ +static tBTA_GATT_STATUS bta_gattc_add_attr_to_cache(tBTA_GATTC_SERV *p_srvc_cb, + UINT16 handle, + tBT_UUID *p_uuid, + UINT8 property, + tBTA_GATTC_ATTR_TYPE type) +{ + tBTA_GATTC_CACHE_ATTR *p_attr; + tBTA_GATT_STATUS status = BTA_GATT_OK; + UINT16 len = sizeof(tBTA_GATTC_CACHE_ATTR) + p_uuid->len; + UINT8 *pp; + +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_DEBUG1("bta_gattc_add_attr_to_cache: Add a [%s] into Service", bta_gattc_attr_type[type]); + APPL_TRACE_DEBUG4("handle=%d uuid16=0x%x property=0x%x type=%d", handle, p_uuid->uu.uuid16, property, type); + APPL_TRACE_DEBUG2("free byte = %d, req %d bytes.", p_srvc_cb->free_byte, len); +#endif + + if (p_srvc_cb->free_byte < len) + { + if (bta_gattc_alloc_cache_buf(p_srvc_cb) == NULL) + return GATT_NO_RESOURCES; + } + + p_attr = (tBTA_GATTC_CACHE_ATTR *)p_srvc_cb->p_free; + + p_attr->attr_handle = handle; + p_attr->attr_type = type; + p_attr->property = property; + p_attr->uuid_len = p_uuid->len; + p_attr->p_uuid = (tBTA_GATTC_UUID *)(p_attr + 1); + p_attr->p_next = NULL; + + pp = (UINT8 *)p_attr->p_uuid; + + if (p_uuid->len == LEN_UUID_16) + { + UINT16_TO_STREAM(pp, p_uuid->uu.uuid16); + } + else if (p_uuid->len == LEN_UUID_128) + { + memcpy(pp, p_uuid->uu.uuid128, LEN_UUID_128); + } + + if (type == BTA_GATTC_ATTR_TYPE_CHAR) + p_attr->inst_id = bta_gattc_get_char_inst_id(p_srvc_cb->p_cur_srvc, *p_uuid); + /* else: char descriptor, no instance ID needed */ + else /* TODO: --->> temp treat included service same as char descriptor */ + p_attr->inst_id = 0; + + /* update service information */ + p_srvc_cb->p_free += len; + p_srvc_cb->free_byte -= len; + + /* first attribute within the service, update the attribute pointer */ + if (p_srvc_cb->p_cur_srvc->p_attr == NULL) + { + p_srvc_cb->p_cur_srvc->p_attr = p_attr; + } + if (p_srvc_cb->p_cur_srvc->p_last_attr != NULL) + p_srvc_cb->p_cur_srvc->p_last_attr->p_next = p_attr; + + p_srvc_cb->p_cur_srvc->p_last_attr = p_attr; + +#if 0 +//#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + bta_gattc_display_cache_server(p_srvc_cb->p_srvc_cache); +#endif + return status; +} + +/******************************************************************************* +** +** Function bta_gattc_get_disc_range +** +** Description get discovery stating and ending handle range. +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_get_disc_range(tBTA_GATTC_SERV *p_srvc_cb, UINT16 *p_s_hdl, UINT16 *p_e_hdl, BOOLEAN is_srvc) +{ + tBTA_GATTC_ATTR_REC *p_rec = NULL; + + if (is_srvc) + { + p_rec = p_srvc_cb->p_srvc_list + p_srvc_cb->cur_srvc_idx; + *p_s_hdl = p_rec->s_handle; + } + else + { + p_rec = p_srvc_cb->p_srvc_list + p_srvc_cb->cur_char_idx; + *p_s_hdl = p_rec->s_handle + 1; + } + + *p_e_hdl = p_rec->e_handle; +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_DEBUG2("discover range [%d ~ %d]",p_rec->s_handle, p_rec->e_handle); +#endif + return; +} +/******************************************************************************* +** +** Function bta_gattc_discover_pri_service +** +** Description Start primary service discovery +** +** Returns status of the operation. +** +*******************************************************************************/ +tBTA_GATT_STATUS bta_gattc_discover_pri_service(UINT16 conn_id, tBTA_GATTC_SERV *p_server_cb, UINT8 disc_type) +{ +#if (BLE_INCLUDED == TRUE && (defined BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE)) + tBT_DEVICE_TYPE dev_type; + tBLE_ADDR_TYPE addr_type; + + BTM_ReadDevInfo(p_server_cb->server_bda, &dev_type, &addr_type); + if (dev_type == BT_DEVICE_TYPE_BLE) + return bta_gattc_discover_procedure(conn_id, p_server_cb, disc_type); + else + return bta_gattc_sdp_service_disc(conn_id, p_server_cb); +#endif + return BTA_GATT_ERROR; + +} +/******************************************************************************* +** +** Function bta_gattc_discover_procedure +** +** Description Start a particular type of discovery procedure on server. +** +** Returns status of the operation. +** +*******************************************************************************/ +tBTA_GATT_STATUS bta_gattc_discover_procedure(UINT16 conn_id, tBTA_GATTC_SERV *p_server_cb, UINT8 disc_type) +{ + tGATT_DISC_PARAM param; + BOOLEAN is_service = TRUE; + + memset(¶m, 0, sizeof(tGATT_DISC_PARAM)); + + if (disc_type == GATT_DISC_SRVC_ALL || disc_type == GATT_DISC_SRVC_BY_UUID) + { + param.s_handle = 1; + param.e_handle = 0xFFFF; + } + else + { + if (disc_type == GATT_DISC_CHAR_DSCPT) + is_service = FALSE; + + bta_gattc_get_disc_range(p_server_cb, ¶m.s_handle, ¶m.e_handle, is_service); + + if (param.s_handle > param.e_handle) + { + APPL_TRACE_ERROR2("discover range invalid: [0x%04x ~ 0x%04x]", param.s_handle, param.e_handle); + + return GATT_ERROR; + } + } + return GATTC_Discover (conn_id, disc_type, ¶m); + +} +/******************************************************************************* +** +** Function bta_gattc_start_disc_include_srvc +** +** Description Start discovery for included service +** +** Returns status of the operation. +** +*******************************************************************************/ +tBTA_GATT_STATUS bta_gattc_start_disc_include_srvc(UINT16 conn_id, tBTA_GATTC_SERV *p_srvc_cb) +{ + APPL_TRACE_DEBUG0("starting discovery included service"); + + return bta_gattc_discover_procedure(conn_id, p_srvc_cb, GATT_DISC_INC_SRVC); +} +/******************************************************************************* +** +** Function bta_gattc_start_disc_char +** +** Description Start discovery for characteristic +** +** Returns status of the operation. +** +*******************************************************************************/ +tBTA_GATT_STATUS bta_gattc_start_disc_char(UINT16 conn_id, tBTA_GATTC_SERV *p_srvc_cb) +{ + p_srvc_cb->total_char = 0; + + APPL_TRACE_DEBUG0("starting discover characteristics"); + + return bta_gattc_discover_procedure(conn_id, p_srvc_cb, GATT_DISC_CHAR); +} +/******************************************************************************* +** +** Function bta_gattc_start_disc_char_dscp +** +** Description Start discovery for characteristic descriptor +** +** Returns none. +** +*******************************************************************************/ +void bta_gattc_start_disc_char_dscp(UINT16 conn_id, tBTA_GATTC_SERV *p_srvc_cb) +{ + APPL_TRACE_DEBUG0("starting discover characteristics descriptor"); + + if (bta_gattc_discover_procedure(conn_id, p_srvc_cb, GATT_DISC_CHAR_DSCPT) != 0) + bta_gattc_char_dscpt_disc_cmpl(conn_id, p_srvc_cb); + +} +/******************************************************************************* +** +** Function bta_gattc_explore_srvc +** +** Description process the service discovery complete event +** +** Returns status +** +*******************************************************************************/ +static void bta_gattc_explore_srvc(UINT16 conn_id, tBTA_GATTC_SERV *p_srvc_cb) +{ + tBTA_GATTC_ATTR_REC *p_rec = p_srvc_cb->p_srvc_list + p_srvc_cb->cur_srvc_idx; + tBTA_GATTC_CLCB *p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id); + + APPL_TRACE_DEBUG1("Start service discovery: srvc_idx = %d", p_srvc_cb->cur_srvc_idx); + + p_srvc_cb->cur_char_idx = p_srvc_cb->next_avail_idx = p_srvc_cb->total_srvc; + + if (p_clcb == NULL) + { + APPL_TRACE_ERROR0("unknown connection ID"); + return; + } + /* start expore a service if there is service not been explored */ + if (p_srvc_cb->cur_srvc_idx < p_srvc_cb->total_srvc) + { + /* add the first service into cache */ + if (bta_gattc_add_srvc_to_cache (p_srvc_cb, + p_rec->s_handle, + p_rec->e_handle, + &p_rec->uuid, + p_rec->is_primary, + p_rec->srvc_inst_id) == 0) + { + /* start discovering included services */ + bta_gattc_start_disc_include_srvc(conn_id, p_srvc_cb); + return; + } + } + /* no service found at all, the end of server discovery*/ + APPL_TRACE_ERROR0("No More Service found"); + +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + bta_gattc_display_cache_server(p_srvc_cb->p_srvc_cache); +#endif + /* save cache to NV */ + p_clcb->p_srcb->state = BTA_GATTC_SERV_SAVE; + bta_gattc_co_cache_open(p_srvc_cb->server_bda, BTA_GATTC_CI_CACHE_OPEN_EVT, + conn_id, TRUE); + //bta_gattc_sm_execute(p_clcb, BTA_GATTC_DISCOVER_CMPL_EVT, NULL); +} +/******************************************************************************* +** +** Function bta_gattc_incl_srvc_disc_cmpl +** +** Description process the relationship discovery complete event +** +** Returns status +** +*******************************************************************************/ +static void bta_gattc_incl_srvc_disc_cmpl(UINT16 conn_id, tBTA_GATTC_SERV *p_srvc_cb) +{ + p_srvc_cb->cur_char_idx = p_srvc_cb->total_srvc; + + /* start discoverying characteristic */ + bta_gattc_start_disc_char(conn_id, p_srvc_cb); +} +/******************************************************************************* +** +** Function bta_gattc_char_disc_cmpl +** +** Description process the characteristic discovery complete event +** +** Returns status +** +*******************************************************************************/ +static void bta_gattc_char_disc_cmpl(UINT16 conn_id, tBTA_GATTC_SERV *p_srvc_cb) +{ + tBTA_GATTC_ATTR_REC *p_rec = p_srvc_cb->p_srvc_list + p_srvc_cb->cur_char_idx; + + APPL_TRACE_DEBUG1("Total %d Char found ", p_srvc_cb->total_char); + + /* if there are characteristic needs to be explored */ + if (p_srvc_cb->total_char > 0) + { + /* add the first characteristic into cache */ + bta_gattc_add_attr_to_cache (p_srvc_cb, + p_rec->s_handle, + &p_rec->uuid, + p_rec->property, + BTA_GATTC_ATTR_TYPE_CHAR); + + /* start discoverying characteristic descriptor , if failed, disc for next char*/ + bta_gattc_start_disc_char_dscp(conn_id, p_srvc_cb); + } + else /* otherwise start with next service */ + { + p_srvc_cb->cur_srvc_idx ++; + + bta_gattc_explore_srvc (conn_id, p_srvc_cb); + } +} +/******************************************************************************* +** +** Function bta_gattc_char_dscpt_disc_cmpl +** +** Description process the char descriptor discovery complete event +** +** Returns status +** +*******************************************************************************/ +static void bta_gattc_char_dscpt_disc_cmpl(UINT16 conn_id, tBTA_GATTC_SERV *p_srvc_cb) +{ + tBTA_GATTC_ATTR_REC *p_rec = NULL; + + if (-- p_srvc_cb->total_char > 0) + { + p_rec = p_srvc_cb->p_srvc_list + (++ p_srvc_cb->cur_char_idx); + /* add the next characteristic into cache */ + bta_gattc_add_attr_to_cache (p_srvc_cb, + p_rec->s_handle, + &p_rec->uuid, + p_rec->property, + BTA_GATTC_ATTR_TYPE_CHAR); + + /* start discoverying next characteristic for char descriptor */ + bta_gattc_start_disc_char_dscp(conn_id, p_srvc_cb); + } + else + /* all characteristic has been explored, start with next service if any */ + { +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_ERROR0("all char has been explored"); +#endif + p_srvc_cb->cur_srvc_idx ++; + bta_gattc_explore_srvc (conn_id, p_srvc_cb); + } + +} +static BOOLEAN bta_gattc_srvc_in_list(tBTA_GATTC_SERV *p_srvc_cb, UINT16 s_handle, + UINT16 e_handle, tBT_UUID uuid) +{ + tBTA_GATTC_ATTR_REC *p_rec = NULL; + UINT8 i; + BOOLEAN exist_srvc = FALSE; + + if (!GATT_HANDLE_IS_VALID(s_handle) || !GATT_HANDLE_IS_VALID(e_handle)) + { + APPL_TRACE_ERROR2("invalid included service handle: [0x%04x ~ 0x%04x]", s_handle, e_handle); + exist_srvc = TRUE; + } + else + { + for (i = 0; i < p_srvc_cb->next_avail_idx; i ++) + { + p_rec = p_srvc_cb->p_srvc_list + i; + + /* a new service should not have any overlap with other service handle range */ + if (p_rec->s_handle == s_handle || p_rec->e_handle == e_handle) + { + exist_srvc = TRUE; + break; + } + } + } + return exist_srvc; +} +/******************************************************************************* +** +** Function bta_gattc_add_srvc_to_list +** +** Description Add a service into explore pending list +** +** Returns status +** +*******************************************************************************/ +static tBTA_GATT_STATUS bta_gattc_add_srvc_to_list(tBTA_GATTC_SERV *p_srvc_cb, + UINT16 s_handle, UINT16 e_handle, + tBT_UUID uuid, BOOLEAN is_primary) +{ + tBTA_GATTC_ATTR_REC *p_rec = NULL; + tBTA_GATT_STATUS status = BTA_GATT_OK; + + if (p_srvc_cb->next_avail_idx < BTA_GATTC_MAX_CACHE_CHAR) + { + p_rec = p_srvc_cb->p_srvc_list + p_srvc_cb->next_avail_idx; + + p_srvc_cb->total_srvc ++; + + APPL_TRACE_DEBUG2("bta_gattc_add_srvc_to_list handle = %d, service type = 0x%04x", + s_handle, uuid.uu.uuid16); + + p_rec->s_handle = s_handle; + p_rec->e_handle = e_handle; + p_rec->is_primary = is_primary; + p_rec->srvc_inst_id = bta_gattc_get_srvc_inst_id(p_srvc_cb, uuid); + memcpy(&p_rec->uuid, &uuid, sizeof(tBT_UUID)); + + p_srvc_cb->next_avail_idx ++; + + } + else + { /* allocate bigger buffer ?? */ + status = GATT_DB_FULL; + + APPL_TRACE_ERROR0("char not added, no resources"); + } + return status; +} +/******************************************************************************* +** +** Function bta_gattc_add_char_to_list +** +** Description Add a characteristic into explore pending list +** +** Returns status +** +*******************************************************************************/ +static tBTA_GATT_STATUS bta_gattc_add_char_to_list(tBTA_GATTC_SERV *p_srvc_cb, + UINT16 decl_handle, UINT16 value_handle, + tBT_UUID uuid, UINT8 property) +{ + tBTA_GATTC_ATTR_REC *p_rec = NULL; + tBTA_GATT_STATUS status = BTA_GATT_OK; + + if (p_srvc_cb->p_srvc_list == NULL) + { + APPL_TRACE_ERROR0("No service available, unexpected char discovery result"); + status = BTA_GATT_INTERNAL_ERROR; + } + else if (p_srvc_cb->next_avail_idx < BTA_GATTC_MAX_CACHE_CHAR) + { + + p_rec = p_srvc_cb->p_srvc_list + p_srvc_cb->next_avail_idx; + + p_srvc_cb->total_char ++; + + p_rec->s_handle = value_handle; + p_rec->property = property; + p_rec->e_handle = (p_srvc_cb->p_srvc_list + p_srvc_cb->cur_srvc_idx)->e_handle; + memcpy(&p_rec->uuid, &uuid, sizeof(tBT_UUID)); + + /* update the endind handle of pervious characteristic if available */ + if (p_srvc_cb->total_char > 1) + { + p_rec -= 1; + p_rec->e_handle = decl_handle - 1; + } + p_srvc_cb->next_avail_idx ++; + } + else + { + APPL_TRACE_ERROR0("char not added, no resources"); + /* allocate bigger buffer ?? */ + status = BTA_GATT_DB_FULL; + } + return status; + +} +/******************************************************************************* +** +** Function bta_gattc_sdp_callback +** +** Description Process the discovery result from sdp +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_sdp_callback (UINT16 sdp_status) +{ + tSDP_DISC_REC *p_sdp_rec = NULL; + tBT_UUID service_uuid; + tSDP_PROTOCOL_ELEM pe; + UINT16 start_handle = 0, end_handle = 0; + tBTA_GATTC_SERV *p_srvc_cb = bta_gattc_find_scb_by_cid(bta_gattc_cb.sdp_conn_id); + + if(((sdp_status == SDP_SUCCESS) || (sdp_status == SDP_DB_FULL)) && p_srvc_cb != NULL) + { + do + { + /* find a service record, report it */ + p_sdp_rec = SDP_FindServiceInDb(bta_gattc_cb.p_sdp_db, + 0, p_sdp_rec); + if (p_sdp_rec) + { + if (SDP_FindServiceUUIDInRec(p_sdp_rec, &service_uuid)) + { + + if (SDP_FindProtocolListElemInRec(p_sdp_rec, UUID_PROTOCOL_ATT, &pe)) + { + start_handle = (UINT16) pe.params[0]; + end_handle = (UINT16) pe.params[1]; + +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_EVENT3("Found ATT service [0x%04x] handle[0x%04x ~ 0x%04x]", + service_uuid.uu.uuid16, start_handle, end_handle); +#endif + + if (GATT_HANDLE_IS_VALID(start_handle) && GATT_HANDLE_IS_VALID(end_handle) && + p_srvc_cb != NULL) + { + /* discover services result, add services into a service list */ + bta_gattc_add_srvc_to_list(p_srvc_cb, + start_handle, + end_handle, + service_uuid, + TRUE); + } + else + { + APPL_TRACE_ERROR2("invalid start_handle = %d end_handle = %d", start_handle, end_handle); + } + } + + + } + } + } while (p_sdp_rec); + } + + if ( p_srvc_cb != NULL) + /* start discover primary service */ + bta_gattc_explore_srvc(bta_gattc_cb.sdp_conn_id, p_srvc_cb); + else + { + APPL_TRACE_ERROR0("GATT service discovery is done on unknown connection"); + } + + GKI_freebuf(bta_gattc_cb.p_sdp_db); + bta_gattc_cb.p_sdp_db = NULL; + bta_gattc_cb.sdp_conn_id = 0; +} +/******************************************************************************* +** +** Function bta_gattc_sdp_service_disc +** +** Description Start DSP Service Discovert +** +** Returns void +** +*******************************************************************************/ +static tBTA_GATT_STATUS bta_gattc_sdp_service_disc(UINT16 conn_id, tBTA_GATTC_SERV *p_server_cb) +{ + tSDP_UUID uuid; + UINT16 num_attrs = 2; + UINT16 attr_list[2]; + tBTA_GATT_STATUS status = BTA_GATT_ERROR; + + memset (&uuid, 0, sizeof(tSDP_UUID)); + + uuid.len = LEN_UUID_16; + uuid.uu.uuid16 = UUID_PROTOCOL_ATT; + + if((bta_gattc_cb.p_sdp_db = (tSDP_DISCOVERY_DB *)GKI_getbuf(BTA_GATT_SDP_DB_SIZE)) != NULL) + { + attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST; + attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST; + + SDP_InitDiscoveryDb (bta_gattc_cb.p_sdp_db, BTA_GATT_SDP_DB_SIZE, 1, &uuid, num_attrs, attr_list); + + if(!SDP_ServiceSearchAttributeRequest (p_server_cb->server_bda, bta_gattc_cb.p_sdp_db, &bta_gattc_sdp_callback)) + { + GKI_freebuf(bta_gattc_cb.p_sdp_db); + bta_gattc_cb.p_sdp_db = NULL; + } + else + { + bta_gattc_cb.sdp_conn_id = conn_id; + status = BTA_GATT_OK; + } + } + return status; +} +/******************************************************************************* +** +** Function bta_gattc_disc_res_cback +** bta_gattc_disc_cmpl_cback +** +** Description callback functions to GATT client stack. +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_disc_res_cback (UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT_DISC_RES *p_data) +{ + tBTA_GATTC_SERV * p_srvc_cb = NULL; + BOOLEAN pri_srvc; + + p_srvc_cb = bta_gattc_find_scb_by_cid(conn_id); + + if (p_srvc_cb != NULL) + { + switch (disc_type) + { + case GATT_DISC_SRVC_ALL: + /* discover services result, add services into a service list */ + bta_gattc_add_srvc_to_list(p_srvc_cb, + p_data->handle, + p_data->value.group_value.e_handle, + p_data->value.group_value.service_type, + TRUE); + + break; + case GATT_DISC_SRVC_BY_UUID: + bta_gattc_add_srvc_to_list(p_srvc_cb, + p_data->handle, + p_data->value.handle, + p_data->type, + TRUE); + break; + + case GATT_DISC_INC_SRVC: + /* add included service into service list if it's secondary or it never showed up + in the primary service search */ + pri_srvc = bta_gattc_srvc_in_list(p_srvc_cb, + p_data->value.incl_service.s_handle, + p_data->value.incl_service.e_handle, + p_data->value.incl_service.service_type); + + if (!pri_srvc) + bta_gattc_add_srvc_to_list(p_srvc_cb, + p_data->value.incl_service.s_handle, + p_data->value.incl_service.e_handle, + p_data->value.incl_service.service_type, + FALSE); + /* add into database */ + bta_gattc_add_attr_to_cache(p_srvc_cb, + p_data->handle, + &p_data->value.incl_service.service_type, + pri_srvc, + BTA_GATTC_ATTR_TYPE_INCL_SRVC); + break; + + case GATT_DISC_CHAR: + /* add char value into database */ + bta_gattc_add_char_to_list(p_srvc_cb, + p_data->handle, + p_data->value.dclr_value.val_handle, + p_data->value.dclr_value.char_uuid, + p_data->value.dclr_value.char_prop); + break; + + case GATT_DISC_CHAR_DSCPT: + bta_gattc_add_attr_to_cache(p_srvc_cb, p_data->handle, &p_data->type, 0, BTA_GATTC_ATTR_TYPE_CHAR_DESCR); + break; + } + } +} +void bta_gattc_disc_cmpl_cback (UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT_STATUS status) +{ + tBTA_GATTC_SERV * p_srvc_cb; + + p_srvc_cb = bta_gattc_find_scb_by_cid(conn_id); + + if (p_srvc_cb != NULL) + { + switch (disc_type) + { + case GATT_DISC_SRVC_ALL: +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + bta_gattc_display_explore_record(p_srvc_cb->p_srvc_list, p_srvc_cb->next_avail_idx); +#endif + bta_gattc_explore_srvc(conn_id, p_srvc_cb); + break; + + case GATT_DISC_INC_SRVC: + bta_gattc_incl_srvc_disc_cmpl(conn_id, p_srvc_cb); + + break; + + case GATT_DISC_CHAR: +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + bta_gattc_display_explore_record(p_srvc_cb->p_srvc_list, p_srvc_cb->next_avail_idx); +#endif + bta_gattc_char_disc_cmpl(conn_id, p_srvc_cb); + break; + + case GATT_DISC_CHAR_DSCPT: + bta_gattc_char_dscpt_disc_cmpl(conn_id, p_srvc_cb); + break; + } + } +} +/******************************************************************************* +** +** Function bta_gattc_id2handle +** +** Description map GATT ID to handle in a given cache. +** +** Returns the handle mapped. 0 if not found. +** +*******************************************************************************/ +UINT16 bta_gattc_id2handle(tBTA_GATTC_SERV *p_srcb, tBTA_GATT_SRVC_ID *p_service_id, + tBTA_GATT_ID *p_char_id, tBT_UUID descr_uuid) +{ + tBTA_GATTC_CACHE *p_cache = p_srcb->p_srvc_cache; + tBTA_GATTC_CACHE_ATTR *p_attr; + UINT8 j; + UINT16 handle = 0; + tBT_UUID attr_uuid; + BOOLEAN char_map = FALSE, done = FALSE; + + while (p_cache && !done) + { +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_DEBUG3("Service: handle[%d] uuid[0x%04x] inst[%d]", + p_cache->s_handle, p_cache->service_uuid.id.uuid.uu.uuid16, + p_cache->service_uuid.id.inst_id); +#endif + p_attr = p_cache->p_attr; + + if (bta_gattc_uuid_compare(p_service_id->id.uuid, p_cache->service_uuid.id.uuid, TRUE) && + p_service_id->id.inst_id == p_cache->service_uuid.id.inst_id && + p_cache->service_uuid.is_primary == p_service_id->is_primary) + { + for (j = 0; p_attr; j ++) + { +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_DEBUG5("\t Attr[0x%04x] handle[0x%04x] uuid[0x%04x] inst[%d] type[%d]", + j + 1, p_attr->attr_handle, p_attr->p_uuid->uuid16, p_attr->inst_id, p_attr->attr_type); +#endif + bta_gattc_pack_attr_uuid(p_attr, &attr_uuid); + + if (bta_gattc_uuid_compare(p_char_id->uuid, attr_uuid, TRUE) && + p_char_id->inst_id == p_attr->inst_id) + { + if (descr_uuid.len == 0) + { + handle = p_attr->attr_handle; + done = TRUE; + break; + } + else + { +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_DEBUG0("found matching characteristic for the descriptor"); +#endif + char_map = TRUE; + } + } + else if (char_map == TRUE) + { + if (p_attr->attr_type == BTA_GATTC_ATTR_TYPE_CHAR_DESCR) + { + + if (bta_gattc_uuid_compare(descr_uuid, attr_uuid, TRUE)) + { +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_DEBUG0("found descripotor!!"); +#endif + handle = p_attr->attr_handle; + done = TRUE; + break; + } + else + { +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_DEBUG0("descriptor UUID not matching"); +#endif + } + } + else /* another char */ + { +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_DEBUG0("no matching descriptor found!! start of next characteristic"); +#endif + char_map = FALSE; + done = TRUE; + break; + } + } + p_attr = p_attr->p_next; + } + } + p_cache = p_cache->p_next; + } + + return handle; +} +/******************************************************************************* +** +** Function bta_gattc_handle2id +** +** Description map a handle to GATT ID in a given cache. +** +** Returns FALSE if map can not be found. +** +*******************************************************************************/ + +BOOLEAN bta_gattc_handle2id(tBTA_GATTC_SERV *p_srcb, UINT16 handle, tBTA_GATT_SRVC_ID *p_service_id, + tBTA_GATT_ID *p_char_id, tBT_UUID *p_descr_type) +{ + tBTA_GATTC_CACHE *p_cache = p_srcb->p_srvc_cache; + tBTA_GATTC_CACHE_ATTR *p_attr, *p_char = NULL; + UINT8 j; + + memset(p_service_id, 0, sizeof(tBTA_GATT_SRVC_ID)); + memset(p_char_id, 0, sizeof(tBTA_GATT_ID)); + memset(p_descr_type, 0, sizeof(tBT_UUID)); + + while (p_cache) + { +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_DEBUG3("Service: handle[%d] uuid[0x%04x] inst[%d]", + p_cache->s_handle, p_cache->service_uuid.id.uuid.uu.uuid16, + p_cache->service_uuid.id.inst_id); +#endif + /* a service found */ + if (p_cache->s_handle == handle) + { + memcpy(p_service_id, &p_cache->service_uuid, sizeof(tBTA_GATT_SRVC_ID)); + + return TRUE; + } + else /* start looking for attributes within the service */ + { + p_attr = p_cache->p_attr; + + for (j = 0; p_attr; j ++) + { +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_DEBUG5("\t Attr[0x%04x] handle[0x%04x] uuid[0x%04x] inst[%d] type[%d]", + j + 1, p_attr->attr_handle, p_attr->p_uuid->uuid16, p_attr->inst_id, p_attr->attr_type); +#endif + if (p_attr->attr_type == BTA_GATTC_ATTR_TYPE_CHAR) + p_char = p_attr; + + if (handle == p_attr->attr_handle) + { + memcpy(p_service_id, &p_cache->service_uuid, sizeof(tBTA_GATT_SRVC_ID)); + + if (p_attr->attr_type == BTA_GATTC_ATTR_TYPE_CHAR_DESCR) + { + bta_gattc_pack_attr_uuid(p_attr, p_descr_type); + + if (p_char != NULL) + { + bta_gattc_pack_attr_uuid(p_char, &p_char_id->uuid); + p_char_id->inst_id = p_char->inst_id; + } + else + { + APPL_TRACE_ERROR0("descriptor does not belong to any chracteristic, error"); + } + } + else + /* is a characterisitc value or included service */ + { + bta_gattc_pack_attr_uuid(p_attr, &p_char_id->uuid); + p_char_id->inst_id =p_attr->inst_id; + } + return TRUE; + } + p_attr = p_attr->p_next; + } + } + p_cache = p_cache->p_next; + } + + return FALSE; +} + +/******************************************************************************* +** +** Function bta_gattc_search_service +** +** Description search local cache for matching service record. +** +** Returns FALSE if map can not be found. +** +*******************************************************************************/ +void bta_gattc_search_service(tBTA_GATTC_CLCB *p_clcb, tBT_UUID uuid) +{ + tBTA_GATTC_SERV *p_srcb = p_clcb->p_srcb; + tBTA_GATTC_CACHE *p_cache = p_srcb->p_srvc_cache; + tBTA_GATTC cb_data; + + while (p_cache) + { + if (bta_gattc_uuid_compare(uuid, p_cache->service_uuid.id.uuid, FALSE)) + { +//#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_DEBUG3("found service [0x%04x], inst[%d] handle [%d]", + p_cache->service_uuid.id.uuid.uu.uuid16, + p_cache->service_uuid.id.inst_id, + p_cache->s_handle); +//#endif + if (p_clcb->p_rcb->p_cback) + { + memset(&cb_data, 0, sizeof(tBTA_GATTC)); + + cb_data.srvc_res.conn_id = p_clcb->bta_conn_id; + memcpy(&cb_data.srvc_res.service_uuid, &p_cache->service_uuid ,sizeof(tBTA_GATT_SRVC_ID)); + + (* p_clcb->p_rcb->p_cback)(BTA_GATTC_SEARCH_RES_EVT, &cb_data); + //todo (tBTA_GATTC *)&p_cache->service_uuid); + } + } + p_cache = p_cache->p_next; + } +} +/******************************************************************************* +** +** Function bta_gattc_find_record +** +** Description search local cache for matching attribute record. +** +** Parameter p_result: output parameter to store the characteristic/ +** included service GATT ID. +** +** Returns GATT_ERROR is no recording found. BTA_GATT_OK if record found. +** +*******************************************************************************/ +static tBTA_GATT_STATUS bta_gattc_find_record(tBTA_GATTC_SERV *p_srcb, + tBTA_GATTC_ATTR_TYPE attr_type, + tBTA_GATT_SRVC_ID *p_service_id, + tBTA_GATT_ID *p_start_rec, + tBT_UUID * p_uuid_cond, + tBTA_GATT_ID *p_result, + void *p_param) +{ + tBTA_GATTC_CACHE *p_cache = p_srcb->p_srvc_cache; + tBTA_GATT_STATUS status = BTA_GATT_ERROR; + tBT_UUID uuid_cond = {0}, start_descr = {0}; + UINT8 i, j; + tBTA_GATTC_CACHE_ATTR *p_attr; + BOOLEAN char_found = FALSE, descr_found = FALSE; + + if (p_uuid_cond) + memcpy(&uuid_cond, p_uuid_cond, sizeof(tBT_UUID)); + + for (i = 0; p_cache <= p_srcb->p_cur_srvc && p_cache && status != BTA_GATT_OK; i ++) + { + if (bta_gattc_uuid_compare(p_service_id->id.uuid, p_cache->service_uuid.id.uuid, FALSE) && + p_service_id->id.inst_id == p_cache->service_uuid.id.inst_id && + p_service_id->is_primary == p_cache->service_uuid.is_primary) + { +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_DEBUG2("found matching service [0x%04x], inst[%d]", + p_cache->service_uuid.id.uuid.uu.uuid16, + p_cache->service_uuid.id.inst_id); +#endif + p_attr = p_cache->p_attr; + + for (j = 0; p_attr; j ++) + { +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_DEBUG5("\t Attr[%d] handle[0x%04x] uuid[0x%04x] inst[%d] type[%d]", + j + 1, p_attr->attr_handle, + p_attr->p_uuid->uuid16, + p_attr->inst_id, + p_attr->attr_type); +#endif + bta_gattc_pack_attr_uuid(p_attr, &p_result->uuid); + + if (p_start_rec != NULL && char_found == FALSE) + { + /* find the starting record first */ + if (bta_gattc_uuid_compare(p_start_rec->uuid, p_result->uuid, FALSE) && + p_start_rec->inst_id == p_attr->inst_id && + (attr_type == p_attr->attr_type || + /* find descriptor would look for characteristic first */ + (attr_type == BTA_GATTC_ATTR_TYPE_CHAR_DESCR && p_attr->attr_type == BTA_GATTC_ATTR_TYPE_CHAR))) + { + char_found = TRUE; + } + } + else + { + /* if looking for descriptor, here is the where the descrptor to be found */ + if (attr_type == BTA_GATTC_ATTR_TYPE_CHAR_DESCR) + { + /* starting descriptor UUID */ + if (p_param != NULL) + memcpy(&start_descr, p_param, sizeof(tBT_UUID)); + /* next characeteristic already, return error */ + if (p_attr->attr_type != BTA_GATTC_ATTR_TYPE_CHAR_DESCR) + { + break; + } + else + { + if (start_descr.len != 0 && !descr_found) + { + if (bta_gattc_uuid_compare(start_descr, p_result->uuid, FALSE)) + { + descr_found = TRUE; + } + } + else + { + /* with matching descriptor */ + if (bta_gattc_uuid_compare(uuid_cond, p_result->uuid, FALSE)) + { + status = BTA_GATT_OK; + break; + } + } + } + } + else + { + if (bta_gattc_uuid_compare(uuid_cond, p_result->uuid, FALSE) && + attr_type == p_attr->attr_type) + { + + APPL_TRACE_DEBUG0("found char handle mapping characteristic"); + p_result->inst_id = p_attr->inst_id; + + if (p_param != NULL) + { + if (attr_type == BTA_GATTC_ATTR_TYPE_CHAR || + attr_type == BTA_GATTC_ATTR_TYPE_INCL_SRVC) + { + *(tBTA_GATT_CHAR_PROP *)p_param = p_attr->property; + } + } + + status = BTA_GATT_OK; + break; + } + } + } + p_attr = p_attr->p_next; + } + if (status) + { + APPL_TRACE_ERROR0("In the given service, can not find matching record"); + } + break; + } + + p_cache = p_cache->p_next; + } + return status; + +} + +/******************************************************************************* +** +** Function bta_gattc_query_cache +** +** Description search local cache for matching attribute record. +** +** Parameters conn_id: connection ID which identify the server. +** p_srvc_id: the service ID of which the characteristic is belonged to. +** *p_start_rec: start the search from the next record +** after the one identified by *p_start_rec. +** p_uuid_cond: UUID, if NULL find the first available +** characteristic/included service. +** p_output: output parameter which will store the GATT ID +** of the characteristic /included service found. +** +** Returns BTA_GATT_ERROR is no recording found. BTA_GATT_OK if record found. +** +*******************************************************************************/ +tBTA_GATT_STATUS bta_gattc_query_cache(UINT16 conn_id, + tBTA_GATTC_ATTR_TYPE query_type, + tBTA_GATT_SRVC_ID *p_srvc_id, + tBTA_GATT_ID *p_start_rec, + tBT_UUID *p_uuid_cond, + tBTA_GATT_ID *p_output, + void *p_param) +{ + tBTA_GATTC_CLCB *p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id); + tBTA_GATT_STATUS status = BTA_GATT_ILLEGAL_PARAMETER; + + /* lock other GKI task */ + GKI_sched_lock(); + + APPL_TRACE_DEBUG0("bta_gattc_query_cache"); + + if (p_clcb != NULL ) + { + if (p_clcb->state == BTA_GATTC_CONN_ST) + { + if (p_clcb->p_srcb && + !p_clcb->p_srcb->p_srvc_list && /* no active discovery */ + p_clcb->p_srcb->p_srvc_cache) + { + status = bta_gattc_find_record(p_clcb->p_srcb, + query_type, + p_srvc_id, + p_start_rec, + p_uuid_cond, + p_output, + p_param); + } + else + { + status = BTA_GATT_ERROR; + APPL_TRACE_ERROR0("No server cache available"); + } + } + else + { + APPL_TRACE_ERROR1("server cache not available, CLCB state = %d", p_clcb->state); + + status = (p_clcb->state == BTA_GATTC_DISCOVER_ST) ? BTA_GATT_BUSY : BTA_GATT_ERROR; + } + } + else + { + APPL_TRACE_ERROR1("Unknown conn ID: %d", conn_id); + } + GKI_sched_unlock(); + + return status; +} + +/******************************************************************************* +** +** Function bta_gattc_rebuild_cache +** +** Description rebuild server cache from NV cache. +** +** Parameters +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_rebuild_cache(tBTA_GATTC_SERV *p_srvc_cb, UINT16 num_attr, + tBTA_GATTC_NV_ATTR *p_attr, UINT16 attr_index) +{ + /* first attribute loading, initialize buffer */ + APPL_TRACE_ERROR0("bta_gattc_rebuild_cache"); + if (attr_index == 0) + { + while (p_srvc_cb->cache_buffer.p_first) + GKI_freebuf (GKI_dequeue (&p_srvc_cb->cache_buffer)); + + if (bta_gattc_alloc_cache_buf(p_srvc_cb) == NULL) + { + APPL_TRACE_ERROR0("allocate cache buffer failed, no resources"); + } + else + { + p_srvc_cb->p_cur_srvc = p_srvc_cb->p_srvc_cache = NULL; + } + } + + while (num_attr > 0 && p_attr != NULL) + { + switch (p_attr->attr_type) + { + case BTA_GATTC_ATTR_TYPE_SRVC: + bta_gattc_add_srvc_to_cache(p_srvc_cb, + p_attr->s_handle, + p_attr->e_handle, + &p_attr->uuid, + p_attr->is_primary, + p_attr->id); + break; + + case BTA_GATTC_ATTR_TYPE_CHAR: + case BTA_GATTC_ATTR_TYPE_CHAR_DESCR: + case BTA_GATTC_ATTR_TYPE_INCL_SRVC: + bta_gattc_add_attr_to_cache(p_srvc_cb, + p_attr->s_handle, + &p_attr->uuid, + p_attr->prop, + p_attr->attr_type); + break; + } + p_attr ++; + num_attr --; + } +} + +/******************************************************************************* +** +** Function bta_gattc_fill_nv_attr +** +** Description fill a NV attribute entry value +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_fill_nv_attr(tBTA_GATTC_NV_ATTR *p_attr, UINT8 type, UINT16 s_handle, + UINT16 e_handle, UINT8 id, tBT_UUID uuid, UINT8 prop, BOOLEAN is_primary) +{ + p_attr->s_handle = s_handle; + p_attr->e_handle = e_handle; + p_attr->attr_type = type; + p_attr->is_primary = is_primary; + p_attr->id = id; + p_attr->prop = prop; + + memcpy(&p_attr->uuid, &uuid, sizeof(tBT_UUID)); +} +/******************************************************************************* +** +** Function bta_gattc_cache_save +** +** Description save the server cache into NV +** +** Returns None. +** +*******************************************************************************/ +BOOLEAN bta_gattc_cache_save(tBTA_GATTC_SERV *p_srvc_cb, UINT16 conn_id) +{ + tBTA_GATTC_CACHE *p_cur_srvc = p_srvc_cb->p_srvc_cache; + UINT8 i = 0; + UINT16 offset = 0; + tBTA_GATTC_NV_ATTR nv_attr[BTA_GATTC_NV_LOAD_MAX]; + tBTA_GATTC_CACHE_ATTR *p_attr; + tBT_UUID uuid; + + while (p_cur_srvc && i < BTA_GATTC_NV_LOAD_MAX) + { + if (offset ++ >= p_srvc_cb->attr_index) + { + bta_gattc_fill_nv_attr(&nv_attr[i++], + BTA_GATTC_ATTR_TYPE_SRVC, + p_cur_srvc->s_handle, + p_cur_srvc->e_handle, + p_cur_srvc->service_uuid.id.inst_id, + p_cur_srvc->service_uuid.id.uuid, + 0, + p_cur_srvc->service_uuid.is_primary); + } + + p_attr = p_cur_srvc->p_attr; + + for (; p_attr && i < BTA_GATTC_NV_LOAD_MAX ; offset ++, p_attr = p_attr->p_next) + { + if (offset >= p_srvc_cb->attr_index) + { + if ((uuid.len = p_attr->uuid_len) == LEN_UUID_16) + { + uuid.uu.uuid16 = p_attr->p_uuid->uuid16; + } + else + { + memcpy(uuid.uu.uuid128, p_attr->p_uuid->uuid128, LEN_UUID_128); + } + + bta_gattc_fill_nv_attr(&nv_attr[i++], + p_attr->attr_type, + p_attr->attr_handle, + 0, + p_attr->inst_id, + uuid, + p_attr->property, + FALSE); + } + } + p_cur_srvc = p_cur_srvc->p_next; + } + + if (i > 0) + { + bta_gattc_co_cache_save(p_srvc_cb->server_bda, BTA_GATTC_CI_CACHE_SAVE_EVT, i, + nv_attr, p_srvc_cb->attr_index, conn_id); + + p_srvc_cb->attr_index += i; + + return TRUE; + } + else + { + return FALSE; + } +} +#endif /* BTA_GATT_INCLUDED */ + diff --git a/bta/gatt/bta_gattc_ci.c b/bta/gatt/bta_gattc_ci.c new file mode 100644 index 0000000..f5b4f41 --- /dev/null +++ b/bta/gatt/bta_gattc_ci.c @@ -0,0 +1,125 @@ +/***************************************************************************** +** +** Name: bta_gattc_ci.c +** +** Description: This is the implementation file for the GATT +** call-in functions. +** +** Copyright (c) 2010, Broadcom Corp., All Rights Reserved. +** Widcomm Bluetooth Core. Proprietary and confidential. +** +*****************************************************************************/ + +#include "bt_target.h" + +#if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE) + +#include <string.h> + +#include "bta_api.h" +#include "bta_sys.h" +#include "bta_gattc_ci.h" +#include "gki.h" +#include "bd.h" + +/******************************************************************************* +** +** Function bta_gattc_ci_cache_open +** +** Description This function sends an event to indicate server cache open +** completed. +** +** Parameters server_bda - server BDA of this cache. +** status - BTA_GATT_OK if full buffer of data, +** BTA_GATT_FAIL if an error has occurred. +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_ci_cache_open(BD_ADDR server_bda, UINT16 evt, tBTA_GATT_STATUS status, + UINT16 conn_id) +{ + tBTA_GATTC_CI_EVT *p_evt; + + if ((p_evt = (tBTA_GATTC_CI_EVT *) GKI_getbuf(sizeof(tBTA_GATTC_CI_EVT))) != NULL) + { + p_evt->hdr.event = evt; + p_evt->hdr.layer_specific = conn_id; + + p_evt->status = status; + bta_sys_sendmsg(p_evt); + } +} + +/******************************************************************************* +** +** Function bta_gattc_ci_cache_load +** +** Description This function sends an event to BTA indicating the phone has +** load the servere cache and ready to send it to the stack. +** +** Parameters server_bda - server BDA of this cache. +** num_bytes_read - number of bytes read into the buffer +** specified in the read callout-function. +** status - BTA_GATT_OK if full buffer of data, +** BTA_GATT_FAIL if an error has occurred. +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_ci_cache_load(BD_ADDR server_bda, UINT16 evt, UINT16 num_attr, + tBTA_GATTC_NV_ATTR *p_attr, tBTA_GATT_STATUS status, + UINT16 conn_id) +{ + tBTA_GATTC_CI_LOAD *p_evt; + + if ((p_evt = (tBTA_GATTC_CI_LOAD *) GKI_getbuf(sizeof(tBTA_GATTC_CI_LOAD))) != NULL) + { + memset(p_evt, 0, sizeof(tBTA_GATTC_CI_LOAD)); + + p_evt->hdr.event = evt; + p_evt->hdr.layer_specific = conn_id; + + p_evt->status = status; + p_evt->num_attr = (num_attr > BTA_GATTC_NV_LOAD_MAX) ? BTA_GATTC_NV_LOAD_MAX : num_attr; + + if (p_evt->num_attr > 0 && p_attr != NULL) + { + memcpy(p_evt->attr, p_attr, p_evt->num_attr * sizeof(tBTA_GATTC_NV_ATTR)); + } + + bta_sys_sendmsg(p_evt); + } +} + +/******************************************************************************* +** +** Function bta_gattc_ci_cache_save +** +** Description This function sends an event to BTA indicating the phone has +** save the servere cache. +** +** Parameters server_bda - server BDA of this cache. +** evt - callin event code. +** status - BTA_GATT_OK if full buffer of data, +** BTA_GATT_ERROR if an error has occurred. +*8 conn_id - for this NV operation for. +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_ci_cache_save(BD_ADDR server_bda, UINT16 evt, tBTA_GATT_STATUS status, + UINT16 conn_id) +{ + tBTA_GATTC_CI_EVT *p_evt; + + if ((p_evt = (tBTA_GATTC_CI_EVT *) GKI_getbuf(sizeof(tBTA_GATTC_CI_EVT))) != NULL) + { + p_evt->hdr.event = evt; + p_evt->hdr.layer_specific = conn_id; + + p_evt->status = status; + bta_sys_sendmsg(p_evt); + } +} +#endif /* BTA_GATT_INCLUDED */ diff --git a/bta/gatt/bta_gattc_int.h b/bta/gatt/bta_gattc_int.h new file mode 100644 index 0000000..4ae7697 --- /dev/null +++ b/bta/gatt/bta_gattc_int.h @@ -0,0 +1,452 @@ +/***************************************************************************** +** +** Name: bta_gattc_int.h +** +** Description: This is the private file for the file transfer +** client (FTC). +** +** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved. +** Broadcom Bluetooth Core. Proprietary and confidential. +** +*****************************************************************************/ +#ifndef BTA_GATTC_INT_H +#define BTA_GATTC_INT_H + +#include "bt_target.h" +#include "bta_sys.h" +#include "bta_gatt_api.h" +#include "bta_gattc_ci.h" +#include "bta_gattc_co.h" + +#include "gki.h" + +/***************************************************************************** +** Constants and data types +*****************************************************************************/ +enum +{ + BTA_GATTC_API_OPEN_EVT = BTA_SYS_EVT_START(BTA_ID_GATTC), + BTA_GATTC_INT_OPEN_FAIL_EVT, + BTA_GATTC_API_CANCEL_OPEN_EVT, + BTA_GATTC_INT_CANCEL_OPEN_OK_EVT, + + BTA_GATTC_API_READ_EVT, + BTA_GATTC_API_WRITE_EVT, + BTA_GATTC_API_EXEC_EVT, + + BTA_GATTC_API_CLOSE_EVT, + + BTA_GATTC_API_SEARCH_EVT, + BTA_GATTC_API_CONFIRM_EVT, + BTA_GATTC_API_READ_MULTI_EVT, + + BTA_GATTC_INT_CONN_EVT, + BTA_GATTC_INT_DISCOVER_EVT, + BTA_GATTC_DISCOVER_CMPL_EVT, + BTA_GATTC_OP_CMPL_EVT, + BTA_GATTC_INT_DISCONN_EVT, + + /* for cache loading/saving */ + BTA_GATTC_START_CACHE_EVT, + BTA_GATTC_CI_CACHE_OPEN_EVT, + BTA_GATTC_CI_CACHE_LOAD_EVT, + BTA_GATTC_CI_CACHE_SAVE_EVT, + + BTA_GATTC_INT_START_IF_EVT, + BTA_GATTC_API_REG_EVT, + BTA_GATTC_API_DEREG_EVT, + BTA_GATTC_INT_DEREG_EVT + +}; +typedef UINT16 tBTA_GATTC_INT_EVT; + +/* max client application GATTC can support */ +#ifndef BTA_GATTC_CL_MAX +#define BTA_GATTC_CL_MAX 4 +#endif + +/* max known devices GATTC can support */ +#ifndef BTA_GATTC_KNOWN_SR_MAX +#define BTA_GATTC_KNOWN_SR_MAX 4 +#endif + +#ifndef BTA_GATTC_CLCB_MAX + #define BTA_GATTC_CLCB_MAX GATT_CL_MAX_LCB +#endif + +#define BTA_GATTC_WRITE_PREPARE GATT_WRITE_PREPARE + +/* internal strucutre for GATTC register API */ +typedef struct +{ + BT_HDR hdr; + tBT_UUID app_uuid; + tBTA_GATTC_CBACK *p_cback; +}tBTA_GATTC_API_REG; + +typedef struct +{ + BT_HDR hdr; + tBTA_GATTC_IF client_if; +}tBTA_GATTC_INT_START_IF; + +typedef tBTA_GATTC_INT_START_IF tBTA_GATTC_API_DEREG; +typedef tBTA_GATTC_INT_START_IF tBTA_GATTC_INT_DEREG; + +typedef struct +{ + BT_HDR hdr; + BD_ADDR remote_bda; + tBTA_GATTC_IF client_if; + BOOLEAN is_direct; +} tBTA_GATTC_API_OPEN; + +typedef tBTA_GATTC_API_OPEN tBTA_GATTC_API_CANCEL_OPEN; + +typedef struct +{ + BT_HDR hdr; + tBTA_GATT_AUTH_REQ auth_req; + tBTA_GATT_SRVC_ID srvc_id; + tBTA_GATT_ID char_id; + tBT_UUID descr_type; +} tBTA_GATTC_API_READ; + +typedef struct +{ + BT_HDR hdr; + tBTA_GATT_AUTH_REQ auth_req; + tBTA_GATT_SRVC_ID srvc_id; + tBTA_GATT_ID char_id; + tBT_UUID descr_type; + tBTA_GATTC_WRITE_TYPE write_type; + UINT16 offset; + UINT16 len; + UINT8 *p_value; +}tBTA_GATTC_API_WRITE; + +typedef struct +{ + BT_HDR hdr; + BOOLEAN is_execute; +}tBTA_GATTC_API_EXEC; + +typedef struct +{ + BT_HDR hdr; + tBTA_GATT_SRVC_ID srvc_id; + tBTA_GATT_ID char_id; +} tBTA_GATTC_API_CONFIRM; + +typedef tGATT_CL_COMPLETE tBTA_GATTC_CMPL; + +typedef struct +{ + BT_HDR hdr; + UINT8 op_code; + tGATT_STATUS status; + tBTA_GATTC_CMPL *p_cmpl; +}tBTA_GATTC_OP_CMPL; + +typedef struct +{ + BT_HDR hdr; + tBT_UUID srvc_uuid; +}tBTA_GATTC_API_SEARCH; + +typedef struct +{ + BT_HDR hdr; + tBTA_GATT_AUTH_REQ auth_req; + UINT8 num_attr; + tBTA_GATTC_ATTR_ID *p_id_list; +}tBTA_GATTC_API_READ_MULTI; + +typedef union +{ + BT_HDR hdr; + tBTA_GATTC_API_REG api_reg; + tBTA_GATTC_API_DEREG api_dereg; + tBTA_GATTC_API_OPEN api_conn; + tBTA_GATTC_API_CANCEL_OPEN api_cancel_conn; + tBTA_GATTC_API_READ api_read; + tBTA_GATTC_API_SEARCH api_search; + tBTA_GATTC_API_WRITE api_write; + tBTA_GATTC_API_CONFIRM api_confirm; + tBTA_GATTC_API_EXEC api_exec; + tBTA_GATTC_API_READ_MULTI api_read_multi; + tBTA_GATTC_OP_CMPL op_cmpl; + tBTA_GATTC_CI_EVT ci_open; + tBTA_GATTC_CI_EVT ci_save; + tBTA_GATTC_CI_LOAD ci_load; + + tBTA_GATTC_INT_START_IF int_start_if; + tBTA_GATTC_INT_DEREG int_dereg; + +} tBTA_GATTC_DATA; + + +/* GATT server cache on the client */ +typedef union +{ + UINT8 uuid128[LEN_UUID_128]; + UINT16 uuid16; +}tBTA_GATTC_UUID; + +typedef struct gattc_attr_cache +{ + tBTA_GATTC_UUID *p_uuid; + struct gattc_attr_cache *p_next; + UINT16 uuid_len; + UINT16 attr_handle; + UINT8 inst_id; + tBTA_GATT_CHAR_PROP property; /* if characteristic, it is char property; + if included service, flag primary, + if descriptor, not used */ + tBTA_GATTC_ATTR_TYPE attr_type; +// btla-specific ++ +} __attribute__((packed)) tBTA_GATTC_CACHE_ATTR; +// btla-specific -- + +typedef struct gattc_svc_cache +{ + tBTA_GATT_SRVC_ID service_uuid; + tBTA_GATTC_CACHE_ATTR *p_attr; + tBTA_GATTC_CACHE_ATTR *p_last_attr; + UINT16 s_handle; + UINT16 e_handle; + struct gattc_svc_cache *p_next; +// btla-specific ++ +} __attribute__((packed)) tBTA_GATTC_CACHE; +// btla-specific -- + +typedef struct +{ + tBT_UUID uuid; + UINT16 s_handle; + UINT16 e_handle; + BOOLEAN is_primary; + UINT8 srvc_inst_id; + tBTA_GATT_CHAR_PROP property; +}tBTA_GATTC_ATTR_REC; + + +#define BTA_GATTC_MAX_CACHE_CHAR 40 +#define BTA_GATTC_ATTR_LIST_SIZE (BTA_GATTC_MAX_CACHE_CHAR * sizeof(tBTA_GATTC_ATTR_REC)) + +#ifndef BTA_GATTC_CACHE_SRVR_SIZE + #define BTA_GATTC_CACHE_SRVR_SIZE 600 +#endif + +enum +{ + BTA_GATTC_IDLE_ST = 0, /* Idle */ + BTA_GATTC_W4_CONN_ST, /* Wait for connection - (optional) */ + BTA_GATTC_CONN_ST, /* connected state */ + BTA_GATTC_DISCOVER_ST /* discover is in progress */ +}; +typedef UINT8 tBTA_GATTC_STATE; + +typedef struct +{ + BOOLEAN in_use; + BD_ADDR server_bda; + BOOLEAN connected; + +#define BTA_GATTC_SERV_IDLE 0 +#define BTA_GATTC_SERV_LOAD 1 +#define BTA_GATTC_SERV_SAVE 2 + + UINT8 state; + + tBTA_GATTC_CACHE *p_srvc_cache; + tBTA_GATTC_CACHE *p_cur_srvc; + BUFFER_Q cache_buffer; /* buffer queue used for storing the cache data */ + UINT8 *p_free; /* starting point to next available byte */ + UINT16 free_byte; /* number of available bytes in server cache buffer */ + UINT8 update_count; /* indication received */ + UINT8 num_clcb; /* number of associated CLCB */ + + + tBTA_GATTC_ATTR_REC *p_srvc_list; + UINT8 cur_srvc_idx; + UINT8 cur_char_idx; + UINT8 next_avail_idx; + UINT8 total_srvc; + UINT8 total_char; + + UINT8 srvc_hdl_chg; /* service handle change indication pending */ + UINT16 attr_index; /* cahce NV saving/loading attribute index */ + +} tBTA_GATTC_SERV; + +#ifndef BTA_GATTC_NOTIF_REG_MAX +#define BTA_GATTC_NOTIF_REG_MAX 4 +#endif + +typedef struct +{ + BOOLEAN in_use; + BD_ADDR remote_bda; + tBTA_GATTC_CHAR_ID char_id; +}tBTA_GATTC_NOTIF_REG; + +typedef struct +{ + tBTA_GATTC_CBACK *p_cback; + BOOLEAN in_use; + tBTA_GATTC_IF client_if; /* client interface with BTE stack for this application */ + UINT8 num_clcb; /* number of associated CLCB */ + BOOLEAN dereg_pending; + tBT_UUID app_uuid; + tBTA_GATTC_NOTIF_REG notif_reg[BTA_GATTC_NOTIF_REG_MAX]; +}tBTA_GATTC_RCB; + +/* client channel is a mapping between a BTA client(cl_id) and a remote BD address */ +typedef struct +{ + UINT16 bta_conn_id; /* client channel ID, unique for clcb */ + BD_ADDR bda; + tBTA_GATTC_RCB *p_rcb; /* pointer to the registration CB */ + tBTA_GATTC_SERV *p_srcb; /* server cache CB */ + tBTA_GATTC_DATA *p_q_cmd; /* command in queue waiting for execution */ + +#define BTA_GATTC_NO_SCHEDULE 0 +#define BTA_GATTC_DISC_WAITING 0x01 +#define BTA_GATTC_REQ_WAITING 0x10 + + UINT8 auto_update; /* auto update is waiting */ + BOOLEAN in_use; + tBTA_GATTC_STATE state; + tBTA_GATT_STATUS status; + UINT16 reason; +} tBTA_GATTC_CLCB; + +/* back ground connection tracking information */ +#if GATT_MAX_APPS <= 8 +typedef UINT8 tBTA_GATTC_CIF_MASK ; +#elif GATT_MAX_APPS <= 16 +typedef UINT16 tBTA_GATTC_CIF_MASK; +#elif GATT_MAX_APPS <= 32 +typedef UINT32 tBTA_GATTC_CIF_MASK; +#endif + +typedef struct +{ + BOOLEAN in_use; + BD_ADDR remote_bda; + tBTA_GATTC_CIF_MASK cif_mask; + +}tBTA_GATTC_BG_TCK; + +typedef struct +{ + tBTA_GATTC_BG_TCK bg_track[BTA_GATTC_KNOWN_SR_MAX]; + tBTA_GATTC_RCB cl_rcb[BTA_GATTC_CL_MAX]; + + tBTA_GATTC_CLCB clcb[BTA_GATTC_CLCB_MAX]; + tBTA_GATTC_SERV known_server[BTA_GATTC_KNOWN_SR_MAX]; + + tSDP_DISCOVERY_DB *p_sdp_db; + UINT16 sdp_conn_id; +}tBTA_GATTC_CB; + +/***************************************************************************** +** Global data +*****************************************************************************/ + +/* GATTC control block */ +#if BTA_DYNAMIC_MEMORY == FALSE +extern tBTA_GATTC_CB bta_gattc_cb; +#else +extern tBTA_GATTC_CB *bta_gattc_cb_ptr; +#define bta_gattc_cb (*bta_gattc_cb_ptr) +#endif + +/***************************************************************************** +** Function prototypes +*****************************************************************************/ +extern BOOLEAN bta_gattc_hdl_event(BT_HDR *p_msg); +extern void bta_gattc_sm_execute(tBTA_GATTC_CLCB *p_clcb, UINT16 event, tBTA_GATTC_DATA *p_data); + +/* function processed outside SM */ +extern void bta_gattc_register(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_start_if(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_process_api_open (tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA * p_msg); +extern void bta_gattc_process_api_open_cancel (tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA * p_msg); +extern void bta_gattc_deregister(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_int_deregister(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_data); + +/* function within state machine */ +extern void bta_gattc_open(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_open_fail(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_open_error(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); + +extern void bta_gattc_cancel_open(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_cancel_open_ok(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_cancel_open_error(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); + +extern void bta_gattc_conn(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); + +extern void bta_gattc_close(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_close_fail(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); + +extern void bta_gattc_start_discover(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_disc_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_read(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_write(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_op_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_q_cmd(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_search(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_fail(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_confirm(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_execute(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_read_multi(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_ci_open(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_ci_load(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_ci_close(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_ci_save(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_cache_open(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_ignore_op_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_init_bk_conn(tBTA_GATTC_API_OPEN *p_data, tBTA_GATTC_RCB *p_clreg); +extern void bta_gattc_cancel_bk_conn(tBTA_GATTC_API_CANCEL_OPEN *p_data); +extern void bta_gattc_send_open_cback( tBTA_GATTC_RCB *p_clreg, tBTA_GATT_STATUS status, + BD_ADDR remote_bda, UINT16 conn_id); + +/* utility functions */ +extern tBTA_GATTC_CLCB * bta_gattc_find_clcb_by_cif (UINT8 client_if, BD_ADDR remote_bda); //todo +extern tBTA_GATTC_CLCB * bta_gattc_find_clcb_by_conn_id (UINT16 conn_id); +extern tBTA_GATTC_CLCB * bta_gattc_clcb_alloc(tBTA_GATTC_IF client_if, BD_ADDR remote_bda); +extern void bta_gattc_clcb_dealloc(tBTA_GATTC_CLCB *p_clcb); +extern tBTA_GATTC_CLCB * bta_gattc_find_alloc_clcb(tBTA_GATTC_IF client_if, BD_ADDR remote_bda); +extern tBTA_GATTC_RCB * bta_gattc_cl_get_regcb(UINT8 client_if); +extern tBTA_GATTC_SERV * bta_gattc_find_srcb(BD_ADDR bda); +extern tBTA_GATTC_SERV * bta_gattc_srcb_alloc(BD_ADDR bda); +extern tBTA_GATTC_SERV * bta_gattc_find_scb_by_cid (UINT16 conn_id); +extern BOOLEAN bta_gattc_enqueue(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); + +extern UINT16 bta_gattc_id2handle(tBTA_GATTC_SERV *p_srcb, tBTA_GATT_SRVC_ID *p_service_id, tBTA_GATT_ID *p_char_id, tBT_UUID descr_uuid); +extern BOOLEAN bta_gattc_handle2id(tBTA_GATTC_SERV *p_srcb, UINT16 handle, tBTA_GATT_SRVC_ID *service_id, tBTA_GATT_ID *char_id, tBT_UUID *p_type); +extern BOOLEAN bta_gattc_uuid_compare (tBT_UUID src, tBT_UUID tar, BOOLEAN is_precise); +extern void bta_gattc_pack_attr_uuid(tBTA_GATTC_CACHE_ATTR *p_attr, tBT_UUID *p_uuid); +extern BOOLEAN bta_gattc_check_notif_registry(tBTA_GATTC_RCB *p_clreg, tBTA_GATTC_SERV *p_srcb, tBTA_GATTC_NOTIFY *p_notify); +extern tBTA_GATT_STATUS bta_gattc_pack_read_cb_data(tBTA_GATTC_SERV *p_srcb, tBT_UUID descr_uuid, tGATT_VALUE *p_attr, tBTA_GATT_READ_VAL *p_value); +extern BOOLEAN bta_gattc_mark_bg_conn (tBTA_GATTC_IF client_if, BD_ADDR remote_bda, BOOLEAN add); +extern BOOLEAN bta_gattc_check_bg_conn (tBTA_GATTC_IF client_if, BD_ADDR remote_bda); +extern UINT8 bta_gattc_num_reg_app(void); +extern void bta_gattc_clear_notif_registration(UINT16 conn_id); + +/* discovery functions */ +extern void bta_gattc_disc_res_cback (UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT_DISC_RES *p_data); +extern void bta_gattc_disc_cmpl_cback (UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT_STATUS status); +extern tBTA_GATT_STATUS bta_gattc_discover_procedure(UINT16 conn_id, tBTA_GATTC_SERV *p_server_cb, UINT8 disc_type); +extern tBTA_GATT_STATUS bta_gattc_discover_pri_service(UINT16 conn_id, tBTA_GATTC_SERV *p_server_cb, UINT8 disc_type); +extern void bta_gattc_search_service(tBTA_GATTC_CLCB *p_clcb, tBT_UUID uuid); +extern tBTA_GATT_STATUS bta_gattc_query_cache(UINT16 conn_id, UINT8 query_type, tBTA_GATT_SRVC_ID *p_srvc_id, + tBTA_GATT_ID *p_start_rec,tBT_UUID *p_uuid_cond, + tBTA_GATT_ID *p_output, void *p_property); +extern tBTA_GATT_STATUS bta_gattc_init_cache(tBTA_GATTC_SERV *p_srvc_cb); +extern void bta_gattc_rebuild_cache(tBTA_GATTC_SERV *p_srcv, UINT16 num_attr, tBTA_GATTC_NV_ATTR *p_attr, UINT16 attr_index); +extern BOOLEAN bta_gattc_cache_save(tBTA_GATTC_SERV *p_srvc_cb, UINT16 conn_id); + +#endif /* BTA_GATTC_INT_H */ diff --git a/bta/gatt/bta_gattc_main.c b/bta/gatt/bta_gattc_main.c new file mode 100644 index 0000000..5016c46 --- /dev/null +++ b/bta/gatt/bta_gattc_main.c @@ -0,0 +1,474 @@ +/***************************************************************************** +** +** Name: bta_gattc_main.c +** +** Description: This file contains the GATT client main functions +** and state machine. +** +** Copyright (c) 2003-2009, Broadcom Corp., All Rights Reserved. +** Widcomm Bluetooth Core. Proprietary and confidential. +** +*****************************************************************************/ + +#include "bt_target.h" + +#if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE) + +#include <string.h> + +#include "bta_gattc_int.h" +#include "gki.h" + + +/***************************************************************************** +** Constants and types +*****************************************************************************/ + + +/* state machine action enumeration list */ +enum +{ + BTA_GATTC_OPEN, + BTA_GATTC_OPEN_FAIL, + //BTA_GATTC_OPEN_FAIL_IN_CONN, //<--- need to remove this? + BTA_GATTC_OPEN_ERROR, + BTA_GATTC_CANCEL_OPEN, + BTA_GATTC_CANCEL_OPEN_OK, + BTA_GATTC_CANCEL_OPEN_ERROR, + BTA_GATTC_CONN, + BTA_GATTC_START_DISCOVER, + BTA_GATTC_DISC_CMPL, + + BTA_GATTC_Q_CMD, + BTA_GATTC_CLOSE, + BTA_GATTC_CLOSE_FAIL, + BTA_GATTC_READ, + BTA_GATTC_WRITE, + + BTA_GATTC_OP_CMPL, + BTA_GATTC_SEARCH, + BTA_GATTC_FAIL, + BTA_GATTC_CONFIRM, + BTA_GATTC_EXEC, + BTA_GATTC_READ_MULTI, + BTA_GATTC_CI_OPEN, + BTA_GATTC_CI_LOAD, + BTA_GATTC_CI_SAVE, + BTA_GATTC_CACHE_OPEN, + BTA_GATTC_IGNORE_OP_CMPL, + + BTA_GATTC_IGNORE +}; +/* type for action functions */ +typedef void (*tBTA_GATTC_ACTION)(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); + +/* action function list */ +const tBTA_GATTC_ACTION bta_gattc_action[] = +{ + bta_gattc_open, + bta_gattc_open_fail, + //bta_gattc_open_fail_in_conn, //<--- need to remove this? + bta_gattc_open_error, + bta_gattc_cancel_open, + bta_gattc_cancel_open_ok, + bta_gattc_cancel_open_error, + bta_gattc_conn, + bta_gattc_start_discover, + bta_gattc_disc_cmpl, + + bta_gattc_q_cmd, + bta_gattc_close, + bta_gattc_close_fail, + bta_gattc_read, + bta_gattc_write, + + bta_gattc_op_cmpl, + bta_gattc_search, + bta_gattc_fail, + bta_gattc_confirm, + bta_gattc_execute, + bta_gattc_read_multi, + bta_gattc_ci_open, + bta_gattc_ci_load, + bta_gattc_ci_save, + bta_gattc_cache_open, + bta_gattc_ignore_op_cmpl +}; + + +/* state table information */ +#define BTA_GATTC_ACTIONS 1 /* number of actions */ +#define BTA_GATTC_NEXT_STATE 1 /* position of next state */ +#define BTA_GATTC_NUM_COLS 2 /* number of columns in state tables */ + +/* state table for idle state */ +static const UINT8 bta_gattc_st_idle[][BTA_GATTC_NUM_COLS] = +{ +/* Event Action 1 Next state */ +/* BTA_GATTC_API_OPEN_EVT */ {BTA_GATTC_OPEN, BTA_GATTC_W4_CONN_ST}, +/* BTA_GATTC_INT_OPEN_FAIL_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST}, +/* BTA_GATTC_API_CANCEL_OPEN_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST}, +/* BTA_GATTC_INT_CANCEL_OPEN_OK_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST}, + +/* BTA_GATTC_API_READ_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_IDLE_ST}, +/* BTA_GATTC_API_WRITE_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_IDLE_ST}, +/* BTA_GATTC_API_EXEC_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_IDLE_ST}, + +/* BTA_GATTC_API_CLOSE_EVT */ {BTA_GATTC_CLOSE_FAIL, BTA_GATTC_IDLE_ST}, + +/* BTA_GATTC_API_SEARCH_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_IDLE_ST}, +/* BTA_GATTC_API_CONFIRM_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_IDLE_ST}, +/* BTA_GATTC_API_READ_MULTI_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_IDLE_ST}, +/* BTA_GATTC_INT_CONN_EVT */ {BTA_GATTC_CONN, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_INT_DISCOVER_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST}, +/* BTA_GATTC_DISCOVER_CMPL_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST}, +/* BTA_GATTC_OP_CMPL_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST}, +/* BTA_GATTC_INT_DISCONN_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST}, + + +/* ===> for cache loading, saving */ +/* BTA_GATTC_START_CACHE_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST}, +/* BTA_GATTC_CI_CACHE_OPEN_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST}, +/* BTA_GATTC_CI_CACHE_LOAD_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST}, +/* BTA_GATTC_CI_CACHE_SAVE_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST} +}; + +/* state table for wait for open state */ +static const UINT8 bta_gattc_st_w4_conn[][BTA_GATTC_NUM_COLS] = +{ +/* Event Action 1 Next state */ +/* BTA_GATTC_API_OPEN_EVT */ {BTA_GATTC_OPEN, BTA_GATTC_W4_CONN_ST}, +/* BTA_GATTC_INT_OPEN_FAIL_EVT */ {BTA_GATTC_OPEN_FAIL, BTA_GATTC_IDLE_ST}, +/* BTA_GATTC_API_CANCEL_OPEN_EVT */ {BTA_GATTC_CANCEL_OPEN, BTA_GATTC_W4_CONN_ST}, +/* BTA_GATTC_INT_CANCEL_OPEN_OK_EVT */ {BTA_GATTC_CANCEL_OPEN_OK, BTA_GATTC_IDLE_ST}, + +/* BTA_GATTC_API_READ_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_W4_CONN_ST}, +/* BTA_GATTC_API_WRITE_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_W4_CONN_ST}, +/* BTA_GATTC_API_EXEC_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_W4_CONN_ST}, + +/* BTA_GATTC_API_CLOSE_EVT */ {BTA_GATTC_CLOSE_FAIL, BTA_GATTC_W4_CONN_ST}, + +/* BTA_GATTC_API_SEARCH_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_W4_CONN_ST}, +/* BTA_GATTC_API_CONFIRM_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_W4_CONN_ST}, +/* BTA_GATTC_API_READ_MULTI_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_W4_CONN_ST}, + +/* BTA_GATTC_INT_CONN_EVT */ {BTA_GATTC_CONN, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_INT_DISCOVER_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_W4_CONN_ST}, +/* BTA_GATTC_DISCOVER_CMPL_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_W4_CONN_ST}, +/* BTA_GATTC_OP_CMPL_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_W4_CONN_ST}, +/* BTA_GATTC_INT_DISCONN_EVT */ {BTA_GATTC_CLOSE, BTA_GATTC_IDLE_ST}, + +/* ===> for cache loading, saving */ +/* BTA_GATTC_START_CACHE_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_W4_CONN_ST}, +/* BTA_GATTC_CI_CACHE_OPEN_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_W4_CONN_ST}, +/* BTA_GATTC_CI_CACHE_LOAD_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_W4_CONN_ST}, +/* BTA_GATTC_CI_CACHE_SAVE_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_W4_CONN_ST} +}; + +/* state table for open state */ +static const UINT8 bta_gattc_st_connected[][BTA_GATTC_NUM_COLS] = +{ +/* Event Action 1 Next state */ +/* BTA_GATTC_API_OPEN_EVT */ {BTA_GATTC_OPEN_ERROR, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_INT_OPEN_FAIL_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_API_CANCEL_OPEN_EVT */ {BTA_GATTC_CANCEL_OPEN_ERROR, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_INT_CANCEL_OPEN_OK_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_CONN_ST}, + +/* BTA_GATTC_API_READ_EVT */ {BTA_GATTC_READ, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_API_WRITE_EVT */ {BTA_GATTC_WRITE, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_API_EXEC_EVT */ {BTA_GATTC_EXEC, BTA_GATTC_CONN_ST}, + +/* BTA_GATTC_API_CLOSE_EVT */ {BTA_GATTC_CLOSE, BTA_GATTC_IDLE_ST}, //BTA_GATTC_CLOSING_ST + +/* BTA_GATTC_API_SEARCH_EVT */ {BTA_GATTC_SEARCH, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_API_CONFIRM_EVT */ {BTA_GATTC_CONFIRM, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_API_READ_MULTI_EVT */ {BTA_GATTC_READ_MULTI, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_INT_CONN_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_INT_DISCOVER_EVT */ {BTA_GATTC_START_DISCOVER, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_DISCOVER_CMPL_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_OP_CMPL_EVT */ {BTA_GATTC_OP_CMPL, BTA_GATTC_CONN_ST}, + +/* BTA_GATTC_INT_DISCONN_EVT */ {BTA_GATTC_CLOSE, BTA_GATTC_IDLE_ST}, + +/* ===> for cache loading, saving */ +/* BTA_GATTC_START_CACHE_EVT */ {BTA_GATTC_CACHE_OPEN, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_CI_CACHE_OPEN_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_CI_CACHE_LOAD_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_CI_CACHE_SAVE_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_CONN_ST} +}; + +/* state table for discover state */ +static const UINT8 bta_gattc_st_discover[][BTA_GATTC_NUM_COLS] = +{ +/* Event Action 1 Next state */ +/* BTA_GATTC_API_OPEN_EVT */ {BTA_GATTC_OPEN_ERROR, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_INT_OPEN_FAIL_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_API_CANCEL_OPEN_EVT */ {BTA_GATTC_CANCEL_OPEN_ERROR, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_INT_CANCEL_OPEN_OK_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_DISCOVER_ST}, + +/* BTA_GATTC_API_READ_EVT */ {BTA_GATTC_Q_CMD, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_API_WRITE_EVT */ {BTA_GATTC_Q_CMD, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_API_EXEC_EVT */ {BTA_GATTC_Q_CMD, BTA_GATTC_DISCOVER_ST}, + +/* BTA_GATTC_API_CLOSE_EVT */ {BTA_GATTC_CLOSE, BTA_GATTC_IDLE_ST }, //BTA_GATTC_CLOSING_ST + +/* BTA_GATTC_API_SEARCH_EVT */ {BTA_GATTC_Q_CMD, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_API_CONFIRM_EVT */ {BTA_GATTC_CONFIRM, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_API_READ_MULTI_EVT */ {BTA_GATTC_Q_CMD, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_INT_CONN_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_INT_DISCOVER_EVT */ {BTA_GATTC_START_DISCOVER, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_DISCOVER_CMPL_EVT */ {BTA_GATTC_DISC_CMPL, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_OP_CMPL_EVT */ {BTA_GATTC_IGNORE_OP_CMPL, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_INT_DISCONN_EVT */ {BTA_GATTC_CLOSE, BTA_GATTC_IDLE_ST}, + +/* ===> for cache loading, saving */ +/* BTA_GATTC_START_CACHE_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_CI_CACHE_OPEN_EVT */ {BTA_GATTC_CI_OPEN, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_CI_CACHE_LOAD_EVT */ {BTA_GATTC_CI_LOAD, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_CI_CACHE_SAVE_EVT */ {BTA_GATTC_CI_SAVE, BTA_GATTC_DISCOVER_ST} +}; + +/* type for state table */ +typedef const UINT8 (*tBTA_GATTC_ST_TBL)[BTA_GATTC_NUM_COLS]; + +/* state table */ +const tBTA_GATTC_ST_TBL bta_gattc_st_tbl[] = +{ + bta_gattc_st_idle, + bta_gattc_st_w4_conn, + bta_gattc_st_connected, + bta_gattc_st_discover +}; + +/***************************************************************************** +** Global data +*****************************************************************************/ + +/* GATTC control block */ +#if BTA_DYNAMIC_MEMORY == FALSE +tBTA_GATTC_CB bta_gattc_cb; +#endif + +#if BTA_GATT_DEBUG == TRUE +static char *gattc_evt_code(tBTA_GATTC_INT_EVT evt_code); +static char *gattc_state_code(tBTA_GATTC_STATE state_code); +#endif + +/******************************************************************************* +** +** Function bta_gattc_sm_execute +** +** Description State machine event handling function for GATTC +** +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_sm_execute(tBTA_GATTC_CLCB *p_clcb, UINT16 event, tBTA_GATTC_DATA *p_data) +{ + tBTA_GATTC_ST_TBL state_table; + UINT8 action; + int i; +#if BTA_GATT_DEBUG == TRUE + tBTA_GATTC_STATE in_state = p_clcb->state; + UINT16 in_event = event; + APPL_TRACE_DEBUG4("bta_gattc_sm_execute: State 0x%02x [%s], Event 0x%x[%s]", in_state, + gattc_state_code(in_state), + in_event, + gattc_evt_code(in_event)); +#endif + + + /* look up the state table for the current state */ + state_table = bta_gattc_st_tbl[p_clcb->state]; + + event &= 0x00FF; + + /* set next state */ + p_clcb->state = state_table[event][BTA_GATTC_NEXT_STATE]; + + /* execute action functions */ + for (i = 0; i < BTA_GATTC_ACTIONS; i++) + { + if ((action = state_table[event][i]) != BTA_GATTC_IGNORE) + { + (*bta_gattc_action[action])(p_clcb, p_data); + } + else + { + break; + } + } + +#if BTA_GATT_DEBUG == TRUE + if (in_state != p_clcb->state) + { + APPL_TRACE_DEBUG3("GATTC State Change: [%s] -> [%s] after Event [%s]", + gattc_state_code(in_state), + gattc_state_code(p_clcb->state), + gattc_evt_code(in_event)); + } +#endif +} + +/******************************************************************************* +** +** Function bta_gattc_hdl_event +** +** Description GATT client main event handling function. +** +** +** Returns void +** +*******************************************************************************/ +BOOLEAN bta_gattc_hdl_event(BT_HDR *p_msg) +{ + tBTA_GATTC_CB *p_cb = &bta_gattc_cb; + tBTA_GATTC_CLCB *p_clcb = NULL; + +#if BTA_GATT_DEBUG == TRUE + APPL_TRACE_DEBUG1("bta_gattc_hdl_event: Event [%s]", gattc_evt_code(p_msg->event)); +#endif + switch (p_msg->event) + { + case BTA_GATTC_API_REG_EVT: + bta_gattc_register(p_cb, (tBTA_GATTC_DATA *) p_msg); + break; + + case BTA_GATTC_INT_START_IF_EVT: + bta_gattc_start_if(p_cb, (tBTA_GATTC_DATA *) p_msg); + break; + + case BTA_GATTC_API_DEREG_EVT: + bta_gattc_deregister(p_cb, (tBTA_GATTC_DATA *) p_msg); + break; + + case BTA_GATTC_INT_DEREG_EVT: + bta_gattc_int_deregister(p_cb, (tBTA_GATTC_DATA *) p_msg); + break; + + case BTA_GATTC_API_OPEN_EVT: + bta_gattc_process_api_open(p_cb, (tBTA_GATTC_DATA *) p_msg); + break; + + case BTA_GATTC_API_CANCEL_OPEN_EVT: + bta_gattc_process_api_open_cancel(p_cb, (tBTA_GATTC_DATA *) p_msg); + break; + + default: + if ((p_clcb = bta_gattc_find_clcb_by_conn_id(p_msg->layer_specific)) + != NULL) + { + bta_gattc_sm_execute(p_clcb, p_msg->event, (tBTA_GATTC_DATA *) p_msg); + } + else + { + APPL_TRACE_ERROR1("Unknown conn ID: %d", p_msg->layer_specific); + } + + break; + } + + + return(TRUE); +} + + +/***************************************************************************** +** Debug Functions +*****************************************************************************/ +#if BTA_GATT_DEBUG == TRUE + +/******************************************************************************* +** +** Function gattc_evt_code +** +** Description +** +** Returns void +** +*******************************************************************************/ +static char *gattc_evt_code(tBTA_GATTC_INT_EVT evt_code) +{ + switch (evt_code) + { + case BTA_GATTC_API_OPEN_EVT: + return "BTA_GATTC_API_OPEN_EVT"; + case BTA_GATTC_INT_OPEN_FAIL_EVT: + return "BTA_GATTC_INT_OPEN_FAIL_EVT"; + case BTA_GATTC_API_CANCEL_OPEN_EVT: + return "BTA_GATTC_API_CANCEL_OPEN_EVT"; + case BTA_GATTC_INT_CANCEL_OPEN_OK_EVT: + return "BTA_GATTC_INT_CANCEL_OPEN_OK_EVT"; + case BTA_GATTC_API_READ_EVT: + return "BTA_GATTC_API_READ_EVT"; + case BTA_GATTC_API_WRITE_EVT: + return "BTA_GATTC_API_WRITE_EVT"; + case BTA_GATTC_API_EXEC_EVT: + return "BTA_GATTC_API_EXEC_EVT"; + case BTA_GATTC_API_CLOSE_EVT: + return "BTA_GATTC_API_CLOSE_EVT"; + case BTA_GATTC_API_SEARCH_EVT: + return "BTA_GATTC_API_SEARCH_EVT"; + case BTA_GATTC_API_CONFIRM_EVT: + return "BTA_GATTC_API_CONFIRM_EVT"; + case BTA_GATTC_API_READ_MULTI_EVT: + return "BTA_GATTC_API_READ_MULTI_EVT"; + case BTA_GATTC_INT_CONN_EVT: + return "BTA_GATTC_INT_CONN_EVT"; + case BTA_GATTC_INT_DISCOVER_EVT: + return "BTA_GATTC_INT_DISCOVER_EVT"; + case BTA_GATTC_DISCOVER_CMPL_EVT: + return "BTA_GATTC_DISCOVER_CMPL_EVT"; + case BTA_GATTC_OP_CMPL_EVT: + return "BTA_GATTC_OP_CMPL_EVT"; + case BTA_GATTC_INT_DISCONN_EVT: + return "BTA_GATTC_INT_DISCONN_EVT"; + case BTA_GATTC_START_CACHE_EVT: + return "BTA_GATTC_START_CACHE_EVT"; + case BTA_GATTC_CI_CACHE_OPEN_EVT: + return "BTA_GATTC_CI_CACHE_OPEN_EVT"; + case BTA_GATTC_CI_CACHE_LOAD_EVT: + return "BTA_GATTC_CI_CACHE_LOAD_EVT"; + case BTA_GATTC_CI_CACHE_SAVE_EVT: + return "BTA_GATTC_CI_CACHE_SAVE_EVT"; + case BTA_GATTC_INT_START_IF_EVT: + return "BTA_GATTC_INT_START_IF_EVT"; + case BTA_GATTC_API_REG_EVT: + return "BTA_GATTC_API_REG_EVT"; + case BTA_GATTC_API_DEREG_EVT: + return "BTA_GATTC_API_DEREG_EVT"; + + default: + return "unknown GATTC event code"; + } +} + +/******************************************************************************* +** +** Function gattc_state_code +** +** Description +** +** Returns void +** +*******************************************************************************/ +static char *gattc_state_code(tBTA_GATTC_STATE state_code) +{ + switch (state_code) + { + case BTA_GATTC_IDLE_ST: + return "GATTC_IDLE_ST"; + case BTA_GATTC_W4_CONN_ST: + return "GATTC_W4_CONN_ST"; + case BTA_GATTC_CONN_ST: + return "GATTC_CONN_ST"; + case BTA_GATTC_DISCOVER_ST: + return "GATTC_DISCOVER_ST"; + default: + return "unknown GATTC state code"; + } +} + +#endif /* Debug Functions */ +#endif /* BTA_GATT_INCLUDED */ diff --git a/bta/gatt/bta_gattc_utils.c b/bta/gatt/bta_gattc_utils.c new file mode 100644 index 0000000..227129c --- /dev/null +++ b/bta/gatt/bta_gattc_utils.c @@ -0,0 +1,652 @@ +/***************************************************************************** +** +** Name: bta_gattc_utils.c +** +** Description: This file contains the GATT client utility +** function. +** +** Copyright (c) 2003-2010, Broadcom Corp., All Rights Reserved. +** Broadcom Bluetooth Core. Proprietary and confidential. +** +*****************************************************************************/ + +#include "bt_target.h" + +#if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE) + +#include <string.h> +#include "utl.h" +#include "gki.h" +#include "bta_sys.h" +#include "bta_gattc_int.h" +#include "bd.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ + + +static const UINT8 base_uuid[LEN_UUID_128] = {0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +/******************************************************************************* +** +** Function bta_gatt_convert_uuid16_to_uuid128 +** +** Description Convert a 16 bits UUID to be an standard 128 bits one. +** +** Returns TRUE if two uuid match; FALSE otherwise. +** +*******************************************************************************/ +void bta_gatt_convert_uuid16_to_uuid128(UINT8 uuid_128[LEN_UUID_128], UINT16 uuid_16) +{ + UINT8 *p = &uuid_128[LEN_UUID_128 - 4]; + + memcpy (uuid_128, base_uuid, LEN_UUID_128); + + UINT16_TO_STREAM(p, uuid_16); +} +/******************************************************************************* +** +** Function bta_gattc_uuid_compare +** +** Description Compare two UUID to see if they are the same. +** +** Returns TRUE if two uuid match; FALSE otherwise. +** +*******************************************************************************/ +BOOLEAN bta_gattc_uuid_compare (tBT_UUID src, tBT_UUID tar, BOOLEAN is_precise) +{ + UINT8 su[LEN_UUID_128], tu[LEN_UUID_128]; + UINT8 *ps, *pt; + + /* any of the UUID is unspecified */ + if (src.len == 0 || tar.len == 0) + { + if (is_precise) + return FALSE; + else + return TRUE; + } + + /* If both are 16-bit, we can do a simple compare */ + if (src.len == 2 && tar.len == 2) + { + return src.uu.uuid16 == tar.uu.uuid16; + } + + /* One or both of the UUIDs is 128-bit */ + if (src.len == LEN_UUID_16) + { + /* convert a 16 bits UUID to 128 bits value */ + bta_gatt_convert_uuid16_to_uuid128(su, src.uu.uuid16); + ps = su; + } + else + ps = src.uu.uuid128; + + if (tar.len == LEN_UUID_16) + { + /* convert a 16 bits UUID to 128 bits value */ + bta_gatt_convert_uuid16_to_uuid128(tu, tar.uu.uuid16); + pt = tu; + } + else + pt = tar.uu.uuid128; + + return(memcmp(ps, pt, LEN_UUID_128) == 0); +} + +/******************************************************************************* +** +** Function bta_gattc_cl_get_regcb +** +** Description get registration control block by client interface. +** +** Returns pointer to the regcb +** +*******************************************************************************/ +tBTA_GATTC_RCB * bta_gattc_cl_get_regcb(UINT8 client_if) +{ + UINT8 i = 0; + tBTA_GATTC_RCB *p_clrcb = &bta_gattc_cb.cl_rcb[0]; + + for (i = 0; i < BTA_GATTC_CL_MAX; i ++, p_clrcb ++) + { + if (p_clrcb->in_use && + p_clrcb->client_if == client_if) + return p_clrcb; + } + return NULL; +} +/******************************************************************************* +** +** Function bta_gattc_num_reg_app +** +** Description find the number of registered application. +** +** Returns pointer to the regcb +** +*******************************************************************************/ +UINT8 bta_gattc_num_reg_app(void) +{ + UINT8 i = 0, j = 0; + + for (i = 0; i < BTA_GATTC_CL_MAX; i ++) + { + if (bta_gattc_cb.cl_rcb[i].in_use) + j ++; + } + return j; +} +/******************************************************************************* +** +** Function bta_gattc_find_clcb_by_cif +** +** Description get clcb by client interface and remote bd adddress +** +** Returns pointer to the clcb +** +*******************************************************************************/ +tBTA_GATTC_CLCB * bta_gattc_find_clcb_by_cif (UINT8 client_if, BD_ADDR remote_bda) +{ + tBTA_GATTC_CLCB *p_clcb = &bta_gattc_cb.clcb[0]; + UINT8 i; + + for (i = 0; i < BTA_GATTC_CLCB_MAX; i ++, p_clcb ++) + { + if (p_clcb->in_use && + p_clcb->p_rcb->client_if == client_if && + p_clcb->p_srcb && + bdcmp(p_clcb->p_srcb->server_bda, remote_bda) == 0) + return p_clcb; + } + return NULL; +} +/******************************************************************************* +** +** Function bta_gattc_find_clcb_by_conn_id +** +** Description get clcb by connection ID +** +** Returns pointer to the clcb +** +*******************************************************************************/ +tBTA_GATTC_CLCB * bta_gattc_find_clcb_by_conn_id (UINT16 conn_id) +{ + tBTA_GATTC_CLCB *p_clcb = &bta_gattc_cb.clcb[0]; + UINT8 i; + + for (i = 0; i < BTA_GATTC_CLCB_MAX; i ++, p_clcb ++) + { + if (p_clcb->in_use && + p_clcb->bta_conn_id == conn_id) + return p_clcb; + } + return NULL; +} + +/******************************************************************************* +** +** Function bta_gattc_clcb_alloc +** +** Description allocate CLCB +** +** Returns pointer to the clcb +** +*******************************************************************************/ +tBTA_GATTC_CLCB * bta_gattc_clcb_alloc(tBTA_GATTC_IF client_if, BD_ADDR remote_bda) +{ + UINT8 i_clcb = 0; + tBTA_GATTC_CLCB *p_clcb = NULL; + + for (i_clcb = 0; i_clcb < BTA_GATTC_CLCB_MAX; i_clcb++) + { + if (!bta_gattc_cb.clcb[i_clcb].in_use) + { +#if BTA_GATT_DEBUG == TRUE + APPL_TRACE_DEBUG1("bta_gattc_clcb_alloc: found clcb[%d] available",i_clcb); +#endif + p_clcb = &bta_gattc_cb.clcb[i_clcb]; + p_clcb->in_use = TRUE; + bdcpy(p_clcb->bda, remote_bda); + + p_clcb->p_rcb = bta_gattc_cl_get_regcb(client_if); + + if ((p_clcb->p_srcb = bta_gattc_find_srcb(remote_bda)) == NULL) + p_clcb->p_srcb = bta_gattc_srcb_alloc(remote_bda); + + if (p_clcb->p_rcb != NULL && p_clcb->p_srcb != NULL) + { + p_clcb->p_srcb->num_clcb ++; + p_clcb->p_rcb->num_clcb ++; + } + else + { + /* release this clcb if clcb or srcb allocation failed */ + p_clcb->in_use = FALSE; + p_clcb = NULL; + } + break; + } + } + return p_clcb; +} +/******************************************************************************* +** +** Function bta_gattc_find_alloc_clcb +** +** Description find or allocate CLCB if not found. +** +** Returns pointer to the clcb +** +*******************************************************************************/ +tBTA_GATTC_CLCB *bta_gattc_find_alloc_clcb(tBTA_GATTC_IF client_if, BD_ADDR remote_bda) +{ + tBTA_GATTC_CLCB *p_clcb ; + + if ((p_clcb = bta_gattc_find_clcb_by_cif(client_if, remote_bda)) == NULL) + { + p_clcb = bta_gattc_clcb_alloc(client_if, remote_bda); + } + return p_clcb; +} + +/******************************************************************************* +** +** Function bta_gattc_clcb_dealloc +** +** Description Deallocte a clcb +** +** Returns pointer to the clcb +** +*******************************************************************************/ +void bta_gattc_clcb_dealloc(tBTA_GATTC_CLCB *p_clcb) +{ + + if (p_clcb) + { + if (p_clcb->p_srcb->num_clcb) + p_clcb->p_srcb->num_clcb --; + + if (p_clcb->p_rcb->num_clcb) + p_clcb->p_rcb->num_clcb --; + + utl_freebuf((void **)&p_clcb->p_q_cmd); + + APPL_TRACE_ERROR2("bta_gattc_clcb_dealloc in_use=%d conn_id=%d",p_clcb->in_use, p_clcb->bta_conn_id); + memset(p_clcb, 0, sizeof(tBTA_GATTC_CLCB)); + } + else + { + APPL_TRACE_ERROR0("bta_gattc_clcb_dealloc p_clcb=NULL"); + } +} + +/******************************************************************************* +** +** Function bta_gattc_find_srcb +** +** Description find server cache by remote bd address +** +** Returns pointer to the server cache. +** +*******************************************************************************/ +tBTA_GATTC_SERV * bta_gattc_find_srcb(BD_ADDR bda) +{ + tBTA_GATTC_SERV *p_srcb = &bta_gattc_cb.known_server[0]; + UINT8 i; + + for (i = 0; i < BTA_GATTC_KNOWN_SR_MAX; i ++, p_srcb ++) + { + if (p_srcb->in_use && bdcmp(p_srcb->server_bda, bda) == 0) + return p_srcb; + } + return NULL; +} +/******************************************************************************* +** +** Function bta_gattc_find_scb_by_cid +** +** Description find server control block by connection ID +** +** Returns pointer to the server cache. +** +*******************************************************************************/ +tBTA_GATTC_SERV * bta_gattc_find_scb_by_cid (UINT16 conn_id) +{ + tBTA_GATTC_CLCB *p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id); + + if (p_clcb) + return p_clcb->p_srcb; + else + return NULL; +} +/******************************************************************************* +** +** Function bta_gattc_srcb_alloc +** +** Description allocate server cache control block +** +** Returns pointer to the server cache. +** +*******************************************************************************/ +tBTA_GATTC_SERV * bta_gattc_srcb_alloc(BD_ADDR bda) +{ + tBTA_GATTC_SERV *p_tcb = &bta_gattc_cb.known_server[0], + *p_recycle = NULL; + BOOLEAN found = FALSE; + UINT8 i; + + for (i = 0; i < BTA_GATTC_KNOWN_SR_MAX; i ++, p_tcb ++) + { + if (!p_tcb->in_use) + { + found = TRUE; + break; + } + else if (!p_tcb->connected) + { + p_recycle = p_tcb; + } + } + + /* if not found, try to recycle one known device */ + if (!found && !p_recycle) + p_tcb = NULL; + else if (p_recycle) + p_tcb = p_recycle; + + if (p_tcb != NULL) + { + while (p_tcb->cache_buffer.p_first) + GKI_freebuf (GKI_dequeue (&p_tcb->cache_buffer)); + + utl_freebuf((void **)&p_tcb->p_srvc_list); + memset(p_tcb, 0 , sizeof(tBTA_GATTC_SERV)); + + p_tcb->in_use = TRUE; + bdcpy(p_tcb->server_bda, bda); + } + return p_tcb; +} +/******************************************************************************* +** +** Function bta_gattc_enqueue +** +** Description enqueue a client request in clcb. +** +** Returns success or failure. +** +*******************************************************************************/ +BOOLEAN bta_gattc_enqueue(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + BOOLEAN in_q = FALSE; + + if (p_clcb->p_q_cmd == NULL) + { + p_clcb->p_q_cmd = (tBTA_GATTC_DATA *)GKI_getbuf(sizeof(tBTA_GATTC_DATA)); + + if (p_data) + memcpy(p_clcb->p_q_cmd, p_data, sizeof(tBTA_GATTC_DATA)); + + in_q = TRUE; + } + else + { + APPL_TRACE_ERROR0("already has a pending command!!"); + /* skip the callback now. ----- need to send callback ? */ + } + return in_q; +} +/******************************************************************************* +** +** Function bta_gattc_pack_attr_uuid +** +** Description pack UUID into a stream. +** +** Returns +** +*******************************************************************************/ +void bta_gattc_pack_attr_uuid(tBTA_GATTC_CACHE_ATTR *p_attr, tBT_UUID *p_uuid) +{ + UINT8 *pp = (UINT8 *)p_attr->p_uuid; + + memset(p_uuid, 0, sizeof(tBT_UUID)); + + p_uuid->len = p_attr->uuid_len; + + if (p_attr->uuid_len == LEN_UUID_16) + { + STREAM_TO_UINT16(p_uuid->uu.uuid16, pp); + } + else + { + memcpy(p_uuid->uu.uuid128, pp, LEN_UUID_128); + } + + return; +} +/******************************************************************************* +** +** Function bta_gattc_check_notif_registry +** +** Description check if the service notificaition has been registered. +** +** Returns +** +*******************************************************************************/ +BOOLEAN bta_gattc_check_notif_registry(tBTA_GATTC_RCB *p_clreg, tBTA_GATTC_SERV *p_srcb, + tBTA_GATTC_NOTIFY *p_notify) +{ + UINT8 i; + + for (i = 0 ; i < BTA_GATTC_NOTIF_REG_MAX; i ++) + { + if (p_clreg->notif_reg[i].in_use && + bdcmp(p_clreg->notif_reg[i].remote_bda, p_srcb->server_bda) == 0 && + (bta_gattc_uuid_compare(p_clreg->notif_reg[i].char_id.srvc_id.id.uuid, p_notify->char_id.srvc_id.id.uuid, FALSE) && + p_clreg->notif_reg[i].char_id.srvc_id.id.inst_id == p_notify->char_id.srvc_id.id.inst_id && + p_clreg->notif_reg[i].char_id.srvc_id.is_primary == p_notify->char_id.srvc_id.is_primary && + bta_gattc_uuid_compare(p_clreg->notif_reg[i].char_id.char_id.uuid, p_notify->char_id.char_id.uuid, FALSE) && + p_clreg->notif_reg[i].char_id.char_id.inst_id == p_notify->char_id.char_id.inst_id) + ) + { + APPL_TRACE_DEBUG0("Notification registered!"); + return TRUE; + } + } + return FALSE; + +} +/******************************************************************************* +** +** Function bta_gattc_clear_notif_registration +** +** Description clear up the notification registration information by BD_ADDR. +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_clear_notif_registration(UINT16 conn_id) +{ + BD_ADDR remote_bda; + tBTA_GATTC_IF gatt_if; + tBTA_GATTC_RCB *p_clrcb ; + UINT8 i; + + if (GATT_GetConnectionInfor(conn_id, &gatt_if, remote_bda)) + { + if ((p_clrcb = bta_gattc_cl_get_regcb(gatt_if)) != NULL) + { + for (i = 0 ; i < BTA_GATTC_NOTIF_REG_MAX; i ++) + { + if (p_clrcb->notif_reg[i].in_use && !bdcmp(p_clrcb->notif_reg[i].remote_bda, remote_bda)) + memset(&p_clrcb->notif_reg[i], 0, sizeof(tBTA_GATTC_NOTIF_REG)); + } + } + } + else + { + APPL_TRACE_ERROR0("can not clear indication/notif registration for unknown app"); + } + return; +} + +/******************************************************************************* +** +** Function bta_gattc_pack_cb_data +** +** Description pack the data from read response into callback data structure. +** +** Returns +** +*******************************************************************************/ +tBTA_GATT_STATUS bta_gattc_pack_read_cb_data(tBTA_GATTC_SERV *p_srcb, tBT_UUID descr_uuid, + tGATT_VALUE *p_attr, tBTA_GATT_READ_VAL *p_value) +{ + UINT8 i = 0, *pp = p_attr->value; + tBT_UUID uuid = {LEN_UUID_16, {GATT_UUID_CHAR_AGG_FORMAT}}; + UINT16 handle; + tBTA_GATT_STATUS status = BTA_GATT_OK; + + /* GATT_UUID_CHAR_AGG_FORMAT */ + if (bta_gattc_uuid_compare (uuid, descr_uuid, TRUE)) + { + while (p_attr->len >= 2 && i < BTA_GATTC_MULTI_MAX) + { + STREAM_TO_UINT16(handle, pp); + + if (bta_gattc_handle2id(p_srcb, + handle, + &p_value->aggre_value.pre_format[i].char_id.srvc_id, + &p_value->aggre_value.pre_format[i].char_id.char_id, + &p_value->aggre_value.pre_format[i].descr_type) == FALSE) + { + status = BTA_GATT_INTERNAL_ERROR; + APPL_TRACE_ERROR1("can not map to GATT ID. handle = 0x%04x", handle); + break; + } + i ++; + p_attr->len -= 2; + } + p_value->aggre_value.num_pres_fmt = i; + } + else + { + /* all others, take as raw format */ + p_value->unformat.len = p_attr->len; + p_value->unformat.p_value = p_attr->value; + } + return status; +} +/******************************************************************************* +** +** Function bta_gattc_mark_bg_conn +** +** Description mark background connection status when a bg connection is initiated +** or terminated. +** +** Returns TRUE if success; FALSE otherwise. +** +*******************************************************************************/ +BOOLEAN bta_gattc_mark_bg_conn (tBTA_GATTC_IF client_if, BD_ADDR remote_bda, BOOLEAN add) +{ + tBTA_GATTC_BG_TCK *p_bg_tck = &bta_gattc_cb.bg_track[0]; + UINT8 i = 0; + + for (i = 0; i < BTA_GATTC_KNOWN_SR_MAX; i ++, p_bg_tck ++) + { + if (p_bg_tck->in_use && + bdcmp(p_bg_tck->remote_bda, remote_bda) == 0) + { + if (add) + /* mask on the cif bit */ + p_bg_tck->cif_mask |= (1 <<(client_if - 1)); + else + p_bg_tck->cif_mask &= (~(1 <<(client_if - 1))); + + return TRUE; + } + } + if (!add) + { + APPL_TRACE_ERROR0("Do not find the bg connection mask for the remote device"); + return FALSE; + } + else /* adding a new device mask */ + { + for (i = 0, p_bg_tck = &bta_gattc_cb.bg_track[0]; + i < BTA_GATTC_KNOWN_SR_MAX; i ++, p_bg_tck ++) + { + if (!p_bg_tck->in_use) + { + p_bg_tck->in_use = TRUE; + bdcpy(p_bg_tck->remote_bda, remote_bda); + p_bg_tck->cif_mask = (1 <<(client_if - 1)); + return TRUE; + } + } + APPL_TRACE_ERROR0("no available space to mark the bg connection status"); + return FALSE; + } +} +/******************************************************************************* +** +** Function bta_gattc_check_bg_conn +** +** Description check if this is a background connection background connection. +** +** Returns TRUE if success; FALSE otherwise. +** +*******************************************************************************/ +BOOLEAN bta_gattc_check_bg_conn (tBTA_GATTC_IF client_if, BD_ADDR remote_bda) +{ + tBTA_GATTC_BG_TCK *p_bg_tck = &bta_gattc_cb.bg_track[0]; + UINT8 i = 0; + BOOLEAN is_bg_conn = FALSE; + + for (i = 0; i < BTA_GATTC_KNOWN_SR_MAX; i ++, p_bg_tck ++) + { + if (p_bg_tck->in_use && + bdcmp(p_bg_tck->remote_bda, remote_bda) == 0) + { + if ((p_bg_tck->cif_mask &(1 <<(client_if - 1))) != 0) + is_bg_conn = TRUE; + break; + } + } + return is_bg_conn; +} +/******************************************************************************* +** +** Function bta_gattc_send_open_cback +** +** Description send open callback +** +** Returns +** +*******************************************************************************/ +void bta_gattc_send_open_cback( tBTA_GATTC_RCB *p_clreg, tBTA_GATT_STATUS status, + BD_ADDR remote_bda, UINT16 conn_id) +{ + tBTA_GATTC cb_data; + + if (p_clreg->p_cback) + { + memset(&cb_data, 0, sizeof(tBTA_GATTC)); + + cb_data.open.status = status; + cb_data.open.client_if = p_clreg->client_if; + cb_data.open.conn_id = conn_id; + bdcpy(cb_data.open.remote_bda, remote_bda); + + (*p_clreg->p_cback)(BTA_GATTC_OPEN_EVT, &cb_data); + } +} + + + + + +#endif /* BTA_GATT_INCLUDED */ diff --git a/bta/gatt/bta_gatts_act.c b/bta/gatt/bta_gatts_act.c new file mode 100644 index 0000000..cb56a32 --- /dev/null +++ b/bta/gatt/bta_gatts_act.c @@ -0,0 +1,785 @@ +/***************************************************************************** +** +** Name: bta_gatts_act.c +** +** Description: This file contains the GATT Server action +** functions for the state machine. +** +** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved. +** Broadcom Bluetooth Core. Proprietary and confidential. +** +*****************************************************************************/ + + +#include "bt_target.h" + +#if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE) + +#include "utl.h" +#include "gki.h" +#include "bta_sys.h" +#include "bta_gatts_int.h" +#include "bta_gatts_co.h" + +#include <string.h> + +static void bta_gatts_nv_save_cback(BOOLEAN is_saved, tGATTS_HNDL_RANGE *p_hndl_range); +static BOOLEAN bta_gatts_nv_srv_chg_cback(tGATTS_SRV_CHG_CMD cmd, tGATTS_SRV_CHG_REQ *p_req, tGATTS_SRV_CHG_RSP *p_rsp); + +static void bta_gatts_conn_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id, BOOLEAN connected, tGATT_DISCONN_REASON reason); +static void bta_gatts_send_request_cback (UINT16 conn_id, + UINT32 trans_id, + tGATTS_REQ_TYPE req_type, tGATTS_DATA *p_data); +static tGATT_CBACK bta_gatts_cback = +{ + bta_gatts_conn_cback, + NULL, + NULL, + NULL, + bta_gatts_send_request_cback +}; + +tGATT_APPL_INFO bta_gatts_nv_cback = +{ + bta_gatts_nv_save_cback, + bta_gatts_nv_srv_chg_cback +}; + +/******************************************************************************* +** +** Function bta_gatts_nv_save_cback +** +** Description NV save callback function. +** +** Parameter is_add: true is to add a handle range; otherwise is to delete. +** Returns none. +** +*******************************************************************************/ +static void bta_gatts_nv_save_cback(BOOLEAN is_add, tGATTS_HNDL_RANGE *p_hndl_range) +{ + bta_gatts_co_update_handle_range(is_add, (tBTA_GATTS_HNDL_RANGE *)p_hndl_range); +} + + +/******************************************************************************* +** +** Function bta_gatts_nv_srv_chg_cback +** +** Description NV save callback function. +** +** Parameter is_add: true is to add a handle range; otherwise is to delete. +** Returns none. +** +*******************************************************************************/ +static BOOLEAN bta_gatts_nv_srv_chg_cback(tGATTS_SRV_CHG_CMD cmd, tGATTS_SRV_CHG_REQ *p_req, tGATTS_SRV_CHG_RSP *p_rsp) +{ + return bta_gatts_co_srv_chg((tBTA_GATTS_SRV_CHG_CMD) cmd, + (tBTA_GATTS_SRV_CHG_REQ *) p_req, + (tBTA_GATTS_SRV_CHG_RSP *) p_rsp); +} + + +/******************************************************************************* +** +** Function bta_gatts_enable +** +** Description enable BTA GATTS module. +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_enable(tBTA_GATTS_CB *p_cb) +{ + UINT8 index=0; + tBTA_GATTS_HNDL_RANGE handle_range; + + p_cb->enabled = TRUE; + + APPL_TRACE_DEBUG0("bta_gatts_enable"); + while ( bta_gatts_co_load_handle_range(index, &handle_range)) + { + GATTS_AddHandleRange((tGATTS_HNDL_RANGE *)&handle_range); + memset(&handle_range, 0, sizeof(tGATTS_HNDL_RANGE)); + index++; + } + + APPL_TRACE_DEBUG1("bta_gatts_enable: num of handle range added=%d", index); + + if (!GATTS_NVRegister(&bta_gatts_nv_cback)) + { + APPL_TRACE_ERROR0("BTA GATTS NV register failed."); + } +} +/******************************************************************************* +** +** Function bta_gatts_register +** +** Description register an application. +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_register(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA *p_msg) +{ + tBTA_GATTS_INT_START_IF *p_buf; + tBTA_GATTS cb_data; + tBTA_GATT_STATUS status = BTA_GATT_OK; + UINT8 i, first_unuse = 0xff; + + if (!p_cb->enabled) + bta_gatts_enable(p_cb); + + + for (i = 0; i < BTA_GATTS_MAX_APP_NUM; i ++) + { + if (p_cb->rcb[i].in_use) + { + if (bta_gatts_uuid_compare(p_cb->rcb[i].app_uuid, p_msg->api_reg.app_uuid)) + { + APPL_TRACE_ERROR0("application already registered."); + status = BTA_GATT_DUP_REG; + break; + } + } + } + + if (status == BTA_GATT_OK) + { + for (i = 0; i < BTA_GATTS_MAX_APP_NUM; i ++) + { + if (first_unuse == 0xff && !p_cb->rcb[i].in_use) + { + first_unuse = i; + break; + } + } + + cb_data.reg_oper.server_if = BTA_GATTS_INVALID_IF; +// btla-specific ++ + memcpy(&cb_data.reg_oper.uuid, &p_msg->api_reg.app_uuid, sizeof(tBT_UUID)); +// btla-specific -- + if (first_unuse != 0xff) + { + APPL_TRACE_ERROR1("register application first_unuse rcb_idx = %d", first_unuse); + + p_cb->rcb[first_unuse].in_use = TRUE; + p_cb->rcb[first_unuse].p_cback = p_msg->api_reg.p_cback; + memcpy(&p_cb->rcb[first_unuse].app_uuid, &p_msg->api_reg.app_uuid, sizeof(tBT_UUID)); + cb_data.reg_oper.server_if = + p_cb->rcb[first_unuse].gatt_if = GATT_Register(&p_msg->api_reg.app_uuid, &bta_gatts_cback); + if ( !p_cb->rcb[first_unuse].gatt_if) + { + status = BTA_GATT_NO_RESOURCES; + } + else + { + if ((p_buf = (tBTA_GATTS_INT_START_IF *) GKI_getbuf(sizeof(tBTA_GATTS_INT_START_IF))) != NULL) + { + p_buf->hdr.event = BTA_GATTS_INT_START_IF_EVT; + p_buf->server_if = p_cb->rcb[first_unuse].gatt_if; + + bta_sys_sendmsg(p_buf); + } + else + { + status = BTA_GATT_NO_RESOURCES; + memset( &p_cb->rcb[first_unuse], 0 , sizeof(tBTA_GATTS_RCB)); + } + } + } + else + { + status = BTA_GATT_NO_RESOURCES; + } + + } + cb_data.reg_oper.status = status; + if (p_msg->api_reg.p_cback) + (*p_msg->api_reg.p_cback)(BTA_GATTS_REG_EVT, &cb_data); +} + + +/******************************************************************************* +** +** Function bta_gatts_start_if +** +** Description start an application interface. +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_start_if(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA *p_msg) +{ + if (bta_gatts_find_app_rcb_by_app_if(p_msg->int_start_if.server_if)) + { + GATT_StartIf(p_msg->int_start_if.server_if); + } + else + { + APPL_TRACE_ERROR1("Unable to start app.: Unknown interface =%d",p_msg->int_start_if.server_if ); + } +} +/******************************************************************************* +** +** Function bta_gatts_deregister +** +** Description deregister an application. +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_deregister(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA *p_msg) +{ + tBTA_GATT_STATUS status = BTA_GATT_ERROR; + tBTA_GATTS_CBACK *p_cback = NULL; + UINT8 i; + tBTA_GATTS cb_data; + + cb_data.reg_oper.server_if = p_msg->api_dereg.server_if; + cb_data.reg_oper.status = status; + + for (i = 0; i < BTA_GATTS_MAX_APP_NUM; i ++) + { + if (p_cb->rcb[i].in_use && p_cb->rcb[i].gatt_if == p_msg->api_dereg.server_if) + { + p_cback = p_cb->rcb[i].p_cback; + status = BTA_GATT_OK; + + /* deregister the app */ + GATT_Deregister(p_cb->rcb[i].gatt_if); + + /* reset cb */ + memset(&p_cb->rcb[i], 0, sizeof(tBTA_GATTS_RCB)); + cb_data.reg_oper.status = status; + break; + } + } + + if (p_cback) + { + (*p_cback)(BTA_GATTS_DEREG_EVT, &cb_data); + } + else + { + APPL_TRACE_ERROR0("application not registered."); + } +} +/******************************************************************************* +** +** Function bta_gatts_create_srvc +** +** Description action function to create a service. +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_create_srvc(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg) +{ + UINT8 rcb_idx; + tBTA_GATTS cb_data; + UINT8 srvc_idx; + UINT16 service_id = 0; + //tBTA_GATTS_HNDL_RANGE handle_range; + + cb_data.create.status = BTA_GATT_ERROR; + + rcb_idx = bta_gatts_find_app_rcb_idx_by_app_if(p_cb, p_msg->api_create_svc.server_if); + + APPL_TRACE_ERROR1("create service rcb_idx = %d", rcb_idx); + + if (rcb_idx != BTA_GATTS_INVALID_APP) + { + if ((srvc_idx = bta_gatts_alloc_srvc_cb(p_cb, rcb_idx)) != BTA_GATTS_INVALID_APP) + { + /* create the service now */ + service_id = GATTS_CreateService (p_cb->rcb[rcb_idx].gatt_if, + &p_msg->api_create_svc.service_uuid, + p_msg->api_create_svc.inst, + p_msg->api_create_svc.num_handle, + p_msg->api_create_svc.is_pri); + + if (service_id != 0) + { + memcpy(&p_cb->srvc_cb[srvc_idx].service_uuid, &p_msg->api_create_svc.service_uuid, sizeof(tBT_UUID)); + p_cb->srvc_cb[srvc_idx].service_id = service_id; + p_cb->srvc_cb[srvc_idx].inst_num = p_msg->api_create_svc.inst; + p_cb->srvc_cb[srvc_idx].idx = srvc_idx; + + cb_data.create.status = BTA_GATT_OK; + cb_data.create.service_id = service_id; +// btla-specific ++ + cb_data.create.is_primary = p_msg->api_create_svc.is_pri; +// btla-specific -- + cb_data.create.server_if = p_cb->rcb[rcb_idx].gatt_if; + } + else + { + cb_data.status = BTA_GATT_ERROR; + memset(&p_cb->srvc_cb[srvc_idx], 0, sizeof(tBTA_GATTS_SRVC_CB)); + APPL_TRACE_ERROR0("service creation failed."); + } +// btla-specific ++ + memcpy(&cb_data.create.uuid, &p_msg->api_create_svc.service_uuid, sizeof(tBT_UUID)); + cb_data.create.svc_instance= p_msg->api_create_svc.inst; +// btla-specific -- + } + if (p_cb->rcb[rcb_idx].p_cback) + (* p_cb->rcb[rcb_idx].p_cback)(BTA_GATTS_CREATE_EVT, &cb_data); + } + else /* application not registered */ + { + APPL_TRACE_ERROR0("Application not registered"); + } +} +/******************************************************************************* +** +** Function bta_gatts_add_include_srvc +** +** Description action function to add an included service. +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_add_include_srvc(tBTA_GATTS_SRVC_CB *p_srvc_cb,tBTA_GATTS_DATA * p_msg) +{ + tBTA_GATTS_RCB *p_rcb = &bta_gatts_cb.rcb[p_srvc_cb->rcb_idx]; + UINT16 attr_id = 0; + tBTA_GATTS cb_data; + + attr_id = GATTS_AddIncludeService(p_msg->api_add_incl_srvc.hdr.layer_specific, + p_msg->api_add_incl_srvc.included_service_id); + + cb_data.add_result.server_if = p_rcb->gatt_if; + cb_data.add_result.service_id = p_msg->api_add_incl_srvc.hdr.layer_specific; + cb_data.add_result.attr_id = attr_id; + + if (attr_id) + { + cb_data.add_result.status = BTA_GATT_OK; + } + else + { + cb_data.add_result.status = BTA_GATT_ERROR; + } + + if (p_rcb->p_cback) + (*p_rcb->p_cback)(BTA_GATTS_ADD_INCL_SRVC_EVT, &cb_data); +} +/******************************************************************************* +** +** Function bta_gatts_add_char +** +** Description action function to add characteristic. +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_add_char(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA * p_msg) +{ + tBTA_GATTS_RCB *p_rcb = &bta_gatts_cb.rcb[p_srvc_cb->rcb_idx]; + UINT16 attr_id = 0; + tBTA_GATTS cb_data; + + attr_id = GATTS_AddCharacteristic(p_msg->api_add_char.hdr.layer_specific, + &p_msg->api_add_char.char_uuid, + p_msg->api_add_char.perm, + p_msg->api_add_char.property); + cb_data.add_result.server_if = p_rcb->gatt_if; + cb_data.add_result.service_id = p_msg->api_add_incl_srvc.hdr.layer_specific; + cb_data.add_result.attr_id = attr_id; +// btla-specific ++ + memcpy(&cb_data.add_result.char_uuid, &p_msg->api_add_char.char_uuid, sizeof(tBT_UUID)); +// btla-specific -- + + if (attr_id) + { + cb_data.add_result.status = BTA_GATT_OK; + } + else + { + cb_data.add_result.status = BTA_GATT_ERROR; + } + + if (p_rcb->p_cback) + (*p_rcb->p_cback)(BTA_GATTS_ADD_CHAR_EVT, &cb_data); +} +/******************************************************************************* +** +** Function bta_gatts_add_char_descr +** +** Description action function to add characteristic descriptor. +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_add_char_descr(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA * p_msg) +{ + tBTA_GATTS_RCB *p_rcb = &bta_gatts_cb.rcb[p_srvc_cb->rcb_idx]; + UINT16 attr_id = 0; + tBTA_GATTS cb_data; + + attr_id = GATTS_AddCharDescriptor(p_msg->api_add_char_descr.hdr.layer_specific, + p_msg->api_add_char_descr.perm, + &p_msg->api_add_char_descr.descr_uuid); + + cb_data.add_result.server_if = p_rcb->gatt_if; + cb_data.add_result.service_id = p_msg->api_add_incl_srvc.hdr.layer_specific; + cb_data.add_result.attr_id = attr_id; +// btla-specific ++ + memcpy(&cb_data.add_result.char_uuid, &p_msg->api_add_char_descr.descr_uuid, sizeof(tBT_UUID)); +// btla-specific -- + + if (attr_id) + { + cb_data.add_result.status = BTA_GATT_OK; + } + else + { + cb_data.add_result.status = BTA_GATT_ERROR; + } + + if (p_rcb->p_cback) + (*p_rcb->p_cback)(BTA_GATTS_ADD_CHAR_DESCR_EVT, &cb_data); + +} +/******************************************************************************* +** +** Function bta_gatts_delete_service +** +** Description action function to delete a service. +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_delete_service(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA * p_msg) +{ + tBTA_GATTS_RCB *p_rcb = &bta_gatts_cb.rcb[p_srvc_cb->rcb_idx]; + tBTA_GATTS cb_data; + + cb_data.srvc_oper.server_if = p_rcb->gatt_if; + cb_data.srvc_oper.service_id = p_msg->api_add_incl_srvc.hdr.layer_specific; + + if (GATTS_DeleteService(p_rcb->gatt_if, + &p_srvc_cb->service_uuid, + p_srvc_cb->inst_num)) + { + cb_data.srvc_oper.status = BTA_GATT_OK; + memset(p_srvc_cb, 0, sizeof(tBTA_GATTS_SRVC_CB)); + } + else + { + cb_data.srvc_oper.status = BTA_GATT_ERROR; + } + + if (p_rcb->p_cback) + (*p_rcb->p_cback)(BTA_GATTS_DELELTE_EVT, &cb_data); + +} +/******************************************************************************* +** +** Function bta_gatts_start_service +** +** Description action function to start a service. +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_start_service(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA * p_msg) +{ + tBTA_GATTS_RCB *p_rcb = &bta_gatts_cb.rcb[p_srvc_cb->rcb_idx]; + tBTA_GATTS cb_data; + + cb_data.srvc_oper.server_if = p_rcb->gatt_if; + cb_data.srvc_oper.service_id = p_msg->api_add_incl_srvc.hdr.layer_specific; + + if (GATTS_StartService(p_rcb->gatt_if, + p_srvc_cb->service_id, + p_msg->api_start.transport) == GATT_SUCCESS) + { + APPL_TRACE_DEBUG1("bta_gatts_start_service service_id= %d", p_srvc_cb->service_id); + cb_data.srvc_oper.status = BTA_GATT_OK; + } + else + { + cb_data.srvc_oper.status = BTA_GATT_ERROR; + } + + if (p_rcb->p_cback) + (*p_rcb->p_cback)(BTA_GATTS_START_EVT, &cb_data); + +} +/******************************************************************************* +** +** Function bta_gatts_stop_service +** +** Description action function to stop a service. +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_stop_service(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA * p_msg) +{ + tBTA_GATTS_RCB *p_rcb = &bta_gatts_cb.rcb[p_srvc_cb->rcb_idx]; + tBTA_GATTS cb_data; + + GATTS_StopService(p_srvc_cb->service_id); + cb_data.srvc_oper.server_if = p_rcb->gatt_if; + cb_data.srvc_oper.service_id = p_srvc_cb->service_id; + cb_data.srvc_oper.status = BTA_GATT_OK; + APPL_TRACE_ERROR1("bta_gatts_stop_service service_id= %d", p_srvc_cb->service_id); + + if (p_rcb->p_cback) + (*p_rcb->p_cback)(BTA_GATTS_STOP_EVT, &cb_data); + +} +/******************************************************************************* +** +** Function bta_gatts_send_rsp +** +** Description GATTS send response. +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_send_rsp (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg) +{ + + if (GATTS_SendRsp (p_msg->api_rsp.hdr.layer_specific, + p_msg->api_rsp.trans_id, + p_msg->api_rsp.status, + (tGATTS_RSP *)p_msg->api_rsp.p_rsp) != GATT_SUCCESS) + { + APPL_TRACE_ERROR0("Sending response failed"); + } + +} +/******************************************************************************* +** +** Function bta_gatts_send_rsp +** +** Description GATTS send response. +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_indicate_handle (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg) +{ + tBTA_GATTS_SRVC_CB *p_srvc_cb; + tBTA_GATT_STATUS status; + + + p_srvc_cb = bta_gatts_find_srvc_cb_by_attr_id (p_cb, p_msg->api_indicate.attr_id); + + if (p_srvc_cb ) + { + if (p_msg->api_indicate.need_confirm) + + status = GATTS_HandleValueIndication (p_msg->api_indicate.hdr.layer_specific, + p_msg->api_indicate.attr_id, + p_msg->api_indicate.len, + p_msg->api_indicate.value); + else + status = GATTS_HandleValueNotification (p_msg->api_indicate.hdr.layer_specific, + p_msg->api_indicate.attr_id, + p_msg->api_indicate.len, + p_msg->api_indicate.value); + + if (status != GATT_SUCCESS && + p_msg->api_indicate.need_confirm && + p_cb->rcb[p_srvc_cb->rcb_idx].p_cback) + { + (*p_cb->rcb[p_srvc_cb->rcb_idx].p_cback)(BTA_GATTS_CONF_EVT, (tBTA_GATTS *)&status); + } + } + else + { + APPL_TRACE_ERROR1("Not an registered servce attribute ID: 0x%04x", p_msg->api_indicate.attr_id); + } +} + + +/******************************************************************************* +** +** Function bta_gatts_open +** +** Description +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_open (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg) +{ + tBTA_GATTS_RCB *p_rcb=NULL; + tBTA_GATT_STATUS status= BTA_GATT_ERROR; + + + if ((p_rcb = bta_gatts_find_app_rcb_by_app_if(p_msg->api_open.server_if)) != NULL) + { + if (GATT_Connect(p_rcb->gatt_if, p_msg->api_open.remote_bda, p_msg->api_open.is_direct)) + { + status = BTA_GATT_OK; + } + } + else + { + APPL_TRACE_ERROR1("Inavlide server_if=%d", p_msg->api_open.server_if); + } + + if (p_rcb && p_rcb->p_cback) + (*p_rcb->p_cback)(BTA_GATTS_OPEN_EVT, (tBTA_GATTS *)&status); + +} +/******************************************************************************* +** +** Function bta_gatts_cancel_open +** +** Description +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_cancel_open (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg) +{ + tBTA_GATTS_RCB *p_rcb; + tBTA_GATT_STATUS status= BTA_GATT_ERROR; + + if ((p_rcb = bta_gatts_find_app_rcb_by_app_if(p_msg->api_cancel_open.server_if)) != NULL) + { + if (!GATT_CancelConnect(p_rcb->gatt_if, p_msg->api_cancel_open.remote_bda, p_msg->api_cancel_open.is_direct)) + { + APPL_TRACE_ERROR0("bta_gatts_cancel_open failed for open request"); + } + else + { + status= BTA_GATT_OK; + } + } + else + { + APPL_TRACE_ERROR1("Inavlide server_if=%d", p_msg->api_cancel_open.server_if); + } + + if (p_rcb && p_rcb->p_cback) + (*p_rcb->p_cback)(BTA_GATTS_CANCEL_OPEN_EVT, (tBTA_GATTS *)&status); +} +/******************************************************************************* +** +** Function bta_gatts_close +** +** Description +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_close (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg) +{ + tBTA_GATTS_RCB *p_rcb; + tBTA_GATT_STATUS status= BTA_GATT_ERROR; + tGATT_IF gatt_if; + BD_ADDR remote_bda; + + if (GATT_GetConnectionInfor(p_msg->hdr.layer_specific, &gatt_if, remote_bda)) + { + if (GATT_Disconnect(p_msg->hdr.layer_specific) != GATT_SUCCESS) + { + APPL_TRACE_ERROR1("bta_gatts_close fail conn_id=%d", p_msg->hdr.layer_specific); + } + else + { + status= BTA_GATT_OK; + } + + p_rcb = bta_gatts_find_app_rcb_by_app_if(gatt_if); + + if (p_rcb && p_rcb->p_cback) + (*p_rcb->p_cback)(BTA_GATTS_CLOSE_EVT, (tBTA_GATTS *)&status); + } + else + { + APPL_TRACE_ERROR1("Unknown connection ID: %d", p_msg->hdr.layer_specific); + } + +} + + +/******************************************************************************* +** +** Function bta_gatts_request_cback +** +** Description GATTS attribute request callback. +** +** Returns none. +** +*******************************************************************************/ +static void bta_gatts_send_request_cback (UINT16 conn_id, + UINT32 trans_id, + tGATTS_REQ_TYPE req_type, tGATTS_DATA *p_data) +{ + tBTA_GATTS cb_data; + tBTA_GATTS_RCB *p_rcb; + tGATT_IF gatt_if; + + memset(&cb_data, 0 , sizeof(tBTA_GATTS)); + + if (GATT_GetConnectionInfor(conn_id, &gatt_if, cb_data.req_data.remote_bda)) + { + p_rcb = bta_gatts_find_app_rcb_by_app_if(gatt_if); + + APPL_TRACE_DEBUG3 ("bta_gatts_send_request_cback conn_id=%d trans_id=%d req_type=%d", conn_id, trans_id, req_type); + + if (p_rcb && p_rcb->p_cback) + { + cb_data.req_data.conn_id = conn_id; + cb_data.req_data.trans_id = trans_id; + cb_data.req_data.p_data = (tBTA_GATTS_REQ_DATA *)p_data; + + (*p_rcb->p_cback)(req_type, &cb_data); + } + else + { + APPL_TRACE_ERROR1("connection request on gatt_if[%d] is not interested", gatt_if); + } + } + else + { + APPL_TRACE_ERROR1("request received on unknown connectino ID: %d", conn_id); + } +} + +/******************************************************************************* +** +** Function bta_gatts_conn_cback +** +** Description connection callback. +** +** Returns none. +** +*******************************************************************************/ +static void bta_gatts_conn_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id, + BOOLEAN connected, tGATT_DISCONN_REASON reason) +{ + tBTA_GATTS cb_data; + UINT8 evt = connected ? BTA_GATTS_CONNECT_EVT: BTA_GATTS_DISCONNECT_EVT; + tBTA_GATTS_RCB *p_reg; + + APPL_TRACE_DEBUG4 ("bta_gatts_conn_cback gatt_if=%d conn_id=%d connected=%d reason = 0x%04d", + gatt_if, conn_id, connected, reason); + APPL_TRACE_DEBUG6("bta_gatts_conn_cback bda :%02x-%02x-%02x-%02x-%02x-%02x ", + bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]); + + p_reg = bta_gatts_find_app_rcb_by_app_if(gatt_if); + + if (p_reg && p_reg->p_cback) + { + cb_data.conn.conn_id = conn_id; + cb_data.conn.server_if = gatt_if; + cb_data.conn.reason = reason; + memcpy(cb_data.conn.remote_bda, bda, BD_ADDR_LEN); + (*p_reg->p_cback)(evt, &cb_data); + } + else + { + APPL_TRACE_ERROR1("bta_gatts_conn_cback server_if=%d not found",gatt_if); + } +} +#endif /* BTA_GATT_INCLUDED */ diff --git a/bta/gatt/bta_gatts_api.c b/bta/gatt/bta_gatts_api.c new file mode 100644 index 0000000..77a8f6e --- /dev/null +++ b/bta/gatt/bta_gatts_api.c @@ -0,0 +1,500 @@ +/***************************************************************************** +** +** Name: bta_gatts_api.c +** +** Description: This is the implementation of the API for GATT server +** of BTA. +** +** Copyright (c) 2010-2011, Broadcom Corp., All Rights Reserved. +** Broadcom Bluetooth Core. Proprietary and confidential. +** +*****************************************************************************/ + +#include "bt_target.h" + +#if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE) + +#include <string.h> +#include "gki.h" +#include "bta_sys.h" +#include "bta_gatt_api.h" +#include "bta_gatts_int.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ + +static const tBTA_SYS_REG bta_gatts_reg = +{ + bta_gatts_hdl_event, + NULL /* need a disable functino to be called when BT is disabled */ +}; + +/******************************************************************************* +** +** Function BTA_GATTS_AppRegister +** +** Description This function is called to register application callbacks +** with BTA GATTS module. +** +** Parameters p_app_uuid - applicaiton UUID +** p_cback - pointer to the application callback function. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTS_AppRegister(tBT_UUID *p_app_uuid, tBTA_GATTS_CBACK *p_cback) +{ + tBTA_GATTS_API_REG *p_buf; + + /* register with BTA system manager */ + GKI_sched_lock(); + if (!bta_gatts_cb.enabled) + { + bta_sys_register(BTA_ID_GATTS, &bta_gatts_reg); + } + GKI_sched_unlock(); + + if ((p_buf = (tBTA_GATTS_API_REG *) GKI_getbuf(sizeof(tBTA_GATTS_API_REG))) != NULL) + { + p_buf->hdr.event = BTA_GATTS_API_REG_EVT; + + if (p_app_uuid != NULL) + memcpy(&p_buf->app_uuid, p_app_uuid, sizeof(tBT_UUID)); + p_buf->p_cback = p_cback; + + bta_sys_sendmsg(p_buf); + } + return; +} + + + +/******************************************************************************* +** +** Function BTA_GATTS_AppDeregister +** +** Description De-register with GATT Server. +** +** Parameters app_id: applicatino ID. +** +** Returns void +** +*******************************************************************************/ +void BTA_GATTS_AppDeregister(tBTA_GATTS_IF server_if) +{ + tBTA_GATTS_API_DEREG *p_buf; + + if ((p_buf = (tBTA_GATTS_API_DEREG *) GKI_getbuf(sizeof(tBTA_GATTS_API_DEREG))) != NULL) + { + p_buf->hdr.event = BTA_GATTS_API_DEREG_EVT; + p_buf->server_if = server_if; + + bta_sys_sendmsg(p_buf); + } + return; +} + +/******************************************************************************* +** +** Function BTA_GATTS_CreateService +** +** Description Create a service. When service creation is done, a callback +** event BTA_GATTS_CREATE_SRVC_EVT is called to report status +** and service ID to the profile. The service ID obtained in +** the callback function needs to be used when adding included +** service and characteristics/descriptors into the service. +** +** Parameters app_id: Profile ID this service is belonged to. +** p_service_uuid: service UUID. +** inst: instance ID number of this service. +** num_handle: numble of handle requessted for this service. +** is_primary: is this service a primary one or not. +** +** Returns void +** +*******************************************************************************/ +void BTA_GATTS_CreateService(tBTA_GATTS_IF server_if, tBT_UUID *p_service_uuid, UINT8 inst, + UINT16 num_handle, BOOLEAN is_primary) +{ + tBTA_GATTS_API_CREATE_SRVC *p_buf; + + if ((p_buf = (tBTA_GATTS_API_CREATE_SRVC *) GKI_getbuf(sizeof(tBTA_GATTS_API_CREATE_SRVC))) != NULL) + { + p_buf->hdr.event = BTA_GATTS_API_CREATE_SRVC_EVT; + + p_buf->server_if = server_if; + p_buf->inst = inst; + memcpy(&p_buf->service_uuid, p_service_uuid, sizeof(tBT_UUID)); + p_buf->num_handle = num_handle; + p_buf->is_pri = is_primary; + + bta_sys_sendmsg(p_buf); + } + return; +} +/******************************************************************************* +** +** Function BTA_GATTS_AddIncludeService +** +** Description This function is called to add an included service. After included +** service is included, a callback event BTA_GATTS_ADD_INCL_SRVC_EVT +** is reported the included service ID. +** +** Parameters service_id: service ID to which this included service is to +** be added. +** included_service_id: the service ID to be included. +** +** Returns void +** +*******************************************************************************/ +void BTA_GATTS_AddIncludeService(UINT16 service_id, UINT16 included_service_id) +{ + tBTA_GATTS_API_ADD_INCL_SRVC *p_buf; + + if ((p_buf = + (tBTA_GATTS_API_ADD_INCL_SRVC *) GKI_getbuf(sizeof(tBTA_GATTS_API_ADD_INCL_SRVC))) + != NULL) + { + p_buf->hdr.event = BTA_GATTS_API_ADD_INCL_SRVC_EVT; + + p_buf->hdr.layer_specific = service_id; + p_buf->included_service_id = included_service_id; + + bta_sys_sendmsg(p_buf); + } + return; + +} +/******************************************************************************* +** +** Function BTA_GATTS_AddCharacteristic +** +** Description This function is called to add a characteristic into a service. +** +** Parameters service_id: service ID to which this included service is to +** be added. +** p_char_uuid : Characteristic UUID. +** perm : Characteristic value declaration attribute permission. +** property : Characteristic Properties +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTS_AddCharacteristic (UINT16 service_id, tBT_UUID *p_char_uuid, + tBTA_GATT_PERM perm, tBTA_GATT_CHAR_PROP property) +{ + tBTA_GATTS_API_ADD_CHAR *p_buf; + + if ((p_buf = (tBTA_GATTS_API_ADD_CHAR *) GKI_getbuf(sizeof(tBTA_GATTS_API_ADD_CHAR))) != NULL) + { + memset(p_buf, 0, sizeof(tBTA_GATTS_API_ADD_CHAR)); + + p_buf->hdr.event = BTA_GATTS_API_ADD_CHAR_EVT; + p_buf->hdr.layer_specific = service_id; + p_buf->perm = perm; + p_buf->property = property; + + if (p_char_uuid) + { + memcpy(&p_buf->char_uuid, p_char_uuid, sizeof(tBT_UUID)); + } + bta_sys_sendmsg(p_buf); + } + return; +} + +/******************************************************************************* +** +** Function BTA_GATTS_AddCharDescriptor +** +** Description This function is called to add characteristic descriptor. When +** it's done, a callback event BTA_GATTS_ADD_DESCR_EVT is called +** to report the status and an ID number for this descriptor. +** +** Parameters service_id: service ID to which this charatceristic descriptor is to +** be added. +** perm: descriptor access permission. +** p_descr_uuid: descriptor UUID. +** +** Returns returns status. +** +*******************************************************************************/ +void BTA_GATTS_AddCharDescriptor (UINT16 service_id, + tBTA_GATT_PERM perm, + tBT_UUID * p_descr_uuid) +{ + tBTA_GATTS_API_ADD_DESCR *p_buf; + UINT16 len = sizeof(tBTA_GATTS_API_ADD_DESCR); + + + if ((p_buf = (tBTA_GATTS_API_ADD_DESCR *) GKI_getbuf(len)) != NULL) + { + memset(p_buf, 0, len); + + p_buf->hdr.event = BTA_GATTS_API_ADD_DESCR_EVT; + p_buf->hdr.layer_specific = service_id; + p_buf->perm = perm; + + if (p_descr_uuid) + { + memcpy(&p_buf->descr_uuid, p_descr_uuid, sizeof(tBT_UUID)); + } + bta_sys_sendmsg(p_buf); + } + return; + +} + +/******************************************************************************* +** +** Function BTA_GATTS_DeleteService +** +** Description This function is called to delete a service. When this is done, +** a callback event BTA_GATTS_DELETE_EVT is report with the status. +** +** Parameters service_id: service_id to be deleted. +** +** Returns returns none. +** +*******************************************************************************/ +void BTA_GATTS_DeleteService(UINT16 service_id) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = BTA_GATTS_API_DEL_SRVC_EVT; + + p_buf->layer_specific = service_id; + + bta_sys_sendmsg(p_buf); + } + return; + +} + +/******************************************************************************* +** +** Function BTA_GATTS_StartService +** +** Description This function is called to start a service. +** +** Parameters service_id: the service ID to be started. +** sup_transport: supported trasnport. +** +** Returns None. +** +*******************************************************************************/ +void BTA_GATTS_StartService(UINT16 service_id, tBTA_GATT_TRANSPORT sup_transport) +{ + tBTA_GATTS_API_START *p_buf; + + if ((p_buf = (tBTA_GATTS_API_START *) GKI_getbuf(sizeof(tBTA_GATTS_API_START))) != NULL) + { + p_buf->hdr.event = BTA_GATTS_API_START_SRVC_EVT; + + p_buf->hdr.layer_specific = service_id; + p_buf->transport = sup_transport; + + bta_sys_sendmsg(p_buf); + } + return; +} + +/******************************************************************************* +** +** Function BTA_GATTS_StopService +** +** Description This function is called to stop a service. +** +** Parameters service_id - service to be topped. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTS_StopService(UINT16 service_id) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = BTA_GATTS_API_STOP_SRVC_EVT; + + p_buf->layer_specific = service_id; + + bta_sys_sendmsg(p_buf); + } + return; +} + +/******************************************************************************* +** +** Function BTA_GATTS_HandleValueIndication +** +** Description This function is called to read a characteristics descriptor. +** +** Parameters bda - remote device bd address to indicate. +** attr_id - attribute ID to indicate. +** data_len - indicate data length. +** p_data: data to indicate. +** need_confirm - if this indication expects a confirmation or not. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTS_HandleValueIndication (UINT16 conn_id, UINT16 attr_id, UINT16 data_len, + UINT8 *p_data, BOOLEAN need_confirm) +{ + tBTA_GATTS_API_INDICATION *p_buf; + UINT16 len = sizeof(tBTA_GATTS_API_INDICATION); + + if ((p_buf = (tBTA_GATTS_API_INDICATION *) GKI_getbuf(len)) != NULL) + { + memset(p_buf, 0, len); + + p_buf->hdr.event = BTA_GATTS_API_INDICATION_EVT; + p_buf->hdr.layer_specific = conn_id; + p_buf->attr_id = attr_id; + p_buf->need_confirm = need_confirm; + + if (data_len > 0 && p_data != NULL) + { + p_buf->len = data_len; + memcpy(p_buf->value, p_data, data_len); + + } + bta_sys_sendmsg(p_buf); + } + return; + +} +/******************************************************************************* +** +** Function BTA_GATTS_SendRsp +** +** Description This function is called to send a response to a request. +** +** Parameters conn_id - connection identifier. +** trans_id - transaction ID. +** status - response status +** p_msg - response data. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTS_SendRsp (UINT16 conn_id, UINT32 trans_id, + tBTA_GATT_STATUS status, tBTA_GATTS_RSP *p_msg) +{ + tBTA_GATTS_API_RSP *p_buf; + UINT16 len = sizeof(tBTA_GATTS_API_RSP) + sizeof(tBTA_GATTS_RSP); + + if ((p_buf = (tBTA_GATTS_API_RSP *) GKI_getbuf(len)) != NULL) + { + memset(p_buf, 0, len); + + p_buf->hdr.event = BTA_GATTS_API_RSP_EVT; + p_buf->hdr.layer_specific = conn_id; + p_buf->trans_id = trans_id; + p_buf->status = status; + + if (p_msg != NULL) + { + p_buf->p_rsp = (tBTA_GATTS_RSP *)(p_buf + 1); + memcpy(p_buf->p_rsp, p_msg, sizeof(tBTA_GATTS_RSP)); + } + + bta_sys_sendmsg(p_buf); + } + return; + +} + + + +/******************************************************************************* +** +** Function BTA_GATTS_Open +** +** Description Open a direct open connection or add a background auto connection +** bd address +** +** Parameters server_if: server interface. +** remote_bda: remote device BD address. +** is_direct: direct connection or background auto connection +** +** Returns void +** +*******************************************************************************/ +void BTA_GATTS_Open(tBTA_GATTS_IF server_if, BD_ADDR remote_bda, BOOLEAN is_direct) +{ + tBTA_GATTS_API_OPEN *p_buf; + + if ((p_buf = (tBTA_GATTS_API_OPEN *) GKI_getbuf(sizeof(tBTA_GATTS_API_OPEN))) != NULL) + { + p_buf->hdr.event = BTA_GATTS_API_OPEN_EVT; + p_buf->server_if = server_if; + p_buf->is_direct = is_direct; + memcpy(p_buf->remote_bda, remote_bda, BD_ADDR_LEN); + + bta_sys_sendmsg(p_buf); + } + return; +} + + +/******************************************************************************* +** +** Function BTA_GATTS_CancelOpen +** +** Description Cancel a direct open connection or remove a background auto connection +** bd address +** +** Parameters server_if: server interface. +** remote_bda: remote device BD address. +** is_direct: direct connection or background auto connection +** +** Returns void +** +*******************************************************************************/ +void BTA_GATTS_CancelOpen(tBTA_GATTS_IF server_if, BD_ADDR remote_bda, BOOLEAN is_direct) +{ + tBTA_GATTS_API_CANCEL_OPEN *p_buf; + + if ((p_buf = (tBTA_GATTS_API_CANCEL_OPEN *) GKI_getbuf(sizeof(tBTA_GATTS_API_CANCEL_OPEN))) != NULL) + { + p_buf->hdr.event = BTA_GATTS_API_CANCEL_OPEN_EVT; + p_buf->server_if = server_if; + p_buf->is_direct = is_direct; + memcpy(p_buf->remote_bda, remote_bda, BD_ADDR_LEN); + bta_sys_sendmsg(p_buf); + } + return; +} + +/******************************************************************************* +** +** Function BTA_GATTS_Close +** +** Description Close a connection a remote device. +** +** Parameters conn_id: connectino ID to be closed. +** +** Returns void +** +*******************************************************************************/ +void BTA_GATTS_Close(UINT16 conn_id) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = BTA_GATTS_API_CLOSE_EVT; + p_buf->layer_specific = conn_id; + bta_sys_sendmsg(p_buf); + } + return; + +} + +#endif /* BTA_GATT_INCLUDED */ diff --git a/bta/gatt/bta_gatts_int.h b/bta/gatt/bta_gatts_int.h new file mode 100644 index 0000000..77945f0 --- /dev/null +++ b/bta/gatt/bta_gatts_int.h @@ -0,0 +1,233 @@ +/***************************************************************************** +** +** Name: bta_gatts_int.h +** +** Description: This is the private file for the BTA GATT server. +** +** Copyright (c) 2003-2010, Broadcom Corp., All Rights Reserved. +** Widcomm Bluetooth Core. Proprietary and confidential. +** +*****************************************************************************/ +#ifndef BTA_GATTS_INT_H +#define BTA_GATTS_INT_H + +#include "bt_target.h" +#include "bta_sys.h" +#include "bta_gatt_api.h" +#include "gatt_api.h" +//#include "bta_gatts_co.h" + +#include "gki.h" + +/***************************************************************************** +** Constants and data types +*****************************************************************************/ +enum +{ + BTA_GATTS_API_REG_EVT = BTA_SYS_EVT_START(BTA_ID_GATTS), + BTA_GATTS_INT_START_IF_EVT, + BTA_GATTS_API_DEREG_EVT, + BTA_GATTS_API_CREATE_SRVC_EVT, + BTA_GATTS_API_INDICATION_EVT, + + BTA_GATTS_API_ADD_INCL_SRVC_EVT, + BTA_GATTS_API_ADD_CHAR_EVT, + BTA_GATTS_API_ADD_DESCR_EVT, + BTA_GATTS_API_DEL_SRVC_EVT, + BTA_GATTS_API_START_SRVC_EVT, + BTA_GATTS_API_STOP_SRVC_EVT, + BTA_GATTS_API_RSP_EVT, + BTA_GATTS_API_OPEN_EVT, + BTA_GATTS_API_CANCEL_OPEN_EVT, + BTA_GATTS_API_CLOSE_EVT + +}; +typedef UINT16 tBTA_GATTS_INT_EVT; + +/* max number of application allowed on device */ +#define BTA_GATTS_MAX_APP_NUM GATT_MAX_SR_PROFILES + +/* max number of services allowed in the device */ +#define BTA_GATTS_MAX_SRVC_NUM GATT_MAX_SR_PROFILES + +/* internal strucutre for GATTC register API */ +typedef struct +{ + BT_HDR hdr; + tBT_UUID app_uuid; + tBTA_GATTS_CBACK *p_cback; +}tBTA_GATTS_API_REG; + +typedef struct +{ + BT_HDR hdr; + tBTA_GATTS_IF server_if; +}tBTA_GATTS_INT_START_IF; + +typedef tBTA_GATTS_INT_START_IF tBTA_GATTS_API_DEREG; + +typedef struct +{ + BT_HDR hdr; + tBTA_GATTS_IF server_if; + tBT_UUID service_uuid; + UINT16 num_handle; + UINT8 inst; + BOOLEAN is_pri; + +} tBTA_GATTS_API_CREATE_SRVC; + +typedef struct +{ + BT_HDR hdr; + tBT_UUID char_uuid; + tBTA_GATT_PERM perm; + tBTA_GATT_CHAR_PROP property; + +}tBTA_GATTS_API_ADD_CHAR; + +typedef struct +{ + BT_HDR hdr; + UINT16 included_service_id; + +}tBTA_GATTS_API_ADD_INCL_SRVC; + +typedef struct +{ + BT_HDR hdr; + tBT_UUID descr_uuid; + tBTA_GATT_PERM perm; +}tBTA_GATTS_API_ADD_DESCR; + +typedef struct +{ + BT_HDR hdr; + //todo BD_ADDR bd_addr; + UINT16 attr_id; + UINT16 len; + BOOLEAN need_confirm; + UINT8 value[BTA_GATT_MAX_ATTR_LEN]; +}tBTA_GATTS_API_INDICATION; + +typedef struct +{ + BT_HDR hdr; + UINT32 trans_id; + tBTA_GATT_STATUS status; + tBTA_GATTS_RSP *p_rsp; +}tBTA_GATTS_API_RSP; + +typedef struct +{ + BT_HDR hdr; + tBTA_GATT_TRANSPORT transport; +}tBTA_GATTS_API_START; + + +typedef struct +{ + BT_HDR hdr; + BD_ADDR remote_bda; + tBTA_GATTS_IF server_if; + BOOLEAN is_direct; +}tBTA_GATTS_API_OPEN; + +typedef tBTA_GATTS_API_OPEN tBTA_GATTS_API_CANCEL_OPEN; + +typedef union +{ + BT_HDR hdr; + tBTA_GATTS_API_REG api_reg; + tBTA_GATTS_API_DEREG api_dereg; + tBTA_GATTS_API_CREATE_SRVC api_create_svc; + tBTA_GATTS_API_ADD_INCL_SRVC api_add_incl_srvc; + tBTA_GATTS_API_ADD_CHAR api_add_char; + tBTA_GATTS_API_ADD_DESCR api_add_char_descr; + tBTA_GATTS_API_START api_start; + tBTA_GATTS_API_INDICATION api_indicate; + tBTA_GATTS_API_RSP api_rsp; + tBTA_GATTS_API_OPEN api_open; + tBTA_GATTS_API_CANCEL_OPEN api_cancel_open; + + tBTA_GATTS_INT_START_IF int_start_if; +} tBTA_GATTS_DATA; + +/* application registration control block */ +typedef struct +{ + BOOLEAN in_use; + tBT_UUID app_uuid; + tBTA_GATTS_CBACK *p_cback; + tBTA_GATTS_IF gatt_if; //todo cahneg to server_if +}tBTA_GATTS_RCB; + +/* service registration control block */ +typedef struct +{ + tBT_UUID service_uuid; /* service UUID */ + UINT16 service_id; /* service handle */ + UINT8 inst_num; /* instance ID */ + UINT8 rcb_idx; + UINT8 idx; /* self index of serviec CB */ + BOOLEAN in_use; + +}tBTA_GATTS_SRVC_CB; + + +/* GATT server control block */ +typedef struct +{ + BOOLEAN enabled; + tBTA_GATTS_RCB rcb[BTA_GATTS_MAX_APP_NUM]; + tBTA_GATTS_SRVC_CB srvc_cb[BTA_GATTS_MAX_SRVC_NUM]; +}tBTA_GATTS_CB; + + + +/***************************************************************************** +** Global data +*****************************************************************************/ + +/* GATTC control block */ +#if BTA_DYNAMIC_MEMORY == FALSE +extern tBTA_GATTS_CB bta_gatts_cb; +#else +extern tBTA_GATTS_CB *bta_gatts_cb_ptr; + #define bta_gatts_cb (*bta_gatts_cb_ptr) +#endif + +/***************************************************************************** +** Function prototypes +*****************************************************************************/ +extern BOOLEAN bta_gatts_hdl_event(BT_HDR *p_msg); + +extern void bta_gatts_register(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA *p_msg); +extern void bta_gatts_start_if(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA *p_msg); +extern void bta_gatts_deregister(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA *p_msg); +extern void bta_gatts_create_srvc(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg); +extern void bta_gatts_add_include_srvc(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA * p_msg); +extern void bta_gatts_add_char(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA * p_msg); +extern void bta_gatts_add_char_descr(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA * p_msg); +extern void bta_gatts_delete_service(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA * p_msg); +extern void bta_gatts_start_service(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA * p_msg); +extern void bta_gatts_stop_service(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA * p_msg); + +extern void bta_gatts_send_rsp(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg); +extern void bta_gatts_indicate_handle (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg); + + +extern void bta_gatts_open (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg); +extern void bta_gatts_cancel_open (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg); +extern void bta_gatts_close (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg); + +extern BOOLEAN bta_gatts_uuid_compare(tBT_UUID tar, tBT_UUID src); +extern tBTA_GATTS_RCB *bta_gatts_find_app_rcb_by_app_if(tBTA_GATTS_IF server_if); +extern UINT8 bta_gatts_find_app_rcb_idx_by_app_if(tBTA_GATTS_CB *p_cb, tBTA_GATTS_IF server_if); +extern UINT8 bta_gatts_alloc_srvc_cb(tBTA_GATTS_CB *p_cb, UINT8 rcb_idx); +extern tBTA_GATTS_SRVC_CB * bta_gatts_find_srvc_cb_by_srvc_id(tBTA_GATTS_CB *p_cb, UINT16 service_id); +extern tBTA_GATTS_SRVC_CB * bta_gatts_find_srvc_cb_by_attr_id(tBTA_GATTS_CB *p_cb, UINT16 attr_id); + + +#endif /* BTA_GATTS_INT_H */ + diff --git a/bta/gatt/bta_gatts_main.c b/bta/gatt/bta_gatts_main.c new file mode 100644 index 0000000..6870016 --- /dev/null +++ b/bta/gatt/bta_gatts_main.c @@ -0,0 +1,122 @@ +/***************************************************************************** +** +** Name: bta_gatts_main.c +** +** Description: This file contains the GATT server main functions +** and state machine. +** +** Copyright (c) 2003-2010, Broadcom Corp., All Rights Reserved. +** Widcomm Bluetooth Core. Proprietary and confidential. +** +*****************************************************************************/ + +#include "bt_target.h" + +#if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE) + +#include <string.h> + +#include "bta_gatts_int.h" +#include "gki.h" + +/* type for service building action functions */ +typedef void (*tBTA_GATTS_SRVC_ACT)(tBTA_GATTS_SRVC_CB *p_rcb, tBTA_GATTS_DATA *p_data); + +/* service building action function list */ +const tBTA_GATTS_SRVC_ACT bta_gatts_srvc_build_act[] = +{ + bta_gatts_add_include_srvc, + bta_gatts_add_char, + bta_gatts_add_char_descr, + bta_gatts_delete_service, + bta_gatts_start_service, + bta_gatts_stop_service, +}; + +/* GATTS control block */ +#if BTA_DYNAMIC_MEMORY == FALSE +tBTA_GATTS_CB bta_gatts_cb; +#endif + +/******************************************************************************* +** +** Function bta_gatts_hdl_event +** +** Description BTA GATT server main event handling function. +** +** +** Returns void +** +*******************************************************************************/ +BOOLEAN bta_gatts_hdl_event(BT_HDR *p_msg) +{ + tBTA_GATTS_CB *p_cb = &bta_gatts_cb; + tBTA_GATTS_SRVC_CB *p_srvc_cb = NULL; + + switch (p_msg->event) + { + case BTA_GATTS_API_REG_EVT: + bta_gatts_register(p_cb, (tBTA_GATTS_DATA *) p_msg); + break; + + case BTA_GATTS_INT_START_IF_EVT: + bta_gatts_start_if(p_cb, (tBTA_GATTS_DATA *) p_msg); + break; + + case BTA_GATTS_API_DEREG_EVT: + bta_gatts_deregister(p_cb, (tBTA_GATTS_DATA *) p_msg); + break; + + case BTA_GATTS_API_CREATE_SRVC_EVT: + bta_gatts_create_srvc(p_cb, (tBTA_GATTS_DATA *) p_msg); + break; + + case BTA_GATTS_API_INDICATION_EVT: + bta_gatts_indicate_handle(p_cb,(tBTA_GATTS_DATA *) p_msg); + break; + + case BTA_GATTS_API_OPEN_EVT: + bta_gatts_open(p_cb,(tBTA_GATTS_DATA *) p_msg); + break; + + case BTA_GATTS_API_CANCEL_OPEN_EVT: + bta_gatts_cancel_open(p_cb,(tBTA_GATTS_DATA *) p_msg); + break; + + case BTA_GATTS_API_CLOSE_EVT: + bta_gatts_close(p_cb,(tBTA_GATTS_DATA *) p_msg); + break; + + case BTA_GATTS_API_RSP_EVT: + bta_gatts_send_rsp(p_cb,(tBTA_GATTS_DATA *) p_msg); + break; + + case BTA_GATTS_API_ADD_INCL_SRVC_EVT: + case BTA_GATTS_API_ADD_CHAR_EVT: + case BTA_GATTS_API_ADD_DESCR_EVT: + case BTA_GATTS_API_DEL_SRVC_EVT: + case BTA_GATTS_API_START_SRVC_EVT: + case BTA_GATTS_API_STOP_SRVC_EVT: + + p_srvc_cb = bta_gatts_find_srvc_cb_by_srvc_id(p_cb, + ((tBTA_GATTS_DATA *)p_msg)->api_add_incl_srvc.hdr.layer_specific); + + if (p_srvc_cb != NULL) + { + bta_gatts_srvc_build_act[p_msg->event - BTA_GATTS_API_ADD_INCL_SRVC_EVT](p_srvc_cb, (tBTA_GATTS_DATA *) p_msg); + } + else + { + APPL_TRACE_ERROR0("service not created"); + } + break; + + default: + break; + } + + + return (TRUE); +} + +#endif /* BTA_GATT_INCLUDED */ diff --git a/bta/gatt/bta_gatts_utils.c b/bta/gatt/bta_gatts_utils.c new file mode 100644 index 0000000..8f00793 --- /dev/null +++ b/bta/gatt/bta_gatts_utils.c @@ -0,0 +1,223 @@ +/***************************************************************************** +** +** Name: bta_gattc_utils.c +** +** Description: This file contains the GATT client utility +** function. +** +** Copyright (c) 2003-2010, Broadcom Corp., All Rights Reserved. +** Broadcom Bluetooth Core. Proprietary and confidential. +** +*****************************************************************************/ + +#include "bt_target.h" + +#if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE) + +#include <string.h> +#include "utl.h" +#include "gki.h" +#include "bta_sys.h" +#include "bta_gatts_int.h" +#include "bd.h" + +static const UINT8 base_uuid[LEN_UUID_128] = {0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +/******************************************************************************* +** +** Function bta_gatt_convert_uuid16_to_uuid128 +** +** Description Convert a 16 bits UUID to be an standard 128 bits one. +** +** Returns TRUE if two uuid match; FALSE otherwise. +** +*******************************************************************************/ +static void bta_gatt_convert_uuid16_to_uuid128(UINT8 uuid_128[LEN_UUID_128], UINT16 uuid_16) +{ + UINT8 *p = &uuid_128[LEN_UUID_128 - 4]; + + memcpy (uuid_128, base_uuid, LEN_UUID_128); + + UINT16_TO_STREAM(p, uuid_16); +} +/******************************************************************************* +** +** Function bta_gatts_alloc_srvc_cb +** +** Description allocate a service control block. +** +** Returns pointer to the control block, or otherwise NULL when failed. +** +*******************************************************************************/ +UINT8 bta_gatts_alloc_srvc_cb(tBTA_GATTS_CB *p_cb, UINT8 rcb_idx) +{ + UINT8 i; + + for (i = 0; i < BTA_GATTS_MAX_SRVC_NUM; i ++) + { + if (!p_cb->srvc_cb[i].in_use) + { + p_cb->srvc_cb[i].in_use = TRUE; + p_cb->srvc_cb[i].rcb_idx = rcb_idx; + return i; + } + } + return BTA_GATTS_INVALID_APP; +} + +/******************************************************************************* +** +** Function bta_gatts_find_app_rcb_by_app_if +** +** Description find the index of the application control block by app ID. +** +** Returns pointer to the control block if success, otherwise NULL +** +*******************************************************************************/ +tBTA_GATTS_RCB *bta_gatts_find_app_rcb_by_app_if(tBTA_GATTS_IF server_if) +{ + UINT8 i; + tBTA_GATTS_RCB *p_reg; + + for (i = 0, p_reg = bta_gatts_cb.rcb; i < BTA_GATTS_MAX_APP_NUM; i ++, p_reg++) + { + if (p_reg->in_use && p_reg->gatt_if == server_if) + return p_reg; + } + return NULL; +} + +/******************************************************************************* +** +** Function bta_gatts_find_app_rcb_idx_by_app_if +** +** Description find the index of the application control block by app ID. +** +** Returns index of the control block, or BTA_GATTS_INVALID_APP if failed. +** +*******************************************************************************/ + +UINT8 bta_gatts_find_app_rcb_idx_by_app_if(tBTA_GATTS_CB *p_cb, tBTA_GATTS_IF server_if) +{ + UINT8 i; + + for (i = 0; i < BTA_GATTS_MAX_APP_NUM; i ++) + { + if (p_cb->rcb[i].in_use && p_cb->rcb[i].gatt_if == server_if) + return i; + } + return BTA_GATTS_INVALID_APP; +} +/******************************************************************************* +** +** Function bta_gatts_find_srvc_cb_by_srvc_id +** +** Description find the service control block by service ID. +** +** Returns pointer to the rcb. +** +*******************************************************************************/ +tBTA_GATTS_SRVC_CB * bta_gatts_find_srvc_cb_by_srvc_id(tBTA_GATTS_CB *p_cb, UINT16 service_id) +{ + UINT8 i; + APPL_TRACE_DEBUG1("bta_gatts_find_srvc_cb_by_srvc_id service_id=%d", service_id); + for (i = 0; i < BTA_GATTS_MAX_SRVC_NUM; i ++) + { + if (p_cb->srvc_cb[i].in_use && + p_cb->srvc_cb[i].service_id == service_id) + { + APPL_TRACE_DEBUG1("bta_gatts_find_srvc_cb_by_srvc_id found service cb index =%d", i); + return &p_cb->srvc_cb[i]; + } + } + return NULL; +} +/******************************************************************************* +** +** Function bta_gatts_find_srvc_cb_by_attr_id +** +** Description find the service control block by attribute ID. +** +** Returns pointer to the rcb. +** +*******************************************************************************/ +tBTA_GATTS_SRVC_CB * bta_gatts_find_srvc_cb_by_attr_id(tBTA_GATTS_CB *p_cb, UINT16 attr_id) +{ + UINT8 i; + + for (i = 0; i < (BTA_GATTS_MAX_SRVC_NUM); i ++) + { + if (/* middle service */ + (i < (BTA_GATTS_MAX_SRVC_NUM - 1) && + p_cb->srvc_cb[i].in_use && + p_cb->srvc_cb[i + 1].in_use && + attr_id >= p_cb->srvc_cb[i].service_id && + attr_id < p_cb->srvc_cb[i + 1].service_id) || + /* last active service */ + (i < (BTA_GATTS_MAX_SRVC_NUM - 1) && + p_cb->srvc_cb[i].in_use && + !p_cb->srvc_cb[i + 1].in_use && + attr_id >= p_cb->srvc_cb[i].service_id) || + /* last service incb */ + (i == (BTA_GATTS_MAX_SRVC_NUM - 1) && + attr_id >= p_cb->srvc_cb[i].service_id) + ) + { + return &p_cb->srvc_cb[i]; + } + } + return NULL; +} +/******************************************************************************* +** +** Function bta_gatts_uuid_compare +** +** Description Compare two UUID to see if they are the same. +** +** Returns TRUE if two uuid match; FALSE otherwise. +** +*******************************************************************************/ +BOOLEAN bta_gatts_uuid_compare(tBT_UUID tar, tBT_UUID src) +{ + UINT8 su[LEN_UUID_128], tu[LEN_UUID_128]; + UINT8 *ps, *pt; + + /* any of the UUID is unspecified */ + if (src.len == 0 || tar.len == 0) + { + return TRUE; + } + + /* If both are 16-bit, we can do a simple compare */ + if (src.len == 2 && tar.len == 2) + { + return src.uu.uuid16 == tar.uu.uuid16; + } + + /* One or both of the UUIDs is 128-bit */ + if (src.len == LEN_UUID_16) + { + /* convert a 16 bits UUID to 128 bits value */ + bta_gatt_convert_uuid16_to_uuid128(su, src.uu.uuid16); + ps = su; + } + else + ps = src.uu.uuid128; + + if (tar.len == LEN_UUID_16) + { + /* convert a 16 bits UUID to 128 bits value */ + bta_gatt_convert_uuid16_to_uuid128(tu, tar.uu.uuid16); + pt = tu; + } + else + pt = tar.uu.uuid128; + + return(memcmp(ps, pt, LEN_UUID_128) == 0); +} + + + + +#endif |