gap_ble.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797
  1. /******************************************************************************
  2. *
  3. * Copyright (C) 2009-2013 Broadcom Corporation
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at:
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. ******************************************************************************/
  18. #include "common/bt_target.h"
  19. #if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE && GATTS_INCLUDED == TRUE)
  20. #include "common/bt_defs.h"
  21. #include "osi/allocator.h"
  22. #include <string.h>
  23. #include "gap_int.h"
  24. #include "stack/gap_api.h"
  25. #include "stack/gattdefs.h"
  26. #include "stack/gatt_api.h"
  27. #include "gatt_int.h"
  28. #include "btm_int.h"
  29. #include "stack/hcimsgs.h"
  30. #include "stack/sdpdefs.h"
  31. #define GAP_CHAR_ICON_SIZE 2
  32. #define GAP_CHAR_DEV_NAME_SIZE 248
  33. #define GAP_MAX_NUM_INC_SVR 0
  34. #define GAP_MAX_ATTR_NUM (2 * GAP_MAX_CHAR_NUM + GAP_MAX_NUM_INC_SVR + 1)
  35. #define GAP_MAX_CHAR_VALUE_SIZE (30 + GAP_CHAR_DEV_NAME_SIZE)
  36. #ifndef GAP_ATTR_DB_SIZE
  37. #define GAP_ATTR_DB_SIZE GATT_DB_MEM_SIZE(GAP_MAX_NUM_INC_SVR, GAP_MAX_CHAR_NUM, GAP_MAX_CHAR_VALUE_SIZE)
  38. #endif
  39. static void gap_ble_s_attr_request_cback (UINT16 conn_id, UINT32 trans_id, tGATTS_REQ_TYPE op_code, tGATTS_DATA *p_data);
  40. /* client connection callback */
  41. static void gap_ble_c_connect_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id, BOOLEAN connected,
  42. tGATT_DISCONN_REASON reason, tGATT_TRANSPORT transport);
  43. static void gap_ble_c_cmpl_cback (UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, tGATT_CL_COMPLETE *p_data);
  44. static const tGATT_CBACK gap_cback = {
  45. gap_ble_c_connect_cback,
  46. gap_ble_c_cmpl_cback,
  47. NULL,
  48. NULL,
  49. gap_ble_s_attr_request_cback,
  50. NULL,
  51. NULL
  52. };
  53. /*******************************************************************************
  54. **
  55. ** Function gap_find_clcb_by_bd_addr
  56. **
  57. ** Description The function searches all LCB with macthing bd address
  58. **
  59. ** Returns total number of clcb found.
  60. **
  61. *******************************************************************************/
  62. tGAP_CLCB *gap_find_clcb_by_bd_addr(BD_ADDR bda)
  63. {
  64. UINT8 i_clcb;
  65. tGAP_CLCB *p_clcb = NULL;
  66. for (i_clcb = 0, p_clcb = gap_cb.clcb; i_clcb < GAP_MAX_CL; i_clcb++, p_clcb++) {
  67. if (p_clcb->in_use && !memcmp(p_clcb->bda, bda, BD_ADDR_LEN)) {
  68. return p_clcb;
  69. }
  70. }
  71. return NULL;
  72. }
  73. /*******************************************************************************
  74. **
  75. ** Function gap_ble_find_clcb_by_conn_id
  76. **
  77. ** Description The function searches all LCB with macthing connection ID
  78. **
  79. ** Returns total number of clcb found.
  80. **
  81. *******************************************************************************/
  82. tGAP_CLCB *gap_ble_find_clcb_by_conn_id(UINT16 conn_id)
  83. {
  84. UINT8 i_clcb;
  85. tGAP_CLCB *p_clcb = NULL;
  86. for (i_clcb = 0, p_clcb = gap_cb.clcb; i_clcb < GAP_MAX_CL; i_clcb++, p_clcb++) {
  87. if (p_clcb->in_use && p_clcb->connected && p_clcb->conn_id == conn_id) {
  88. return p_clcb;
  89. }
  90. }
  91. return p_clcb;
  92. }
  93. /*******************************************************************************
  94. **
  95. ** Function gap_clcb_alloc
  96. **
  97. ** Description The function allocates a GAP connection link control block
  98. **
  99. ** Returns NULL if not found. Otherwise pointer to the connection link block.
  100. **
  101. *******************************************************************************/
  102. tGAP_CLCB *gap_clcb_alloc (BD_ADDR bda)
  103. {
  104. UINT8 i_clcb = 0;
  105. tGAP_CLCB *p_clcb = NULL;
  106. for (i_clcb = 0, p_clcb = gap_cb.clcb; i_clcb < GAP_MAX_CL; i_clcb++, p_clcb++) {
  107. if (!p_clcb->in_use) {
  108. memset(p_clcb, 0, sizeof(tGAP_CLCB));
  109. p_clcb->in_use = TRUE;
  110. memcpy (p_clcb->bda, bda, BD_ADDR_LEN);
  111. break;
  112. }
  113. }
  114. return p_clcb;
  115. }
  116. /*******************************************************************************
  117. **
  118. ** Function gap_ble_dealloc_clcb
  119. **
  120. ** Description The function clean up the pending request queue in GAP
  121. **
  122. ** Returns none
  123. **
  124. *******************************************************************************/
  125. void gap_ble_dealloc_clcb(tGAP_CLCB *p_clcb)
  126. {
  127. tGAP_BLE_REQ *p_q;
  128. while ((p_q = (tGAP_BLE_REQ *)fixed_queue_dequeue(p_clcb->pending_req_q, 0)) != NULL) {
  129. /* send callback to all pending requests if being removed*/
  130. if (p_q->p_cback != NULL) {
  131. (*p_q->p_cback)(FALSE, p_clcb->bda, 0, NULL);
  132. }
  133. osi_free (p_q);
  134. }
  135. memset(p_clcb, 0, sizeof(tGAP_CLCB));
  136. }
  137. /*******************************************************************************
  138. **
  139. ** Function gap_ble_enqueue_request
  140. **
  141. ** Description The function enqueue a GAP client request
  142. **
  143. ** Returns TRUE is successul; FALSE otherwise
  144. **
  145. *******************************************************************************/
  146. BOOLEAN gap_ble_enqueue_request (tGAP_CLCB *p_clcb, UINT16 uuid, tGAP_BLE_CMPL_CBACK *p_cback)
  147. {
  148. tGAP_BLE_REQ *p_q = (tGAP_BLE_REQ *)osi_malloc(sizeof(tGAP_BLE_REQ));
  149. if (p_q != NULL) {
  150. p_q->p_cback = p_cback;
  151. p_q->uuid = uuid;
  152. fixed_queue_enqueue(p_clcb->pending_req_q, p_q, FIXED_QUEUE_MAX_TIMEOUT);
  153. return TRUE;
  154. }
  155. return FALSE;
  156. }
  157. /*******************************************************************************
  158. **
  159. ** Function gap_ble_dequeue_request
  160. **
  161. ** Description The function dequeue a GAP client request if any
  162. **
  163. ** Returns TRUE is successul; FALSE otherwise
  164. **
  165. *******************************************************************************/
  166. BOOLEAN gap_ble_dequeue_request (tGAP_CLCB *p_clcb, UINT16 *p_uuid, tGAP_BLE_CMPL_CBACK **p_cback)
  167. {
  168. tGAP_BLE_REQ *p_q = (tGAP_BLE_REQ *)fixed_queue_dequeue(p_clcb->pending_req_q, 0);;
  169. if (p_q != NULL) {
  170. *p_cback = p_q->p_cback;
  171. *p_uuid = p_q->uuid;
  172. osi_free((void *)p_q);
  173. return TRUE;
  174. }
  175. return FALSE;
  176. }
  177. /*******************************************************************************
  178. ** GAP Attributes Database Request callback
  179. *******************************************************************************/
  180. tGATT_STATUS gap_read_attr_value (UINT16 handle, tGATT_VALUE *p_value, BOOLEAN is_long)
  181. {
  182. tGAP_ATTR *p_db_attr = gap_cb.gap_attr;
  183. UINT8 *p = p_value->value, i;
  184. UINT16 offset = p_value->offset;
  185. UINT8 *p_dev_name = NULL;
  186. for (i = 0; i < GAP_MAX_CHAR_NUM; i ++, p_db_attr ++) {
  187. if (handle == p_db_attr->handle) {
  188. if (p_db_attr->uuid != GATT_UUID_GAP_DEVICE_NAME &&
  189. is_long == TRUE) {
  190. return GATT_NOT_LONG;
  191. }
  192. switch (p_db_attr->uuid) {
  193. case GATT_UUID_GAP_DEVICE_NAME:
  194. BTM_ReadLocalDeviceName((char **)&p_dev_name);
  195. if (strlen ((char *)p_dev_name) > GATT_MAX_ATTR_LEN) {
  196. p_value->len = GATT_MAX_ATTR_LEN;
  197. } else {
  198. p_value->len = (UINT16)strlen ((char *)p_dev_name);
  199. }
  200. if (offset > p_value->len) {
  201. return GATT_INVALID_OFFSET;
  202. } else {
  203. p_value->len -= offset;
  204. p_dev_name += offset;
  205. ARRAY_TO_STREAM(p, p_dev_name, p_value->len);
  206. GAP_TRACE_EVENT("GATT_UUID_GAP_DEVICE_NAME len=0x%04x", p_value->len);
  207. }
  208. break;
  209. case GATT_UUID_GAP_ICON:
  210. UINT16_TO_STREAM(p, p_db_attr->attr_value.icon);
  211. p_value->len = 2;
  212. break;
  213. case GATT_UUID_GAP_PREF_CONN_PARAM:
  214. UINT16_TO_STREAM(p, p_db_attr->attr_value.conn_param.int_min); /* int_min */
  215. UINT16_TO_STREAM(p, p_db_attr->attr_value.conn_param.int_max); /* int_max */
  216. UINT16_TO_STREAM(p, p_db_attr->attr_value.conn_param.latency); /* latency */
  217. UINT16_TO_STREAM(p, p_db_attr->attr_value.conn_param.sp_tout); /* sp_tout */
  218. p_value->len = 8;
  219. break;
  220. /* address resolution */
  221. case GATT_UUID_GAP_CENTRAL_ADDR_RESOL:
  222. UINT8_TO_STREAM(p, p_db_attr->attr_value.addr_resolution);
  223. p_value->len = 1;
  224. break;
  225. }
  226. return GATT_SUCCESS;
  227. }
  228. }
  229. return GATT_NOT_FOUND;
  230. }
  231. /*******************************************************************************
  232. ** GAP Attributes Database Read/Read Blob Request process
  233. *******************************************************************************/
  234. tGATT_STATUS gap_proc_read (tGATTS_REQ_TYPE type, tGATT_READ_REQ *p_data, tGATTS_RSP *p_rsp)
  235. {
  236. tGATT_STATUS status = GATT_NO_RESOURCES;
  237. UNUSED(type);
  238. if (p_data->is_long) {
  239. p_rsp->attr_value.offset = p_data->offset;
  240. }
  241. p_rsp->attr_value.handle = p_data->handle;
  242. status = gap_read_attr_value(p_data->handle, &p_rsp->attr_value, p_data->is_long);
  243. return status;
  244. }
  245. /******************************************************************************
  246. **
  247. ** Function gap_proc_write_req
  248. **
  249. ** Description GAP ATT server process a write request.
  250. **
  251. ** Returns void.
  252. **
  253. *******************************************************************************/
  254. UINT8 gap_proc_write_req( tGATTS_REQ_TYPE type, tGATT_WRITE_REQ *p_data)
  255. {
  256. tGAP_ATTR *p_db_attr = gap_cb.gap_attr;
  257. UINT8 i;
  258. UNUSED(type);
  259. for (i = 0; i < GAP_MAX_CHAR_NUM; i ++, p_db_attr ++) {
  260. if (p_data-> handle == p_db_attr->handle) {
  261. return GATT_WRITE_NOT_PERMIT;
  262. }
  263. }
  264. return GATT_NOT_FOUND;
  265. }
  266. /******************************************************************************
  267. **
  268. ** Function gap_ble_s_attr_request_cback
  269. **
  270. ** Description GAP ATT server attribute access request callback.
  271. **
  272. ** Returns void.
  273. **
  274. *******************************************************************************/
  275. void gap_ble_s_attr_request_cback (UINT16 conn_id, UINT32 trans_id,
  276. tGATTS_REQ_TYPE type, tGATTS_DATA *p_data)
  277. {
  278. UINT8 status = GATT_INVALID_PDU;
  279. tGATTS_RSP rsp_msg;
  280. BOOLEAN ignore = FALSE;
  281. GAP_TRACE_EVENT("gap_ble_s_attr_request_cback : recv type (0x%02x)", type);
  282. memset(&rsp_msg, 0, sizeof(tGATTS_RSP));
  283. switch (type) {
  284. case GATTS_REQ_TYPE_READ:
  285. status = gap_proc_read(type, &p_data->read_req, &rsp_msg);
  286. break;
  287. case GATTS_REQ_TYPE_WRITE:
  288. if (!p_data->write_req.need_rsp) {
  289. ignore = TRUE;
  290. }
  291. status = gap_proc_write_req(type, &p_data->write_req);
  292. break;
  293. case GATTS_REQ_TYPE_WRITE_EXEC:
  294. ignore = TRUE;
  295. GAP_TRACE_EVENT("Ignore GATTS_REQ_TYPE_WRITE_EXEC" );
  296. break;
  297. case GATTS_REQ_TYPE_MTU:
  298. GAP_TRACE_EVENT("Get MTU exchange new mtu size: %d", p_data->mtu);
  299. ignore = TRUE;
  300. break;
  301. default:
  302. GAP_TRACE_EVENT("Unknown/unexpected LE GAP ATT request: 0x%02x", type);
  303. break;
  304. }
  305. if (!ignore) {
  306. GATTS_SendRsp (conn_id, trans_id, status, &rsp_msg);
  307. }
  308. }
  309. /*******************************************************************************
  310. **
  311. ** Function btm_ble_att_db_init
  312. **
  313. ** Description GAP ATT database initalization.
  314. **
  315. ** Returns void.
  316. **
  317. *******************************************************************************/
  318. void gap_attr_db_init(void)
  319. {
  320. tBT_UUID app_uuid = {LEN_UUID_128, {0}};
  321. tBT_UUID uuid = {LEN_UUID_16, {UUID_SERVCLASS_GAP_SERVER}};
  322. UINT16 service_handle;
  323. tGAP_ATTR *p_db_attr = &gap_cb.gap_attr[0];
  324. tGATT_STATUS status;
  325. /* Fill our internal UUID with a fixed pattern 0x82 */
  326. memset (&app_uuid.uu.uuid128, 0x82, LEN_UUID_128);
  327. memset(gap_cb.gap_attr, 0, sizeof(tGAP_ATTR) *GAP_MAX_CHAR_NUM);
  328. gap_cb.gatt_if = GATT_Register(&app_uuid, &gap_cback);
  329. GATT_StartIf(gap_cb.gatt_if);
  330. /* Create a GAP service */
  331. service_handle = GATTS_CreateService (gap_cb.gatt_if, &uuid, 0, GAP_MAX_ATTR_NUM, TRUE);
  332. GAP_TRACE_EVENT ("gap_attr_db_init service_handle = %d", service_handle);
  333. /* add Device Name Characteristic
  334. */
  335. uuid.len = LEN_UUID_16;
  336. uuid.uu.uuid16 = p_db_attr->uuid = GATT_UUID_GAP_DEVICE_NAME;
  337. p_db_attr->handle = GATTS_AddCharacteristic(service_handle, &uuid, GATT_PERM_READ, GATT_CHAR_PROP_BIT_READ,
  338. NULL, NULL);
  339. p_db_attr ++;
  340. /* add Icon characteristic
  341. */
  342. uuid.uu.uuid16 = p_db_attr->uuid = GATT_UUID_GAP_ICON;
  343. p_db_attr->handle = GATTS_AddCharacteristic(service_handle,
  344. &uuid,
  345. GATT_PERM_READ,
  346. GATT_CHAR_PROP_BIT_READ,
  347. NULL, NULL);
  348. p_db_attr ++;
  349. #if ((defined BTM_PERIPHERAL_ENABLED) && (BTM_PERIPHERAL_ENABLED == TRUE))
  350. /* Only needed for peripheral testing */
  351. /* add preferred connection parameter characteristic
  352. */
  353. uuid.uu.uuid16 = p_db_attr->uuid = GATT_UUID_GAP_PREF_CONN_PARAM;
  354. p_db_attr->attr_value.conn_param.int_max = GAP_PREFER_CONN_INT_MAX; /* 6 */
  355. p_db_attr->attr_value.conn_param.int_min = GAP_PREFER_CONN_INT_MIN; /* 0 */
  356. p_db_attr->attr_value.conn_param.latency = GAP_PREFER_CONN_LATENCY; /* 0 */
  357. p_db_attr->attr_value.conn_param.sp_tout = GAP_PREFER_CONN_SP_TOUT; /* 2000 */
  358. p_db_attr->handle = GATTS_AddCharacteristic(service_handle,
  359. &uuid,
  360. GATT_PERM_READ,
  361. GATT_CHAR_PROP_BIT_READ,
  362. NULL, NULL);
  363. p_db_attr ++;
  364. #endif
  365. /* add Central address resolution Characteristic */
  366. uuid.len = LEN_UUID_16;
  367. uuid.uu.uuid16 = p_db_attr->uuid = GATT_UUID_GAP_CENTRAL_ADDR_RESOL;
  368. p_db_attr->handle = GATTS_AddCharacteristic(service_handle, &uuid,
  369. GATT_PERM_READ, GATT_CHAR_PROP_BIT_READ,
  370. NULL, NULL);
  371. p_db_attr->attr_value.addr_resolution = 0;
  372. p_db_attr++;
  373. /* start service now */
  374. memset (&app_uuid.uu.uuid128, 0x81, LEN_UUID_128);
  375. status = GATTS_StartService(gap_cb.gatt_if, service_handle, GAP_TRANSPORT_SUPPORTED );
  376. #if (CONFIG_BT_STACK_NO_LOG)
  377. (void) status;
  378. #endif
  379. GAP_TRACE_EVENT ("GAP App gatt_if: %d s_hdl = %d start_status=%d",
  380. gap_cb.gatt_if, service_handle, status);
  381. }
  382. /*******************************************************************************
  383. **
  384. ** Function GAP_BleAttrDBUpdate
  385. **
  386. ** Description GAP ATT database update.
  387. **
  388. ** Returns void.
  389. **
  390. *******************************************************************************/
  391. void GAP_BleAttrDBUpdate(UINT16 attr_uuid, tGAP_BLE_ATTR_VALUE *p_value)
  392. {
  393. tGAP_ATTR *p_db_attr = gap_cb.gap_attr;
  394. UINT8 i = 0;
  395. GAP_TRACE_EVENT("GAP_BleAttrDBUpdate attr_uuid=0x%04x\n", attr_uuid);
  396. for (i = 0; i < GAP_MAX_CHAR_NUM; i ++, p_db_attr ++) {
  397. if (p_db_attr->uuid == attr_uuid) {
  398. GAP_TRACE_EVENT("Found attr_uuid=0x%04x\n", attr_uuid);
  399. switch (attr_uuid) {
  400. case GATT_UUID_GAP_ICON:
  401. p_db_attr->attr_value.icon = p_value->icon;
  402. break;
  403. case GATT_UUID_GAP_PREF_CONN_PARAM:
  404. memcpy((void *)&p_db_attr->attr_value.conn_param,
  405. (const void *)&p_value->conn_param, sizeof(tGAP_BLE_PREF_PARAM));
  406. break;
  407. case GATT_UUID_GAP_DEVICE_NAME:
  408. BTM_SetLocalDeviceName((char *)p_value->p_dev_name);
  409. break;
  410. case GATT_UUID_GAP_CENTRAL_ADDR_RESOL:
  411. p_db_attr->attr_value.addr_resolution = p_value->addr_resolution;
  412. break;
  413. }
  414. break;
  415. }
  416. }
  417. return;
  418. }
  419. /*******************************************************************************
  420. **
  421. ** Function gap_ble_send_cl_read_request
  422. **
  423. ** Description utility function to send a read request for a GAP charactersitic
  424. **
  425. ** Returns TRUE if read started, else FALSE if GAP is busy
  426. **
  427. *******************************************************************************/
  428. BOOLEAN gap_ble_send_cl_read_request(tGAP_CLCB *p_clcb)
  429. {
  430. tGATT_READ_PARAM param;
  431. UINT16 uuid = 0;
  432. BOOLEAN started = FALSE;
  433. if (gap_ble_dequeue_request(p_clcb, &uuid, &p_clcb->p_cback)) {
  434. memset(&param, 0, sizeof(tGATT_READ_PARAM));
  435. param.service.uuid.len = LEN_UUID_16;
  436. param.service.uuid.uu.uuid16 = uuid;
  437. param.service.s_handle = 1;
  438. param.service.e_handle = 0xFFFF;
  439. param.service.auth_req = 0;
  440. #if (GATTC_INCLUDED == TRUE)
  441. if (GATTC_Read(p_clcb->conn_id, GATT_READ_BY_TYPE, &param) == GATT_SUCCESS) {
  442. p_clcb->cl_op_uuid = uuid;
  443. started = TRUE;
  444. }
  445. #endif ///GATTC_INCLUDED == TRUE
  446. }
  447. return started;
  448. }
  449. /*******************************************************************************
  450. **
  451. ** Function gap_ble_cl_op_cmpl
  452. **
  453. ** Description GAP client operation complete callback
  454. **
  455. ** Returns void
  456. **
  457. *******************************************************************************/
  458. void gap_ble_cl_op_cmpl(tGAP_CLCB *p_clcb, BOOLEAN status, UINT16 len, UINT8 *p_name)
  459. {
  460. tGAP_BLE_CMPL_CBACK *p_cback = p_clcb->p_cback;
  461. UINT16 op = p_clcb->cl_op_uuid;
  462. GAP_TRACE_EVENT("gap_ble_cl_op_cmpl status: %d", status);
  463. p_clcb->cl_op_uuid = 0;
  464. p_clcb->p_cback = NULL;
  465. if (p_cback && op) {
  466. GAP_TRACE_EVENT("calling gap_ble_cl_op_cmpl");
  467. (* p_cback)(status, p_clcb->bda, len, (char *)p_name);
  468. }
  469. /* if no further activity is requested in callback, drop the link */
  470. if (p_clcb->connected) {
  471. if (!gap_ble_send_cl_read_request(p_clcb)) {
  472. GATT_Disconnect(p_clcb->conn_id);
  473. gap_ble_dealloc_clcb(p_clcb);
  474. }
  475. }
  476. }
  477. /*******************************************************************************
  478. **
  479. ** Function gap_ble_c_connect_cback
  480. **
  481. ** Description Client connection callback.
  482. **
  483. ** Returns void
  484. **
  485. *******************************************************************************/
  486. static void gap_ble_c_connect_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id,
  487. BOOLEAN connected, tGATT_DISCONN_REASON reason,
  488. tGATT_TRANSPORT transport)
  489. {
  490. tGAP_CLCB *p_clcb = gap_find_clcb_by_bd_addr (bda);
  491. UNUSED(gatt_if);
  492. UNUSED(transport);
  493. if (p_clcb != NULL) {
  494. if (connected) {
  495. p_clcb->conn_id = conn_id;
  496. p_clcb->connected = TRUE;
  497. /* start operation is pending */
  498. gap_ble_send_cl_read_request(p_clcb);
  499. } else {
  500. p_clcb->connected = FALSE;
  501. gap_ble_cl_op_cmpl(p_clcb, FALSE, 0, NULL);
  502. /* clean up clcb */
  503. gap_ble_dealloc_clcb(p_clcb);
  504. }
  505. }
  506. }
  507. /*******************************************************************************
  508. **
  509. ** Function gap_ble_c_cmpl_cback
  510. **
  511. ** Description Client operation complete callback.
  512. **
  513. ** Returns void
  514. **
  515. *******************************************************************************/
  516. static void gap_ble_c_cmpl_cback (UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, tGATT_CL_COMPLETE *p_data)
  517. {
  518. tGAP_CLCB *p_clcb = gap_ble_find_clcb_by_conn_id(conn_id);
  519. UINT16 op_type;
  520. UINT16 min, max, latency, tout;
  521. UINT16 len;
  522. UINT8 *pp;
  523. if (p_clcb == NULL) {
  524. return;
  525. }
  526. op_type = p_clcb->cl_op_uuid;
  527. GAP_TRACE_EVENT ("gap_ble_c_cmpl_cback() - op_code: 0x%02x status: 0x%02x read_type: 0x%04x\n", op, status, op_type);
  528. /* Currently we only issue read commands */
  529. if (op != GATTC_OPTYPE_READ) {
  530. return;
  531. }
  532. if (status != GATT_SUCCESS) {
  533. gap_ble_cl_op_cmpl(p_clcb, FALSE, 0, NULL);
  534. return;
  535. }
  536. pp = p_data->att_value.value;
  537. switch (op_type) {
  538. case GATT_UUID_GAP_PREF_CONN_PARAM:
  539. GAP_TRACE_EVENT ("GATT_UUID_GAP_PREF_CONN_PARAM");
  540. /* Extract the peripheral preferred connection parameters and save them */
  541. STREAM_TO_UINT16 (min, pp);
  542. STREAM_TO_UINT16 (max, pp);
  543. STREAM_TO_UINT16 (latency, pp);
  544. STREAM_TO_UINT16 (tout, pp);
  545. BTM_BleSetPrefConnParams (p_clcb->bda, min, max, latency, tout);
  546. /* release the connection here */
  547. gap_ble_cl_op_cmpl(p_clcb, TRUE, 0, NULL);
  548. break;
  549. case GATT_UUID_GAP_DEVICE_NAME:
  550. GAP_TRACE_EVENT ("GATT_UUID_GAP_DEVICE_NAME\n");
  551. len = (UINT16)strlen((char *)pp);
  552. if (len > GAP_CHAR_DEV_NAME_SIZE) {
  553. len = GAP_CHAR_DEV_NAME_SIZE;
  554. }
  555. gap_ble_cl_op_cmpl(p_clcb, TRUE, len, pp);
  556. break;
  557. case GATT_UUID_GAP_CENTRAL_ADDR_RESOL:
  558. gap_ble_cl_op_cmpl(p_clcb, TRUE, 1, pp);
  559. break;
  560. }
  561. }
  562. /*******************************************************************************
  563. **
  564. ** Function gap_ble_accept_cl_operation
  565. **
  566. ** Description Start a process to read peer address resolution capability
  567. **
  568. ** Returns TRUE if request accepted
  569. **
  570. *******************************************************************************/
  571. BOOLEAN gap_ble_accept_cl_operation(BD_ADDR peer_bda, UINT16 uuid, tGAP_BLE_CMPL_CBACK *p_cback)
  572. {
  573. tGAP_CLCB *p_clcb;
  574. BOOLEAN started = FALSE;
  575. if (p_cback == NULL && uuid != GATT_UUID_GAP_PREF_CONN_PARAM) {
  576. return (started);
  577. }
  578. if ((p_clcb = gap_find_clcb_by_bd_addr (peer_bda)) == NULL) {
  579. if ((p_clcb = gap_clcb_alloc(peer_bda)) == NULL) {
  580. GAP_TRACE_ERROR("gap_ble_accept_cl_operation max connection reached");
  581. return started;
  582. }
  583. }
  584. GAP_TRACE_EVENT ("%s() - BDA: %08x%04x cl_op_uuid: 0x%04x",
  585. __FUNCTION__,
  586. (peer_bda[0] << 24) + (peer_bda[1] << 16) + (peer_bda[2] << 8) + peer_bda[3],
  587. (peer_bda[4] << 8) + peer_bda[5], uuid);
  588. if (GATT_GetConnIdIfConnected(gap_cb.gatt_if, peer_bda, &p_clcb->conn_id, BT_TRANSPORT_LE)) {
  589. p_clcb->connected = TRUE;
  590. }
  591. /* hold the link here */
  592. if (!GATT_Connect(gap_cb.gatt_if, p_clcb->bda, BLE_ADDR_UNKNOWN_TYPE, TRUE, BT_TRANSPORT_LE)) {
  593. return started;
  594. }
  595. /* enqueue the request */
  596. gap_ble_enqueue_request(p_clcb, uuid, p_cback);
  597. if (p_clcb->connected && p_clcb->cl_op_uuid == 0) {
  598. started = gap_ble_send_cl_read_request(p_clcb);
  599. } else { /* wait for connection up or pending operation to finish */
  600. started = TRUE;
  601. }
  602. return started;
  603. }
  604. /*******************************************************************************
  605. **
  606. ** Function GAP_BleReadPeerPrefConnParams
  607. **
  608. ** Description Start a process to read a connected peripheral's preferred
  609. ** connection parameters
  610. **
  611. ** Returns TRUE if read started, else FALSE if GAP is busy
  612. **
  613. *******************************************************************************/
  614. BOOLEAN GAP_BleReadPeerPrefConnParams (BD_ADDR peer_bda)
  615. {
  616. return gap_ble_accept_cl_operation (peer_bda, GATT_UUID_GAP_PREF_CONN_PARAM, NULL);
  617. }
  618. /*******************************************************************************
  619. **
  620. ** Function GAP_BleReadPeerDevName
  621. **
  622. ** Description Start a process to read a connected peripheral's device name.
  623. **
  624. ** Returns TRUE if request accepted
  625. **
  626. *******************************************************************************/
  627. BOOLEAN GAP_BleReadPeerDevName (BD_ADDR peer_bda, tGAP_BLE_CMPL_CBACK *p_cback)
  628. {
  629. return gap_ble_accept_cl_operation (peer_bda, GATT_UUID_GAP_DEVICE_NAME, p_cback);
  630. }
  631. /*******************************************************************************
  632. **
  633. ** Function GAP_BleReadPeerAddressResolutionCap
  634. **
  635. ** Description Start a process to read peer address resolution capability
  636. **
  637. ** Returns TRUE if request accepted
  638. **
  639. *******************************************************************************/
  640. BOOLEAN GAP_BleReadPeerAddressResolutionCap (BD_ADDR peer_bda, tGAP_BLE_CMPL_CBACK *p_cback)
  641. {
  642. return gap_ble_accept_cl_operation(peer_bda, GATT_UUID_GAP_CENTRAL_ADDR_RESOL, p_cback);
  643. }
  644. /*******************************************************************************
  645. **
  646. ** Function GAP_BleCancelReadPeerDevName
  647. **
  648. ** Description Cancel reading a peripheral's device name.
  649. **
  650. ** Returns TRUE if request accepted
  651. **
  652. *******************************************************************************/
  653. BOOLEAN GAP_BleCancelReadPeerDevName (BD_ADDR peer_bda)
  654. {
  655. tGAP_CLCB *p_clcb = gap_find_clcb_by_bd_addr (peer_bda);
  656. GAP_TRACE_EVENT ("GAP_BleCancelReadPeerDevName() - BDA: %08x%04x cl_op_uuid: 0x%04x",
  657. (peer_bda[0] << 24) + (peer_bda[1] << 16) + (peer_bda[2] << 8) + peer_bda[3],
  658. (peer_bda[4] << 8) + peer_bda[5], (p_clcb == NULL) ? 0 : p_clcb->cl_op_uuid);
  659. if (p_clcb == NULL) {
  660. GAP_TRACE_ERROR ("Cannot cancel current op is not get dev name");
  661. return FALSE;
  662. }
  663. if (!p_clcb->connected) {
  664. if (!GATT_CancelConnect(gap_cb.gatt_if, peer_bda, TRUE)) {
  665. GAP_TRACE_ERROR ("Cannot cancel where No connection id");
  666. return FALSE;
  667. }
  668. }
  669. gap_ble_cl_op_cmpl(p_clcb, FALSE, 0, NULL);
  670. return (TRUE);
  671. }
  672. #endif /* BLE_INCLUDED == TRUE && GATTS_INCLUDED == TRUE*/