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