gap_ble.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823
  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. switch (p_db_attr->uuid) {
  262. #if (GATTS_DEVICE_NAME_WRITABLE == TRUE)
  263. case GATT_UUID_GAP_DEVICE_NAME: {
  264. UINT8 *p_val = p_data->value;
  265. p_val[p_data->len] = '\0';
  266. BTM_SetLocalDeviceName((char *)p_val);
  267. return GATT_SUCCESS;
  268. }
  269. #endif
  270. #if (GATTS_APPEARANCE_WRITABLE == TRUE)
  271. case GATT_UUID_GAP_ICON: {
  272. UINT8 *p_val = p_data->value;
  273. if (p_data->len != sizeof(UINT16)) {
  274. return GATT_INVALID_ATTR_LEN;
  275. }
  276. STREAM_TO_UINT16(p_db_attr->attr_value.icon, p_val);
  277. return GATT_SUCCESS;
  278. }
  279. #endif
  280. default:
  281. break;
  282. }
  283. return GATT_WRITE_NOT_PERMIT;
  284. }
  285. }
  286. return GATT_NOT_FOUND;
  287. }
  288. /******************************************************************************
  289. **
  290. ** Function gap_ble_s_attr_request_cback
  291. **
  292. ** Description GAP ATT server attribute access request callback.
  293. **
  294. ** Returns void.
  295. **
  296. *******************************************************************************/
  297. void gap_ble_s_attr_request_cback (UINT16 conn_id, UINT32 trans_id,
  298. tGATTS_REQ_TYPE type, tGATTS_DATA *p_data)
  299. {
  300. UINT8 status = GATT_INVALID_PDU;
  301. tGATTS_RSP rsp_msg;
  302. BOOLEAN ignore = FALSE;
  303. GAP_TRACE_EVENT("gap_ble_s_attr_request_cback : recv type (0x%02x)", type);
  304. memset(&rsp_msg, 0, sizeof(tGATTS_RSP));
  305. switch (type) {
  306. case GATTS_REQ_TYPE_READ:
  307. status = gap_proc_read(type, &p_data->read_req, &rsp_msg);
  308. break;
  309. case GATTS_REQ_TYPE_WRITE:
  310. if (!p_data->write_req.need_rsp) {
  311. ignore = TRUE;
  312. }
  313. status = gap_proc_write_req(type, &p_data->write_req);
  314. break;
  315. case GATTS_REQ_TYPE_WRITE_EXEC:
  316. ignore = TRUE;
  317. GAP_TRACE_EVENT("Ignore GATTS_REQ_TYPE_WRITE_EXEC" );
  318. break;
  319. case GATTS_REQ_TYPE_MTU:
  320. GAP_TRACE_EVENT("Get MTU exchange new mtu size: %d", p_data->mtu);
  321. ignore = TRUE;
  322. break;
  323. default:
  324. GAP_TRACE_EVENT("Unknown/unexpected LE GAP ATT request: 0x%02x", type);
  325. break;
  326. }
  327. if (!ignore) {
  328. GATTS_SendRsp (conn_id, trans_id, status, &rsp_msg);
  329. }
  330. }
  331. /*******************************************************************************
  332. **
  333. ** Function btm_ble_att_db_init
  334. **
  335. ** Description GAP ATT database initalization.
  336. **
  337. ** Returns void.
  338. **
  339. *******************************************************************************/
  340. void gap_attr_db_init(void)
  341. {
  342. tBT_UUID app_uuid = {LEN_UUID_128, {0}};
  343. tBT_UUID uuid = {LEN_UUID_16, {UUID_SERVCLASS_GAP_SERVER}};
  344. UINT16 service_handle;
  345. tGAP_ATTR *p_db_attr = &gap_cb.gap_attr[0];
  346. tGATT_STATUS status;
  347. /* Fill our internal UUID with a fixed pattern 0x82 */
  348. memset (&app_uuid.uu.uuid128, 0x82, LEN_UUID_128);
  349. memset(gap_cb.gap_attr, 0, sizeof(tGAP_ATTR) *GAP_MAX_CHAR_NUM);
  350. gap_cb.gatt_if = GATT_Register(&app_uuid, &gap_cback);
  351. GATT_StartIf(gap_cb.gatt_if);
  352. /* Create a GAP service */
  353. service_handle = GATTS_CreateService (gap_cb.gatt_if, &uuid, 0, GAP_MAX_ATTR_NUM, TRUE);
  354. GAP_TRACE_EVENT ("gap_attr_db_init service_handle = %d", service_handle);
  355. /* add Device Name Characteristic
  356. */
  357. uuid.len = LEN_UUID_16;
  358. uuid.uu.uuid16 = p_db_attr->uuid = GATT_UUID_GAP_DEVICE_NAME;
  359. p_db_attr->handle = GATTS_AddCharacteristic(service_handle, &uuid,
  360. #if (GATTS_DEVICE_NAME_WRITABLE == TRUE)
  361. GATT_PERM_READ | GATT_PERM_WRITE,
  362. GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_WRITE_NR,
  363. #else
  364. GATT_PERM_READ, GATT_CHAR_PROP_BIT_READ,
  365. #endif
  366. NULL, NULL);
  367. p_db_attr ++;
  368. /* add Icon characteristic
  369. */
  370. uuid.uu.uuid16 = p_db_attr->uuid = GATT_UUID_GAP_ICON;
  371. p_db_attr->handle = GATTS_AddCharacteristic(service_handle, &uuid,
  372. #if (GATTS_APPEARANCE_WRITABLE == TRUE)
  373. GATT_PERM_READ | GATT_PERM_WRITE,
  374. GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_WRITE_NR,
  375. #else
  376. GATT_PERM_READ, GATT_CHAR_PROP_BIT_READ,
  377. #endif
  378. NULL, NULL);
  379. p_db_attr ++;
  380. #if ((defined BTM_PERIPHERAL_ENABLED) && (BTM_PERIPHERAL_ENABLED == TRUE))
  381. /* Only needed for peripheral testing */
  382. /* add preferred connection parameter characteristic
  383. */
  384. uuid.uu.uuid16 = p_db_attr->uuid = GATT_UUID_GAP_PREF_CONN_PARAM;
  385. p_db_attr->attr_value.conn_param.int_max = GAP_PREFER_CONN_INT_MAX; /* 6 */
  386. p_db_attr->attr_value.conn_param.int_min = GAP_PREFER_CONN_INT_MIN; /* 0 */
  387. p_db_attr->attr_value.conn_param.latency = GAP_PREFER_CONN_LATENCY; /* 0 */
  388. p_db_attr->attr_value.conn_param.sp_tout = GAP_PREFER_CONN_SP_TOUT; /* 2000 */
  389. p_db_attr->handle = GATTS_AddCharacteristic(service_handle,
  390. &uuid,
  391. GATT_PERM_READ,
  392. GATT_CHAR_PROP_BIT_READ,
  393. NULL, NULL);
  394. p_db_attr ++;
  395. #endif
  396. /* add Central address resolution Characteristic */
  397. uuid.len = LEN_UUID_16;
  398. uuid.uu.uuid16 = p_db_attr->uuid = GATT_UUID_GAP_CENTRAL_ADDR_RESOL;
  399. p_db_attr->handle = GATTS_AddCharacteristic(service_handle, &uuid,
  400. GATT_PERM_READ, GATT_CHAR_PROP_BIT_READ,
  401. NULL, NULL);
  402. p_db_attr->attr_value.addr_resolution = 0;
  403. p_db_attr++;
  404. /* start service now */
  405. memset (&app_uuid.uu.uuid128, 0x81, LEN_UUID_128);
  406. status = GATTS_StartService(gap_cb.gatt_if, service_handle, GAP_TRANSPORT_SUPPORTED );
  407. #if (CONFIG_BT_STACK_NO_LOG)
  408. (void) status;
  409. #endif
  410. GAP_TRACE_EVENT ("GAP App gatt_if: %d s_hdl = %d start_status=%d",
  411. gap_cb.gatt_if, service_handle, status);
  412. }
  413. /*******************************************************************************
  414. **
  415. ** Function GAP_BleAttrDBUpdate
  416. **
  417. ** Description GAP ATT database update.
  418. **
  419. ** Returns void.
  420. **
  421. *******************************************************************************/
  422. void GAP_BleAttrDBUpdate(UINT16 attr_uuid, tGAP_BLE_ATTR_VALUE *p_value)
  423. {
  424. tGAP_ATTR *p_db_attr = gap_cb.gap_attr;
  425. UINT8 i = 0;
  426. GAP_TRACE_EVENT("GAP_BleAttrDBUpdate attr_uuid=0x%04x\n", attr_uuid);
  427. for (i = 0; i < GAP_MAX_CHAR_NUM; i ++, p_db_attr ++) {
  428. if (p_db_attr->uuid == attr_uuid) {
  429. GAP_TRACE_EVENT("Found attr_uuid=0x%04x\n", attr_uuid);
  430. switch (attr_uuid) {
  431. case GATT_UUID_GAP_ICON:
  432. p_db_attr->attr_value.icon = p_value->icon;
  433. break;
  434. case GATT_UUID_GAP_PREF_CONN_PARAM:
  435. memcpy((void *)&p_db_attr->attr_value.conn_param,
  436. (const void *)&p_value->conn_param, sizeof(tGAP_BLE_PREF_PARAM));
  437. break;
  438. case GATT_UUID_GAP_DEVICE_NAME:
  439. BTM_SetLocalDeviceName((char *)p_value->p_dev_name);
  440. break;
  441. case GATT_UUID_GAP_CENTRAL_ADDR_RESOL:
  442. p_db_attr->attr_value.addr_resolution = p_value->addr_resolution;
  443. break;
  444. }
  445. break;
  446. }
  447. }
  448. return;
  449. }
  450. /*******************************************************************************
  451. **
  452. ** Function gap_ble_send_cl_read_request
  453. **
  454. ** Description utility function to send a read request for a GAP charactersitic
  455. **
  456. ** Returns TRUE if read started, else FALSE if GAP is busy
  457. **
  458. *******************************************************************************/
  459. BOOLEAN gap_ble_send_cl_read_request(tGAP_CLCB *p_clcb)
  460. {
  461. tGATT_READ_PARAM param;
  462. UINT16 uuid = 0;
  463. BOOLEAN started = FALSE;
  464. if (gap_ble_dequeue_request(p_clcb, &uuid, &p_clcb->p_cback)) {
  465. memset(&param, 0, sizeof(tGATT_READ_PARAM));
  466. param.service.uuid.len = LEN_UUID_16;
  467. param.service.uuid.uu.uuid16 = uuid;
  468. param.service.s_handle = 1;
  469. param.service.e_handle = 0xFFFF;
  470. param.service.auth_req = 0;
  471. #if (GATTC_INCLUDED == TRUE)
  472. if (GATTC_Read(p_clcb->conn_id, GATT_READ_BY_TYPE, &param) == GATT_SUCCESS) {
  473. p_clcb->cl_op_uuid = uuid;
  474. started = TRUE;
  475. }
  476. #endif ///GATTC_INCLUDED == TRUE
  477. }
  478. return started;
  479. }
  480. /*******************************************************************************
  481. **
  482. ** Function gap_ble_cl_op_cmpl
  483. **
  484. ** Description GAP client operation complete callback
  485. **
  486. ** Returns void
  487. **
  488. *******************************************************************************/
  489. void gap_ble_cl_op_cmpl(tGAP_CLCB *p_clcb, BOOLEAN status, UINT16 len, UINT8 *p_name)
  490. {
  491. tGAP_BLE_CMPL_CBACK *p_cback = p_clcb->p_cback;
  492. UINT16 op = p_clcb->cl_op_uuid;
  493. GAP_TRACE_EVENT("gap_ble_cl_op_cmpl status: %d", status);
  494. p_clcb->cl_op_uuid = 0;
  495. p_clcb->p_cback = NULL;
  496. if (p_cback && op) {
  497. GAP_TRACE_EVENT("calling gap_ble_cl_op_cmpl");
  498. (* p_cback)(status, p_clcb->bda, len, (char *)p_name);
  499. }
  500. /* if no further activity is requested in callback, drop the link */
  501. if (p_clcb->connected) {
  502. if (!gap_ble_send_cl_read_request(p_clcb)) {
  503. GATT_Disconnect(p_clcb->conn_id);
  504. gap_ble_dealloc_clcb(p_clcb);
  505. }
  506. }
  507. }
  508. /*******************************************************************************
  509. **
  510. ** Function gap_ble_c_connect_cback
  511. **
  512. ** Description Client connection callback.
  513. **
  514. ** Returns void
  515. **
  516. *******************************************************************************/
  517. static void gap_ble_c_connect_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id,
  518. BOOLEAN connected, tGATT_DISCONN_REASON reason,
  519. tGATT_TRANSPORT transport)
  520. {
  521. tGAP_CLCB *p_clcb = gap_find_clcb_by_bd_addr (bda);
  522. UNUSED(gatt_if);
  523. UNUSED(transport);
  524. if (p_clcb != NULL) {
  525. if (connected) {
  526. p_clcb->conn_id = conn_id;
  527. p_clcb->connected = TRUE;
  528. /* start operation is pending */
  529. gap_ble_send_cl_read_request(p_clcb);
  530. } else {
  531. p_clcb->connected = FALSE;
  532. gap_ble_cl_op_cmpl(p_clcb, FALSE, 0, NULL);
  533. /* clean up clcb */
  534. gap_ble_dealloc_clcb(p_clcb);
  535. }
  536. }
  537. }
  538. /*******************************************************************************
  539. **
  540. ** Function gap_ble_c_cmpl_cback
  541. **
  542. ** Description Client operation complete callback.
  543. **
  544. ** Returns void
  545. **
  546. *******************************************************************************/
  547. static void gap_ble_c_cmpl_cback (UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, tGATT_CL_COMPLETE *p_data)
  548. {
  549. tGAP_CLCB *p_clcb = gap_ble_find_clcb_by_conn_id(conn_id);
  550. UINT16 op_type;
  551. UINT16 min, max, latency, tout;
  552. UINT16 len;
  553. UINT8 *pp;
  554. if (p_clcb == NULL) {
  555. return;
  556. }
  557. op_type = p_clcb->cl_op_uuid;
  558. GAP_TRACE_EVENT ("gap_ble_c_cmpl_cback() - op_code: 0x%02x status: 0x%02x read_type: 0x%04x\n", op, status, op_type);
  559. /* Currently we only issue read commands */
  560. if (op != GATTC_OPTYPE_READ) {
  561. return;
  562. }
  563. if (status != GATT_SUCCESS) {
  564. gap_ble_cl_op_cmpl(p_clcb, FALSE, 0, NULL);
  565. return;
  566. }
  567. pp = p_data->att_value.value;
  568. switch (op_type) {
  569. case GATT_UUID_GAP_PREF_CONN_PARAM:
  570. GAP_TRACE_EVENT ("GATT_UUID_GAP_PREF_CONN_PARAM");
  571. /* Extract the peripheral preferred connection parameters and save them */
  572. STREAM_TO_UINT16 (min, pp);
  573. STREAM_TO_UINT16 (max, pp);
  574. STREAM_TO_UINT16 (latency, pp);
  575. STREAM_TO_UINT16 (tout, pp);
  576. BTM_BleSetPrefConnParams (p_clcb->bda, min, max, latency, tout);
  577. /* release the connection here */
  578. gap_ble_cl_op_cmpl(p_clcb, TRUE, 0, NULL);
  579. break;
  580. case GATT_UUID_GAP_DEVICE_NAME:
  581. GAP_TRACE_EVENT ("GATT_UUID_GAP_DEVICE_NAME\n");
  582. len = (UINT16)strlen((char *)pp);
  583. if (len > GAP_CHAR_DEV_NAME_SIZE) {
  584. len = GAP_CHAR_DEV_NAME_SIZE;
  585. }
  586. gap_ble_cl_op_cmpl(p_clcb, TRUE, len, pp);
  587. break;
  588. case GATT_UUID_GAP_CENTRAL_ADDR_RESOL:
  589. gap_ble_cl_op_cmpl(p_clcb, TRUE, 1, pp);
  590. break;
  591. }
  592. }
  593. /*******************************************************************************
  594. **
  595. ** Function gap_ble_accept_cl_operation
  596. **
  597. ** Description Start a process to read peer address resolution capability
  598. **
  599. ** Returns TRUE if request accepted
  600. **
  601. *******************************************************************************/
  602. BOOLEAN gap_ble_accept_cl_operation(BD_ADDR peer_bda, UINT16 uuid, tGAP_BLE_CMPL_CBACK *p_cback)
  603. {
  604. tGAP_CLCB *p_clcb;
  605. BOOLEAN started = FALSE;
  606. if (p_cback == NULL && uuid != GATT_UUID_GAP_PREF_CONN_PARAM) {
  607. return (started);
  608. }
  609. if ((p_clcb = gap_find_clcb_by_bd_addr (peer_bda)) == NULL) {
  610. if ((p_clcb = gap_clcb_alloc(peer_bda)) == NULL) {
  611. GAP_TRACE_ERROR("gap_ble_accept_cl_operation max connection reached");
  612. return started;
  613. }
  614. }
  615. GAP_TRACE_EVENT ("%s() - BDA: %08x%04x cl_op_uuid: 0x%04x",
  616. __FUNCTION__,
  617. (peer_bda[0] << 24) + (peer_bda[1] << 16) + (peer_bda[2] << 8) + peer_bda[3],
  618. (peer_bda[4] << 8) + peer_bda[5], uuid);
  619. if (GATT_GetConnIdIfConnected(gap_cb.gatt_if, peer_bda, &p_clcb->conn_id, BT_TRANSPORT_LE)) {
  620. p_clcb->connected = TRUE;
  621. }
  622. /* hold the link here */
  623. if (!GATT_Connect(gap_cb.gatt_if, p_clcb->bda, BLE_ADDR_UNKNOWN_TYPE, TRUE, BT_TRANSPORT_LE, FALSE)) {
  624. return started;
  625. }
  626. /* enqueue the request */
  627. gap_ble_enqueue_request(p_clcb, uuid, p_cback);
  628. if (p_clcb->connected && p_clcb->cl_op_uuid == 0) {
  629. started = gap_ble_send_cl_read_request(p_clcb);
  630. } else { /* wait for connection up or pending operation to finish */
  631. started = TRUE;
  632. }
  633. return started;
  634. }
  635. /*******************************************************************************
  636. **
  637. ** Function GAP_BleReadPeerPrefConnParams
  638. **
  639. ** Description Start a process to read a connected peripheral's preferred
  640. ** connection parameters
  641. **
  642. ** Returns TRUE if read started, else FALSE if GAP is busy
  643. **
  644. *******************************************************************************/
  645. BOOLEAN GAP_BleReadPeerPrefConnParams (BD_ADDR peer_bda)
  646. {
  647. return gap_ble_accept_cl_operation (peer_bda, GATT_UUID_GAP_PREF_CONN_PARAM, NULL);
  648. }
  649. /*******************************************************************************
  650. **
  651. ** Function GAP_BleReadPeerDevName
  652. **
  653. ** Description Start a process to read a connected peripheral's device name.
  654. **
  655. ** Returns TRUE if request accepted
  656. **
  657. *******************************************************************************/
  658. BOOLEAN GAP_BleReadPeerDevName (BD_ADDR peer_bda, tGAP_BLE_CMPL_CBACK *p_cback)
  659. {
  660. return gap_ble_accept_cl_operation (peer_bda, GATT_UUID_GAP_DEVICE_NAME, p_cback);
  661. }
  662. /*******************************************************************************
  663. **
  664. ** Function GAP_BleReadPeerAddressResolutionCap
  665. **
  666. ** Description Start a process to read peer address resolution capability
  667. **
  668. ** Returns TRUE if request accepted
  669. **
  670. *******************************************************************************/
  671. BOOLEAN GAP_BleReadPeerAddressResolutionCap (BD_ADDR peer_bda, tGAP_BLE_CMPL_CBACK *p_cback)
  672. {
  673. return gap_ble_accept_cl_operation(peer_bda, GATT_UUID_GAP_CENTRAL_ADDR_RESOL, p_cback);
  674. }
  675. /*******************************************************************************
  676. **
  677. ** Function GAP_BleCancelReadPeerDevName
  678. **
  679. ** Description Cancel reading a peripheral's device name.
  680. **
  681. ** Returns TRUE if request accepted
  682. **
  683. *******************************************************************************/
  684. BOOLEAN GAP_BleCancelReadPeerDevName (BD_ADDR peer_bda)
  685. {
  686. tGAP_CLCB *p_clcb = gap_find_clcb_by_bd_addr (peer_bda);
  687. GAP_TRACE_EVENT ("GAP_BleCancelReadPeerDevName() - BDA: %08x%04x cl_op_uuid: 0x%04x",
  688. (peer_bda[0] << 24) + (peer_bda[1] << 16) + (peer_bda[2] << 8) + peer_bda[3],
  689. (peer_bda[4] << 8) + peer_bda[5], (p_clcb == NULL) ? 0 : p_clcb->cl_op_uuid);
  690. if (p_clcb == NULL) {
  691. GAP_TRACE_ERROR ("Cannot cancel current op is not get dev name");
  692. return FALSE;
  693. }
  694. if (!p_clcb->connected) {
  695. if (!GATT_CancelConnect(gap_cb.gatt_if, peer_bda, TRUE)) {
  696. GAP_TRACE_ERROR ("Cannot cancel where No connection id");
  697. return FALSE;
  698. }
  699. }
  700. gap_ble_cl_op_cmpl(p_clcb, FALSE, 0, NULL);
  701. return (TRUE);
  702. }
  703. #endif /* BLE_INCLUDED == TRUE && GATTS_INCLUDED == TRUE*/