1/***************************************************************************** 2** 3** Name: srvc_eng.c 4** 5** Description: this file contains the main Device Information Service over GATT 6** server/client and request handling functions. 7** 8** Copyright (c) 2008-2011, Broadcom Corp., All Rights Reserved. 9** Broadcom Bluetooth Core. Proprietary and confidential. 10******************************************************************************/ 11 12#include "bt_target.h" 13 14#include "gatt_api.h" 15#include "gatt_int.h" 16#include "srvc_eng_int.h" 17 18#if BLE_INCLUDED == TRUE 19 20//#if DIS_INCLUDED == TRUE 21#include "srvc_dis_int.h" 22//#endif 23#include "srvc_battery_int.h" 24 25static void srvc_eng_s_request_cback (UINT16 conn_id, UINT32 trans_id, UINT8 op_code, tGATTS_DATA *p_data); 26static void srvc_eng_connect_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id, BOOLEAN connected, tGATT_DISCONN_REASON reason); 27static void srvc_eng_c_cmpl_cback (UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, tGATT_CL_COMPLETE *p_data); 28 29static tGATT_CBACK srvc_gatt_cback = 30{ 31 srvc_eng_connect_cback, 32 srvc_eng_c_cmpl_cback, 33 NULL, 34 NULL, 35 srvc_eng_s_request_cback 36} ; 37/* type for action functions */ 38typedef void (*tSRVC_ENG_C_CMPL_ACTION)(tSRVC_CLCB *p_clcb, tGATTC_OPTYPE op, 39 tGATT_STATUS status, tGATT_CL_COMPLETE *p_data); 40 41const tSRVC_ENG_C_CMPL_ACTION srvc_eng_c_cmpl_act[SRVC_ID_MAX] = 42{ 43 dis_c_cmpl_cback, 44}; 45 46tSRVC_ENG_CB srvc_eng_cb; 47 48/******************************************************************************* 49** 50** Function srvc_eng_find_conn_id_by_bd_addr 51** 52** Description The function searches all LCB with macthing bd address 53** 54** Returns total number of clcb found. 55** 56*******************************************************************************/ 57UINT16 srvc_eng_find_conn_id_by_bd_addr(BD_ADDR bda) 58{ 59 UINT8 i_clcb; 60 tSRVC_CLCB *p_clcb = NULL; 61 62 for (i_clcb = 0, p_clcb= srvc_eng_cb.clcb; i_clcb < SRVC_MAX_APPS; i_clcb++, p_clcb++) 63 { 64 if (p_clcb->in_use && p_clcb->connected && !memcmp(p_clcb->bda, bda, BD_ADDR_LEN)) 65 { 66 return p_clcb->conn_id; 67 } 68 } 69 70 return GATT_INVALID_CONN_ID; 71} 72 73/******************************************************************************* 74** 75** Function srvc_eng_find_clcb_by_bd_addr 76** 77** Description The function searches all LCBs with macthing bd address. 78** 79** Returns Pointer to the found link conenction control block. 80** 81*******************************************************************************/ 82tSRVC_CLCB *srvc_eng_find_clcb_by_bd_addr(BD_ADDR bda) 83{ 84 UINT8 i_clcb; 85 tSRVC_CLCB *p_clcb = NULL; 86 87 for (i_clcb = 0, p_clcb= srvc_eng_cb.clcb; i_clcb < SRVC_MAX_APPS; i_clcb++, p_clcb++) 88 { 89 if (p_clcb->in_use && p_clcb->connected && !memcmp(p_clcb->bda, bda, BD_ADDR_LEN)) 90 { 91 return p_clcb; 92 } 93 } 94 95 return NULL; 96} 97/******************************************************************************* 98** 99** Function srvc_eng_find_clcb_by_conn_id 100** 101** Description The function searches all LCBs with macthing connection ID. 102** 103** Returns Pointer to the found link conenction control block. 104** 105*******************************************************************************/ 106tSRVC_CLCB *srvc_eng_find_clcb_by_conn_id(UINT16 conn_id) 107{ 108 UINT8 i_clcb; 109 tSRVC_CLCB *p_clcb = NULL; 110 111 for (i_clcb = 0, p_clcb= srvc_eng_cb.clcb; i_clcb < SRVC_MAX_APPS; i_clcb++, p_clcb++) 112 { 113 if (p_clcb->in_use && p_clcb->connected && p_clcb->conn_id == conn_id) 114 { 115 return p_clcb; 116 } 117 } 118 119 return NULL; 120} 121/******************************************************************************* 122** 123** Function srvc_eng_find_clcb_by_conn_id 124** 125** Description The function searches all LCBs with macthing connection ID. 126** 127** Returns Pointer to the found link conenction control block. 128** 129*******************************************************************************/ 130UINT8 srvc_eng_find_clcb_idx_by_conn_id(UINT16 conn_id) 131{ 132 UINT8 i_clcb; 133 tSRVC_CLCB *p_clcb = NULL; 134 135 for (i_clcb = 0, p_clcb= srvc_eng_cb.clcb; i_clcb < SRVC_MAX_APPS; i_clcb++, p_clcb++) 136 { 137 if (p_clcb->in_use && p_clcb->connected && p_clcb->conn_id == conn_id) 138 { 139 return i_clcb; 140 } 141 } 142 143 return SRVC_MAX_APPS; 144} 145/******************************************************************************* 146** 147** Function srvc_eng_clcb_alloc 148** 149** Description The function allocates a GATT profile connection link control block 150** 151** Returns NULL if not found. Otherwise pointer to the connection link block. 152** 153*******************************************************************************/ 154tSRVC_CLCB *srvc_eng_clcb_alloc (UINT16 conn_id, BD_ADDR bda) 155{ 156 UINT8 i_clcb = 0; 157 tSRVC_CLCB *p_clcb = NULL; 158 159 for (i_clcb = 0, p_clcb= srvc_eng_cb.clcb; i_clcb < SRVC_MAX_APPS; i_clcb++, p_clcb++) 160 { 161 if (!p_clcb->in_use) 162 { 163 p_clcb->in_use = TRUE; 164 p_clcb->conn_id = conn_id; 165 p_clcb->connected = TRUE; 166 memcpy (p_clcb->bda, bda, BD_ADDR_LEN); 167 break; 168 } 169 } 170 return p_clcb; 171} 172/******************************************************************************* 173** 174** Function srvc_eng_clcb_dealloc 175** 176** Description The function deallocates a GATT profile connection link control block 177** 178** Returns NTrue the deallocation is successful 179** 180*******************************************************************************/ 181BOOLEAN srvc_eng_clcb_dealloc (UINT16 conn_id) 182{ 183 UINT8 i_clcb = 0; 184 tSRVC_CLCB *p_clcb = NULL; 185 186 for (i_clcb = 0, p_clcb= srvc_eng_cb.clcb; i_clcb < SRVC_MAX_APPS; i_clcb++, p_clcb++) 187 { 188 if (p_clcb->in_use && p_clcb->connected && (p_clcb->conn_id == conn_id)) 189 { 190 memset(p_clcb, 0, sizeof(tSRVC_CLCB)); 191 return TRUE; 192 } 193 } 194 return FALSE; 195} 196/******************************************************************************* 197** Service Engine Server Attributes Database Read/Read Blob Request process 198*******************************************************************************/ 199UINT8 srvc_eng_process_read_req (UINT8 clcb_idx, tGATT_READ_REQ *p_data, tGATTS_RSP *p_rsp, tGATT_STATUS *p_status) 200{ 201 tGATT_STATUS status = GATT_NOT_FOUND; 202 UINT8 act = SRVC_ACT_RSP; 203 204 if (p_data->is_long) 205 p_rsp->attr_value.offset = p_data->offset; 206 207 p_rsp->attr_value.handle = p_data->handle; 208 209 if (dis_valid_handle_range(p_data->handle)) 210 act = dis_read_attr_value(clcb_idx, p_data->handle, &p_rsp->attr_value, p_data->is_long, p_status); 211 212 else if (battery_valid_handle_range(p_data->handle)) 213 act = battery_s_read_attr_value(clcb_idx, p_data->handle, &p_rsp->attr_value, p_data->is_long, p_status); 214 215 else 216 *p_status = status; 217 return act; 218} 219/******************************************************************************* 220** Service Engine Server Attributes Database write Request process 221*******************************************************************************/ 222UINT8 srvc_eng_process_write_req (UINT8 clcb_idx, tGATT_WRITE_REQ *p_data, tGATTS_RSP *p_rsp, tGATT_STATUS *p_status) 223{ 224 UINT8 act = SRVC_ACT_RSP; 225 226 if (dis_valid_handle_range(p_data->handle)) 227 { 228 act = dis_write_attr_value(p_data, p_status); 229 } 230 else if (battery_valid_handle_range(p_data->handle)) 231 { 232 act = battery_s_write_attr_value(clcb_idx, p_data, p_status); 233 } 234 else 235 *p_status = GATT_NOT_FOUND; 236 237 return act; 238} 239 240/******************************************************************************* 241** 242** Function srvc_eng_s_request_cback 243** 244** Description GATT DIS attribute access request callback. 245** 246** Returns void. 247** 248*******************************************************************************/ 249static void srvc_eng_s_request_cback (UINT16 conn_id, UINT32 trans_id, tGATTS_REQ_TYPE type, 250 tGATTS_DATA *p_data) 251{ 252 UINT8 status = GATT_INVALID_PDU; 253 tGATTS_RSP rsp_msg ; 254 UINT8 act = SRVC_ACT_IGNORE; 255 UINT8 clcb_idx = srvc_eng_find_clcb_idx_by_conn_id(conn_id); 256 257 GATT_TRACE_EVENT1("srvc_eng_s_request_cback : recv type (0x%02x)", type); 258 259 memset(&rsp_msg, 0, sizeof(tGATTS_RSP)); 260 261 srvc_eng_cb.clcb[clcb_idx].trans_id = trans_id; 262 263 switch (type) 264 { 265 case GATTS_REQ_TYPE_READ: 266 act = srvc_eng_process_read_req(clcb_idx, &p_data->read_req, &rsp_msg, &status); 267 break; 268 269 case GATTS_REQ_TYPE_WRITE: 270 act = srvc_eng_process_write_req(clcb_idx, &p_data->write_req, &rsp_msg, &status); 271 if (!p_data->write_req.need_rsp) 272 act = SRVC_ACT_IGNORE; 273 break; 274 275 case GATTS_REQ_TYPE_WRITE_EXEC: 276 GATT_TRACE_EVENT0("Ignore GATT_REQ_EXEC_WRITE/WRITE_CMD" ); 277 break; 278 279 case GATTS_REQ_TYPE_MTU: 280 GATT_TRACE_EVENT1("Get MTU exchange new mtu size: %d", p_data->mtu); 281 break; 282 283 default: 284 GATT_TRACE_EVENT1("Unknown/unexpected LE GAP ATT request: 0x%02x", type); 285 break; 286 } 287 288 srvc_eng_cb.clcb[clcb_idx].trans_id = 0; 289 290 if (act == SRVC_ACT_RSP) 291 GATTS_SendRsp (conn_id, trans_id, status, &rsp_msg); 292 293 294} 295 296 297/******************************************************************************* 298** 299** Function srvc_eng_c_cmpl_cback 300** 301** Description Client operation complete callback. 302** 303** Returns void 304** 305*******************************************************************************/ 306static void srvc_eng_c_cmpl_cback (UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, 307 tGATT_CL_COMPLETE *p_data) 308{ 309 tSRVC_CLCB *p_clcb = srvc_eng_find_clcb_by_conn_id(conn_id); 310 311 GATT_TRACE_EVENT2 ("srvc_eng_c_cmpl_cback() - op_code: 0x%02x status: 0x%02x ", op, status); 312 313 if (p_clcb == NULL) 314 { 315 GATT_TRACE_ERROR0("srvc_eng_c_cmpl_cback received for unknown connection"); 316 return; 317 } 318 319 if (p_clcb->cur_srvc_id != SRVC_ID_NONE && 320 p_clcb->cur_srvc_id <= SRVC_ID_MAX) 321 srvc_eng_c_cmpl_act[p_clcb->cur_srvc_id - 1](p_clcb, op, status, p_data); 322} 323 324 325/******************************************************************************* 326** 327** Function srvc_eng_connect_cback 328** 329** Description Gatt profile connection callback. 330** 331** Returns void 332** 333*******************************************************************************/ 334static void srvc_eng_connect_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id, 335 BOOLEAN connected, tGATT_DISCONN_REASON reason) 336{ 337 GATT_TRACE_EVENT5 ("srvc_eng_connect_cback: from %08x%04x connected:%d conn_id=%d reason = 0x%04x", 338 (bda[0]<<24)+(bda[1]<<16)+(bda[2]<<8)+bda[3], 339 (bda[4]<<8)+bda[5], connected, conn_id, reason); 340 341 if (connected) 342 { 343 if (srvc_eng_clcb_alloc(conn_id, bda) == NULL) 344 { 345 GATT_TRACE_ERROR0 ("srvc_eng_connect_cback: no_resource"); 346 return; 347 } 348 } 349 else 350 { 351 srvc_eng_clcb_dealloc(conn_id); 352 } 353 354} 355/******************************************************************************* 356** 357** Function srvc_eng_c_cmpl_cback 358** 359** Description Client operation complete callback. 360** 361** Returns void 362** 363*******************************************************************************/ 364BOOLEAN srvc_eng_request_channel (BD_ADDR remote_bda, UINT8 srvc_id ) 365{ 366 BOOLEAN set = TRUE; 367 tSRVC_CLCB *p_clcb = srvc_eng_find_clcb_by_bd_addr(remote_bda); 368 369 if (p_clcb == NULL) 370 p_clcb = srvc_eng_clcb_alloc(0, remote_bda); 371 372 if (p_clcb && p_clcb->cur_srvc_id == SRVC_ID_NONE) 373 p_clcb->cur_srvc_id = srvc_id; 374 else 375 set = FALSE; 376 377 return set; 378} 379/******************************************************************************* 380** 381** Function srvc_eng_release_channel 382** 383** Description Client operation complete callback. 384** 385** Returns void 386** 387*******************************************************************************/ 388void srvc_eng_release_channel (UINT16 conn_id) 389{ 390 tSRVC_CLCB *p_clcb = srvc_eng_find_clcb_by_conn_id(conn_id); 391 392 p_clcb->cur_srvc_id = SRVC_ID_NONE; 393 394 /* check pending request */ 395 //if (p_clcb->pend_req == NULL) 396 GATT_Disconnect(p_clcb->conn_id); 397} 398/******************************************************************************* 399** 400** Function srvc_eng_init 401** 402** Description Initializa the GATT Service engine. 403** 404*******************************************************************************/ 405tGATT_STATUS srvc_eng_init (void) 406{ 407 tBT_UUID app_uuid = {LEN_UUID_16, {UUID_SERVCLASS_DEVICE_INFO}}; 408 409 if (srvc_eng_cb.enabled) 410 { 411 GATT_TRACE_ERROR0("DIS already initalized"); 412 } 413 else 414 { 415 memset(&srvc_eng_cb, 0, sizeof(tDIS_CB)); 416 417 /* Create a GATT profile service */ 418 srvc_eng_cb.gatt_if = GATT_Register(&app_uuid, &srvc_gatt_cback); 419 GATT_StartIf(srvc_eng_cb.gatt_if); 420 421 GATT_TRACE_DEBUG1 ("Srvc_Init: gatt_if=%d ", srvc_eng_cb.gatt_if); 422 423 srvc_eng_cb.enabled = TRUE; 424//#if DIS_INCLUDED == TRUE 425 dis_cb.dis_read_uuid_idx = 0xff; 426//#endif 427 } 428 return GATT_SUCCESS; 429} 430 431void srvc_sr_rsp(UINT8 clcb_idx, tGATT_STATUS st, tGATTS_RSP *p_rsp) 432{ 433 if (srvc_eng_cb.clcb[clcb_idx].trans_id != 0) 434 { 435 GATTS_SendRsp(srvc_eng_cb.clcb[clcb_idx].conn_id, 436 srvc_eng_cb.clcb[clcb_idx].trans_id, 437 st, 438 p_rsp); 439 440 srvc_eng_cb.clcb[clcb_idx].trans_id = 0; 441 } 442} 443void srvc_sr_notify(BD_ADDR remote_bda, UINT16 handle, UINT16 len, UINT8 *p_value) 444{ 445 UINT16 conn_id = srvc_eng_find_conn_id_by_bd_addr(remote_bda); 446 447 if (conn_id != GATT_INVALID_CONN_ID) 448 { 449 GATTS_HandleValueNotification( conn_id, handle, len, p_value); 450 } 451} 452 453#endif 454 455 456 457