1/******************************************************************************
2 *
3 *  Copyright (C) 2014 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 <string.h>
19#include <stdio.h>
20#include <stddef.h>
21#include "bt_target.h"
22
23#include "btm_ble_api.h"
24#include "bt_types.h"
25#include "bt_utils.h"
26#include "btu.h"
27#include "btm_int.h"
28#include "hcimsgs.h"
29
30#if (BLE_INCLUDED == TRUE)
31
32tBTM_BLE_BATCH_SCAN_CB ble_batchscan_cb;
33tBTM_BLE_ADV_TRACK_CB ble_advtrack_cb;
34
35
36/* length of each batch scan command */
37#define BTM_BLE_BATCH_SCAN_STORAGE_CFG_LEN      4
38#define BTM_BLE_BATCH_SCAN_PARAM_CONFIG_LEN    12
39#define BTM_BLE_BATCH_SCAN_ENB_DISB_LEN         2
40#define BTM_BLE_BATCH_SCAN_READ_RESULTS_LEN     2
41
42#define BTM_BLE_BATCH_SCAN_CB_EVT_MASK       0xF0
43#define BTM_BLE_BATCH_SCAN_SUBCODE_MASK      0x0F
44
45#define BTM_BLE_TRACK_ADV_CMD_LEN               9
46
47/*******************************************************************************
48**  Local functions
49*******************************************************************************/
50void btm_ble_batchscan_vsc_cmpl_cback (tBTM_VSC_CMPL *p_params);
51void btm_ble_batchscan_cleanup(void);
52
53/*******************************************************************************
54**
55** Function         btm_ble_batchscan_filter_track_adv_vse_cback
56**
57** Description      VSE callback for batch scan, filter, and tracking events.
58**
59** Returns          None
60**
61*******************************************************************************/
62void btm_ble_batchscan_filter_track_adv_vse_cback(UINT8 len, UINT8 *p)
63{
64    UINT8   sub_event = 0, filt_index = 0, addr_type = 0, adv_state = 0;
65    BD_ADDR bd_addr;
66    STREAM_TO_UINT8(sub_event, p);
67
68    BTM_TRACE_EVENT("btm_ble_batchscan_filter_track_adv_vse_cback called with event:%x", sub_event);
69    if (HCI_VSE_SUBCODE_BLE_THRESHOLD_SUB_EVT == sub_event &&
70        NULL != ble_batchscan_cb.p_thres_cback)
71    {
72        ble_batchscan_cb.p_thres_cback(ble_batchscan_cb.ref_value);
73        return;
74    }
75
76    if (HCI_VSE_SUBCODE_BLE_TRACKING_SUB_EVT == sub_event && NULL != ble_advtrack_cb.p_track_cback)
77    {
78        if (len < 10)
79            return;
80        STREAM_TO_UINT8(filt_index, p);
81        STREAM_TO_UINT8(addr_type, p);
82        STREAM_TO_BDADDR(bd_addr, p);
83        STREAM_TO_UINT8(adv_state, p);
84        BTM_TRACE_EVENT("track_adv_vse_cback called: %d, %d, %d", filt_index, addr_type, adv_state);
85        ble_advtrack_cb.p_track_cback(filt_index, addr_type, bd_addr, adv_state,
86            ble_advtrack_cb.ref_value);
87        return;
88    }
89}
90
91/*******************************************************************************
92**
93** Function         btm_ble_batchscan_enq_op_q
94**
95** Description      enqueue a batchscan operation in q to check command complete
96**                  status
97**
98** Returns          void
99**
100*******************************************************************************/
101void btm_ble_batchscan_enq_op_q(UINT8 opcode, tBTM_BLE_BATCH_SCAN_STATE cur_state,
102                                          UINT8 cb_evt, tBTM_BLE_REF_VALUE ref_value)
103{
104    ble_batchscan_cb.op_q.sub_code[ble_batchscan_cb.op_q.next_idx] = (opcode |(cb_evt << 4));
105    ble_batchscan_cb.op_q.cur_state[ble_batchscan_cb.op_q.next_idx] = cur_state;
106    ble_batchscan_cb.op_q.ref_value[ble_batchscan_cb.op_q.next_idx] = ref_value;
107    BTM_TRACE_DEBUG("btm_ble_batchscan_enq_op_q: subcode:%d, Cur_state:%d, ref_value:%d",
108        ble_batchscan_cb.op_q.sub_code[ble_batchscan_cb.op_q.next_idx],
109        ble_batchscan_cb.op_q.cur_state[ble_batchscan_cb.op_q.next_idx],
110        ble_batchscan_cb.op_q.ref_value[ble_batchscan_cb.op_q.next_idx]);
111    ble_batchscan_cb.op_q.next_idx = (ble_batchscan_cb.op_q.next_idx + 1)
112                                        % BTM_BLE_BATCH_SCAN_MAX;
113}
114
115/*******************************************************************************
116**
117** Function         btm_ble_batchscan_enq_rep_q
118**
119** Description      enqueue a batchscan report operation in q to check command complete
120**                  status
121**
122** Returns          void
123**
124*******************************************************************************/
125tBTM_STATUS btm_ble_batchscan_enq_rep_q(UINT8 report_format, tBTM_BLE_REF_VALUE ref_value)
126{
127    int i = 0;
128    for (i = 0; i < BTM_BLE_BATCH_REP_MAIN_Q_SIZE; i++)
129    {
130        if (report_format == ble_batchscan_cb.main_rep_q.rep_mode[i])
131            return BTM_ILLEGAL_VALUE;
132    }
133
134    ble_batchscan_cb.main_rep_q.rep_mode[ble_batchscan_cb.main_rep_q.next_idx] = report_format;
135    ble_batchscan_cb.main_rep_q.ref_value[ble_batchscan_cb.main_rep_q.next_idx] = ref_value;
136    ble_batchscan_cb.main_rep_q.num_records[ble_batchscan_cb.main_rep_q.next_idx] = 0;
137    ble_batchscan_cb.main_rep_q.data_len[ble_batchscan_cb.main_rep_q.next_idx] = 0;
138    ble_batchscan_cb.main_rep_q.p_data[ble_batchscan_cb.main_rep_q.next_idx] = NULL;
139    BTM_TRACE_DEBUG("btm_ble_batchscan_enq_rep_q: index:%d, rep %d, ref %d",
140            ble_batchscan_cb.main_rep_q.next_idx, report_format, ref_value);
141
142    ble_batchscan_cb.main_rep_q.next_idx = (ble_batchscan_cb.main_rep_q.next_idx + 1)
143                                            % BTM_BLE_BATCH_REP_MAIN_Q_SIZE;
144    return BTM_SUCCESS;
145}
146
147/*******************************************************************************
148**
149** Function         btm_ble_batchscan_enq_rep_data
150**
151** Description      setup the data in the main report queue
152**
153** Returns          void
154**
155*******************************************************************************/
156void btm_ble_batchscan_enq_rep_data(UINT8 report_format, UINT8 num_records, UINT8 *p_data,
157                                    UINT8 data_len)
158{
159    int index = 0, len = 0;
160    UINT8 *p_orig_data = NULL, *p_app_data = NULL;
161
162    for (index = 0; index < BTM_BLE_BATCH_REP_MAIN_Q_SIZE; index++)
163    {
164        if (report_format == ble_batchscan_cb.main_rep_q.rep_mode[index])
165            break;
166    }
167
168    BTM_TRACE_DEBUG("btm_ble_batchscan_enq_rep_data: index:%d, rep %d, num %d len : %d",
169        index, report_format, num_records, data_len);
170
171    if (index < BTM_BLE_BATCH_REP_MAIN_Q_SIZE && data_len > 0 && num_records > 0)
172    {
173        len = ble_batchscan_cb.main_rep_q.data_len[index];
174        p_orig_data = ble_batchscan_cb.main_rep_q.p_data[index];
175        if (NULL != p_orig_data)
176        {
177            p_app_data = GKI_getbuf(len + data_len);
178            memcpy(p_app_data, p_orig_data, len);
179            memcpy(p_app_data+len, p_data, data_len);
180            GKI_freebuf(p_orig_data);
181            ble_batchscan_cb.main_rep_q.p_data[index] = p_app_data;
182            ble_batchscan_cb.main_rep_q.num_records[index] += num_records;
183            ble_batchscan_cb.main_rep_q.data_len[index] += data_len;
184        }
185        else
186        {
187            p_app_data = GKI_getbuf(data_len);
188            memcpy(p_app_data, p_data, data_len);
189            ble_batchscan_cb.main_rep_q.p_data[index] = p_app_data;
190            ble_batchscan_cb.main_rep_q.num_records[index] = num_records;
191            ble_batchscan_cb.main_rep_q.data_len[index] = data_len;
192        }
193    }
194}
195
196/*******************************************************************************
197**
198** Function         btm_ble_batchscan_deq_rep_q
199**
200** Description      dequeue a batchscan report  in q when command complete
201**                  is received
202**
203** Returns          void
204**
205*******************************************************************************/
206void btm_ble_batchscan_deq_rep_data(UINT8 report_format, tBTM_BLE_REF_VALUE *p_ref_value,
207                                 UINT8 *p_num_records, UINT8 **p_data, UINT16 *p_data_len)
208{
209    int index = 0;
210
211    for (index = 0; index < BTM_BLE_BATCH_REP_MAIN_Q_SIZE; index++)
212    {
213        if (report_format == ble_batchscan_cb.main_rep_q.rep_mode[index])
214            break;
215    }
216
217    if (BTM_BLE_BATCH_REP_MAIN_Q_SIZE == index)
218    {
219        BTM_TRACE_ERROR("btm_ble_batchscan_deq_rep_data: rep_format:%d not found", report_format);
220        return;
221    }
222
223    *p_num_records = ble_batchscan_cb.main_rep_q.num_records[index];
224    *p_ref_value = ble_batchscan_cb.main_rep_q.ref_value[index];
225    *p_data = ble_batchscan_cb.main_rep_q.p_data[index];
226    *p_data_len = ble_batchscan_cb.main_rep_q.data_len[index];
227
228    ble_batchscan_cb.main_rep_q.p_data[index] = NULL;
229    ble_batchscan_cb.main_rep_q.data_len[index] = 0;
230    ble_batchscan_cb.main_rep_q.rep_mode[index] = 0;
231    ble_batchscan_cb.main_rep_q.ref_value[index] = 0;
232    ble_batchscan_cb.main_rep_q.num_records[index] = 0;
233
234    BTM_TRACE_DEBUG("btm_ble_batchscan_deq_rep_data: index:%d, rep %d, num %d, data_len %d",
235        index, report_format, *p_num_records, *p_data_len);
236
237    ble_batchscan_cb.main_rep_q.pending_idx = (ble_batchscan_cb.main_rep_q.pending_idx + 1)
238                                            % BTM_BLE_BATCH_SCAN_MAX;
239}
240
241/*******************************************************************************
242**
243** Function         btm_ble_batchscan_deq_op_q
244**
245** Description      dequeue a batch scan operation from q when command complete
246**                  is received
247**
248** Returns          void
249**
250*******************************************************************************/
251void btm_ble_batchscan_deq_op_q(UINT8 *p_opcode,tBTM_BLE_BATCH_SCAN_STATE *cur_state,
252                                          UINT8 *p_cb_evt, tBTM_BLE_REF_VALUE *p_ref)
253{
254    *p_cb_evt = (ble_batchscan_cb.op_q.sub_code[ble_batchscan_cb.op_q.pending_idx] >> 4);
255    *p_opcode = (ble_batchscan_cb.op_q.sub_code[ble_batchscan_cb.op_q.pending_idx]
256                                            & BTM_BLE_BATCH_SCAN_SUBCODE_MASK);
257    *p_ref = ble_batchscan_cb.op_q.ref_value[ble_batchscan_cb.op_q.pending_idx];
258    *cur_state = (ble_batchscan_cb.op_q.cur_state[ble_batchscan_cb.op_q.pending_idx]);
259    ble_batchscan_cb.op_q.pending_idx = (ble_batchscan_cb.op_q.pending_idx + 1)
260                                            % BTM_BLE_BATCH_SCAN_MAX;
261}
262
263/*******************************************************************************
264**
265** Function         btm_ble_read_batchscan_reports
266**
267** Description      This function reads the reports from controller
268**
269** Parameters       scan_mode - The mode for which the reports are to be read out from the controller
270**                  ref_value - Reference value
271**
272** Returns          status
273**
274*******************************************************************************/
275tBTM_STATUS btm_ble_read_batchscan_reports(tBTM_BLE_BATCH_SCAN_MODE scan_mode,
276                                          tBTM_BLE_REF_VALUE ref_value)
277{
278    tBTM_STATUS     status = BTM_NO_RESOURCES;
279    UINT8 param[BTM_BLE_BATCH_SCAN_READ_RESULTS_LEN], *pp;
280    pp = param;
281
282    memset(param, 0, BTM_BLE_BATCH_SCAN_READ_RESULTS_LEN);
283
284    UINT8_TO_STREAM (pp, BTM_BLE_BATCH_SCAN_READ_RESULTS);
285    UINT8_TO_STREAM (pp, scan_mode);
286
287    if ((status = BTM_VendorSpecificCommand (HCI_BLE_BATCH_SCAN_OCF,
288            BTM_BLE_BATCH_SCAN_READ_RESULTS_LEN, param, btm_ble_batchscan_vsc_cmpl_cback))
289            != BTM_CMD_STARTED)
290    {
291        BTM_TRACE_ERROR("btm_ble_read_batchscan_reports %d", status);
292        return BTM_ILLEGAL_VALUE;
293    }
294
295    if (BTM_CMD_STARTED == status)
296    {
297        /* The user needs to be provided scan read reports event */
298        btm_ble_batchscan_enq_op_q(BTM_BLE_BATCH_SCAN_READ_RESULTS, ble_batchscan_cb.cur_state,
299                                   BTM_BLE_BATCH_SCAN_READ_REPTS_EVT, ref_value);
300    }
301
302    return status;
303}
304
305/*******************************************************************************
306**
307** Function         btm_ble_batchscan_vsc_cmpl_cback
308**
309** Description      Batch scan VSC complete callback
310**
311** Parameters       p_params - VSC completed callback parameters
312**
313** Returns          void
314**
315*******************************************************************************/
316void btm_ble_batchscan_vsc_cmpl_cback (tBTM_VSC_CMPL *p_params)
317{
318    UINT8  *p = p_params->p_param_buf;
319    UINT16  len = p_params->param_len;
320    tBTM_BLE_REF_VALUE ref_value = 0;
321    int index = 0;
322
323    UINT8  status = 0, subcode = 0, opcode = 0;
324    UINT8 report_format = 0, num_records = 0, cb_evt = 0;
325    UINT16 data_len = 0;
326    tBTM_BLE_BATCH_SCAN_STATE cur_state = 0;
327    tBTM_STATUS btm_status = 0;
328    UINT8 *p_data = NULL;
329
330    if (len < 2)
331    {
332        BTM_TRACE_ERROR("wrong length for btm_ble_batch_scan_vsc_cmpl_cback");
333        btm_ble_batchscan_deq_op_q(&opcode, &cur_state, &cb_evt, &ref_value);
334        return;
335    }
336
337    STREAM_TO_UINT8(status, p);
338    STREAM_TO_UINT8(subcode, p);
339
340    btm_ble_batchscan_deq_op_q(&opcode, &cur_state, &cb_evt, &ref_value);
341
342    BTM_TRACE_DEBUG("btm_ble_batchscan op_code = %02x state = %02x cb_evt = %02x,ref_value=%d",
343        opcode, cur_state, cb_evt, ref_value);
344
345    if (opcode != subcode)
346    {
347        BTM_TRACE_ERROR("Got unexpected VSC cmpl, expected: %d got: %d",subcode,opcode);
348        return;
349    }
350
351    switch (subcode)
352    {
353        case BTM_BLE_BATCH_SCAN_ENB_DISAB_CUST_FEATURE:
354        {
355             if (BTM_SUCCESS == status && BTM_BLE_SCAN_ENABLE_CALLED == cur_state)
356                 ble_batchscan_cb.cur_state = BTM_BLE_SCAN_ENABLED_STATE;
357             else
358             if (BTM_BLE_SCAN_ENABLE_CALLED == cur_state)
359             {
360                 BTM_TRACE_ERROR("SCAN_ENB_DISAB_CUST_FEATURE - Invalid state after enb");
361                 ble_batchscan_cb.cur_state = BTM_BLE_SCAN_INVALID_STATE;
362             }
363
364             BTM_TRACE_DEBUG("BTM_BLE_BATCH_SCAN_ENB_DISAB_CUST_FEAT status = %d, state: %d,evt=%d",
365                                status, ble_batchscan_cb.cur_state, cb_evt);
366
367             if (cb_evt != 0 && NULL != ble_batchscan_cb.p_setup_cback)
368                ble_batchscan_cb.p_setup_cback(cb_evt, ref_value, status);
369             break;
370        }
371
372        case BTM_BLE_BATCH_SCAN_SET_STORAGE_PARAM:
373        {
374            BTM_TRACE_DEBUG("BTM_BLE_BATCH_SCAN_SET_STORAGE_PARAM status = %d, evt=%d",
375                            status, cb_evt);
376            if (cb_evt != 0 && NULL != ble_batchscan_cb.p_setup_cback)
377                ble_batchscan_cb.p_setup_cback(cb_evt, ref_value, status);
378            break;
379        }
380
381        case BTM_BLE_BATCH_SCAN_SET_PARAMS:
382        {
383            BTM_TRACE_DEBUG("BTM_BLE_BATCH_SCAN_SET_PARAMS status = %d,evt=%d", status, cb_evt);
384
385            if (BTM_BLE_SCAN_DISABLE_CALLED == cur_state)
386            {
387                if (BTM_SUCCESS == status)
388                {
389                    ble_batchscan_cb.cur_state = BTM_BLE_SCAN_DISABLED_STATE;
390                }
391                else
392                {
393                    BTM_TRACE_ERROR("BTM_BLE_BATCH_SCAN_SET_PARAMS - Invalid state after disabled");
394                    ble_batchscan_cb.cur_state = BTM_BLE_SCAN_INVALID_STATE;
395                }
396            }
397
398            if (cb_evt != 0 && NULL != ble_batchscan_cb.p_setup_cback)
399               ble_batchscan_cb.p_setup_cback(cb_evt, ref_value, status);
400            break;
401        }
402
403        case BTM_BLE_BATCH_SCAN_READ_RESULTS:
404        {
405            if (cb_evt != 0 && NULL != ble_batchscan_cb.p_scan_rep_cback)
406            {
407                STREAM_TO_UINT8(report_format,p);
408                STREAM_TO_UINT8(num_records, p);
409                p = (uint8_t *)(p_params->p_param_buf + 4);
410                BTM_TRACE_DEBUG("BTM_BLE_BATCH_SCAN_READ_RESULTS status=%d,len=%d,rec=%d",
411                    status, len-4, num_records);
412
413                if (0 == num_records)
414                {
415                    btm_ble_batchscan_deq_rep_data(report_format, &ref_value, &num_records,
416                                                   &p_data, &data_len);
417                    if (NULL != ble_batchscan_cb.p_scan_rep_cback)
418                        ble_batchscan_cb.p_scan_rep_cback(ref_value,report_format, num_records,
419                                                          data_len, p_data, status);
420                }
421                else
422                {
423                    if ((len-4) > 0)
424                    {
425                        btm_ble_batchscan_enq_rep_data(report_format, num_records, p, len-4);
426                        /* More records could be in the buffer and needs to be pulled out */
427                        btm_status = btm_ble_read_batchscan_reports(report_format, ref_value);
428                        if (BTM_CMD_STARTED != btm_status)
429                        {
430                            btm_ble_batchscan_deq_rep_data(report_format, &ref_value, &num_records,
431                                                           &p_data, &data_len);
432                            /* Send whatever is available, in case of a command failure */
433                            if (NULL != ble_batchscan_cb.p_scan_rep_cback && NULL != p_data)
434                                ble_batchscan_cb.p_scan_rep_cback(ref_value,report_format,
435                                                 num_records, data_len, p_data, status);
436                        }
437                    }
438                }
439            }
440            break;
441        }
442
443        default:
444            break;
445    }
446
447    return;
448}
449
450/*******************************************************************************
451**
452** Function         btm_ble_set_storage_config
453**
454** Description      This function writes the storage configuration in controller
455**
456** Parameters       batch_scan_full_max -Max storage space (in %) allocated to full scanning
457**                  batch_scan_trunc_max -Max storage space (in %) allocated to truncated scanning
458**                  batch_scan_notify_threshold - Setup notification level based on total space
459**
460** Returns          status
461**
462*******************************************************************************/
463tBTM_STATUS btm_ble_set_storage_config(UINT8 batch_scan_full_max, UINT8 batch_scan_trunc_max,
464                                       UINT8 batch_scan_notify_threshold)
465{
466    tBTM_STATUS     status = BTM_NO_RESOURCES;
467    UINT8 param[BTM_BLE_BATCH_SCAN_STORAGE_CFG_LEN], *pp;
468
469    pp = param;
470    memset(param, 0, BTM_BLE_BATCH_SCAN_STORAGE_CFG_LEN);
471
472    UINT8_TO_STREAM (pp, BTM_BLE_BATCH_SCAN_SET_STORAGE_PARAM);
473    UINT8_TO_STREAM (pp, batch_scan_full_max);
474    UINT8_TO_STREAM (pp, batch_scan_trunc_max);
475    UINT8_TO_STREAM (pp, batch_scan_notify_threshold);
476
477    if ((status = BTM_VendorSpecificCommand (HCI_BLE_BATCH_SCAN_OCF,
478                BTM_BLE_BATCH_SCAN_STORAGE_CFG_LEN, param,
479                btm_ble_batchscan_vsc_cmpl_cback))!= BTM_CMD_STARTED)
480    {
481        BTM_TRACE_ERROR("btm_ble_set_storage_config %d", status);
482        return BTM_ILLEGAL_VALUE;
483    }
484
485    return status;
486}
487
488/*******************************************************************************
489**
490** Function         btm_ble_set_batchscan_param
491**
492** Description      This function writes the batch scan params in controller
493**
494** Parameters       scan_mode -Batch scan mode
495**                  scan_interval - Scan interval
496**                  scan_window  - Scan window
497**                  discard_rule -Discard rules
498**                  addr_type - Address type
499**
500** Returns          status
501**
502*******************************************************************************/
503tBTM_STATUS btm_ble_set_batchscan_param(tBTM_BLE_BATCH_SCAN_MODE scan_mode,
504                     UINT32 scan_interval, UINT32 scan_window, tBLE_ADDR_TYPE addr_type,
505                     tBTM_BLE_DISCARD_RULE discard_rule)
506{
507    tBTM_STATUS     status = BTM_NO_RESOURCES;
508    UINT8 scan_param[BTM_BLE_BATCH_SCAN_PARAM_CONFIG_LEN], *pp_scan;
509
510    pp_scan = scan_param;
511    memset(scan_param, 0, BTM_BLE_BATCH_SCAN_PARAM_CONFIG_LEN);
512
513    UINT8_TO_STREAM (pp_scan, BTM_BLE_BATCH_SCAN_SET_PARAMS);
514    UINT8_TO_STREAM (pp_scan, scan_mode);
515    UINT32_TO_STREAM (pp_scan, scan_window);
516    UINT32_TO_STREAM (pp_scan, scan_interval);
517    UINT8_TO_STREAM (pp_scan, addr_type);
518    UINT8_TO_STREAM (pp_scan, discard_rule);
519
520    if ((status = BTM_VendorSpecificCommand (HCI_BLE_BATCH_SCAN_OCF,
521            BTM_BLE_BATCH_SCAN_PARAM_CONFIG_LEN,
522            scan_param, btm_ble_batchscan_vsc_cmpl_cback))!= BTM_CMD_STARTED)
523    {
524        BTM_TRACE_ERROR("btm_ble_set_batchscan_param %d", status);
525        return BTM_ILLEGAL_VALUE;
526    }
527
528    return status;
529}
530
531/*******************************************************************************
532**
533** Function         btm_ble_enable_disable_batchscan
534**
535** Description      This function enables the customer specific feature in controller
536**
537** Parameters       enable_disable: true - enable, false - disable
538**
539** Returns          status
540**
541*******************************************************************************/
542tBTM_STATUS btm_ble_enable_disable_batchscan(BOOLEAN should_enable)
543{
544    tBTM_STATUS     status = BTM_NO_RESOURCES;
545    UINT8 shld_enable = 0x01;
546    UINT8 enable_param[BTM_BLE_BATCH_SCAN_ENB_DISB_LEN], *pp_enable;
547
548    if (!should_enable)
549        shld_enable = 0x00;
550
551    if (should_enable)
552    {
553        pp_enable = enable_param;
554        memset(enable_param, 0, BTM_BLE_BATCH_SCAN_ENB_DISB_LEN);
555
556        UINT8_TO_STREAM (pp_enable, BTM_BLE_BATCH_SCAN_ENB_DISAB_CUST_FEATURE);
557        UINT8_TO_STREAM (pp_enable, shld_enable);
558
559        if ((status = BTM_VendorSpecificCommand(HCI_BLE_BATCH_SCAN_OCF,
560                 BTM_BLE_BATCH_SCAN_ENB_DISB_LEN, enable_param,
561                 btm_ble_batchscan_vsc_cmpl_cback)) != BTM_CMD_STARTED)
562        {
563            status = BTM_MODE_UNSUPPORTED;
564            BTM_TRACE_ERROR("btm_ble_enable_disable_batchscan %d", status);
565            return BTM_ILLEGAL_VALUE;
566        }
567    }
568    else
569    if ((status = btm_ble_set_batchscan_param(BTM_BLE_BATCH_SCAN_MODE_DISABLE,
570                   ble_batchscan_cb.scan_interval, ble_batchscan_cb.scan_window,
571                   ble_batchscan_cb.addr_type, ble_batchscan_cb.discard_rule)) != BTM_CMD_STARTED)
572    {
573         status = BTM_MODE_UNSUPPORTED;
574         BTM_TRACE_ERROR("btm_ble_enable_disable_batchscan %d", status);
575         return BTM_ILLEGAL_VALUE;
576    }
577
578    if (should_enable)
579        ble_batchscan_cb.cur_state = BTM_BLE_SCAN_ENABLE_CALLED;
580    else
581        ble_batchscan_cb.cur_state = BTM_BLE_SCAN_DISABLE_CALLED;
582    return status;
583}
584
585/*******************************************************************************
586**
587** Function         BTM_BleSetStorageConfig
588**
589** Description      This function is called to write storage config params.
590**
591** Parameters:      batch_scan_full_max - Max storage space (in %) allocated to full style
592**                  batch_scan_trunc_max - Max storage space (in %) allocated to trunc style
593**                  batch_scan_notify_threshold - Setup notification level based on total space
594**                  p_setup_cback - Setup callback pointer
595**                  p_thres_cback - Threshold callback pointer
596**                  p_rep_cback - Reports callback pointer
597**                  ref_value - Reference value
598**
599** Returns          tBTM_STATUS
600**
601*******************************************************************************/
602tBTM_STATUS BTM_BleSetStorageConfig(UINT8 batch_scan_full_max, UINT8 batch_scan_trunc_max,
603                                        UINT8 batch_scan_notify_threshold,
604                                        tBTM_BLE_SCAN_SETUP_CBACK *p_setup_cback,
605                                        tBTM_BLE_SCAN_THRESHOLD_CBACK *p_thres_cback,
606                                        tBTM_BLE_SCAN_REP_CBACK* p_rep_cback,
607                                        tBTM_BLE_REF_VALUE ref_value)
608{
609    tBTM_STATUS     status = BTM_NO_RESOURCES;
610    tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
611
612    BTM_TRACE_EVENT (" BTM_BleSetStorageConfig: %d, %d, %d, %d, %d",
613        ble_batchscan_cb.cur_state, ref_value, batch_scan_full_max, batch_scan_trunc_max,
614        batch_scan_notify_threshold);
615
616    if (!HCI_LE_HOST_SUPPORTED(btm_cb.devcb.local_lmp_features[HCI_EXT_FEATURES_PAGE_1]))
617        return BTM_ILLEGAL_VALUE;
618
619    BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
620
621    if (0 == cmn_ble_vsc_cb.tot_scan_results_strg)
622    {
623        BTM_TRACE_ERROR("Controller does not support batch scan");
624        return BTM_ERR_PROCESSING;
625    }
626
627    ble_batchscan_cb.p_setup_cback = p_setup_cback;
628    ble_batchscan_cb.p_thres_cback = p_thres_cback;
629    ble_batchscan_cb.p_scan_rep_cback = p_rep_cback;
630    ble_batchscan_cb.ref_value = ref_value;
631
632    if (batch_scan_full_max > BTM_BLE_ADV_SCAN_FULL_MAX ||
633        batch_scan_trunc_max > BTM_BLE_ADV_SCAN_TRUNC_MAX ||
634        batch_scan_notify_threshold > BTM_BLE_ADV_SCAN_THR_MAX)
635    {
636        BTM_TRACE_ERROR("Illegal set storage config params");
637        return BTM_ILLEGAL_VALUE;
638    }
639
640     if (BTM_BLE_SCAN_INVALID_STATE == ble_batchscan_cb.cur_state ||
641         BTM_BLE_SCAN_DISABLED_STATE == ble_batchscan_cb.cur_state ||
642         BTM_BLE_SCAN_DISABLE_CALLED == ble_batchscan_cb.cur_state)
643    {
644        status = btm_ble_enable_disable_batchscan(TRUE);
645        if (BTM_CMD_STARTED != status)
646            return status;
647
648        ble_batchscan_cb.cur_state = BTM_BLE_SCAN_ENABLE_CALLED;
649        btm_ble_batchscan_enq_op_q(BTM_BLE_BATCH_SCAN_ENB_DISAB_CUST_FEATURE,
650                                    BTM_BLE_SCAN_ENABLE_CALLED, 0, ref_value);
651    }
652
653    status = btm_ble_set_storage_config(batch_scan_full_max, batch_scan_trunc_max,
654                                        batch_scan_notify_threshold);
655    if (BTM_CMD_STARTED != status)
656       return status;
657            /* The user needs to be provided scan config storage event */
658     btm_ble_batchscan_enq_op_q(BTM_BLE_BATCH_SCAN_SET_STORAGE_PARAM, ble_batchscan_cb.cur_state,
659                                   BTM_BLE_BATCH_SCAN_CFG_STRG_EVT, ref_value);
660
661    return status;
662}
663
664
665/*******************************************************************************
666**
667** Function         BTM_BleEnableBatchScan
668**
669** Description      This function is called to configure and enable batch scanning
670**
671** Parameters:      scan_mode -Batch scan mode
672**                  scan_interval - Scan interval value
673**                  scan_window - Scan window value
674**                  discard_rule - Data discard rule
675**                  ref_value - Reference value
676**
677** Returns          tBTM_STATUS
678**
679*******************************************************************************/
680tBTM_STATUS BTM_BleEnableBatchScan(tBTM_BLE_BATCH_SCAN_MODE scan_mode,
681            UINT32 scan_interval, UINT32 scan_window, tBLE_ADDR_TYPE addr_type,
682            tBTM_BLE_DISCARD_RULE discard_rule, tBTM_BLE_REF_VALUE ref_value)
683{
684    tBTM_STATUS     status = BTM_NO_RESOURCES;
685    tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
686    BTM_TRACE_EVENT (" BTM_BleEnableBatchScan: %d, %d, %d, %d, %d, %d",
687        scan_mode, scan_interval, scan_window, addr_type, discard_rule, ref_value);
688
689    if (!HCI_LE_HOST_SUPPORTED(btm_cb.devcb.local_lmp_features[HCI_EXT_FEATURES_PAGE_1]))
690        return BTM_ILLEGAL_VALUE;
691
692    BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
693
694    if (0 == cmn_ble_vsc_cb.tot_scan_results_strg)
695    {
696        BTM_TRACE_ERROR("Controller does not support batch scan");
697        return BTM_ERR_PROCESSING;
698    }
699
700    BTM_TRACE_DEBUG("BTM_BleEnableBatchScan: %d, %x, %x, %d, %d", scan_mode, scan_interval,
701                                        scan_window, discard_rule, ble_batchscan_cb.cur_state);
702
703    /* Only 16 bits will be used for scan interval and scan window as per agreement with Google */
704    /* So the standard LE range would suffice for scan interval and scan window */
705    if ((BTM_BLE_VALID_PRAM(scan_interval, BTM_BLE_SCAN_INT_MIN, BTM_BLE_SCAN_INT_MAX) ||
706        BTM_BLE_VALID_PRAM(scan_window, BTM_BLE_SCAN_WIN_MIN, BTM_BLE_SCAN_WIN_MAX))
707        && (BTM_BLE_BATCH_SCAN_MODE_PASS == scan_mode || BTM_BLE_BATCH_SCAN_MODE_ACTI == scan_mode
708        || BTM_BLE_BATCH_SCAN_MODE_PASS_ACTI == scan_mode)
709        && (BTM_BLE_DISCARD_OLD_ITEMS == discard_rule ||
710        BTM_BLE_DISCARD_LOWER_RSSI_ITEMS == discard_rule))
711    {
712        if (BTM_BLE_SCAN_INVALID_STATE == ble_batchscan_cb.cur_state ||
713            BTM_BLE_SCAN_DISABLED_STATE == ble_batchscan_cb.cur_state ||
714            BTM_BLE_SCAN_DISABLE_CALLED == ble_batchscan_cb.cur_state)
715        {
716            status = btm_ble_enable_disable_batchscan(TRUE);
717            if (BTM_CMD_STARTED != status)
718               return status;
719            btm_ble_batchscan_enq_op_q(BTM_BLE_BATCH_SCAN_ENB_DISAB_CUST_FEATURE,
720                                       BTM_BLE_SCAN_ENABLE_CALLED, 0, ref_value);
721        }
722
723        ble_batchscan_cb.scan_mode = scan_mode;
724        ble_batchscan_cb.scan_interval = scan_interval;
725        ble_batchscan_cb.scan_window = scan_window;
726        ble_batchscan_cb.addr_type = addr_type;
727        ble_batchscan_cb.discard_rule = discard_rule;
728        /* This command starts batch scanning, if enabled */
729        status = btm_ble_set_batchscan_param(scan_mode, scan_interval, scan_window, addr_type,
730                    discard_rule);
731        if (BTM_CMD_STARTED != status)
732            return status;
733
734        /* The user needs to be provided scan enable event */
735        btm_ble_batchscan_enq_op_q(BTM_BLE_BATCH_SCAN_SET_PARAMS, ble_batchscan_cb.cur_state,
736                                   BTM_BLE_BATCH_SCAN_ENABLE_EVT, ref_value);
737    }
738    else
739    {
740        BTM_TRACE_ERROR("Illegal enable scan params");
741        return BTM_ILLEGAL_VALUE;
742    }
743    return status;
744}
745
746/*******************************************************************************
747**
748** Function         BTM_BleDisableBatchScan
749**
750** Description      This function is called to disable batch scanning
751**
752** Parameters:      ref_value - Reference value
753**
754** Returns          tBTM_STATUS
755**
756*******************************************************************************/
757tBTM_STATUS BTM_BleDisableBatchScan(tBTM_BLE_REF_VALUE ref_value)
758{
759    tBTM_STATUS     status = BTM_NO_RESOURCES;
760    tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
761    BTM_TRACE_EVENT (" BTM_BleDisableBatchScan");
762
763    if (!HCI_LE_HOST_SUPPORTED(btm_cb.devcb.local_lmp_features[HCI_EXT_FEATURES_PAGE_1]))
764        return BTM_ILLEGAL_VALUE;
765
766    BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
767
768    if (0 == cmn_ble_vsc_cb.tot_scan_results_strg)
769    {
770        BTM_TRACE_ERROR("Controller does not support batch scan");
771        return BTM_ERR_PROCESSING;
772    }
773
774    status = btm_ble_enable_disable_batchscan(FALSE);
775    if (BTM_CMD_STARTED == status)
776    {
777       /* The user needs to be provided scan disable event */
778       btm_ble_batchscan_enq_op_q(BTM_BLE_BATCH_SCAN_SET_PARAMS,
779                                  BTM_BLE_SCAN_DISABLE_CALLED, BTM_BLE_BATCH_SCAN_DISABLE_EVT,
780                                  ref_value);
781    }
782
783    return status;
784}
785
786/*******************************************************************************
787**
788** Function         BTM_BleReadScanReports
789**
790** Description      This function is called to start reading batch scan reports
791**
792** Parameters:      scan_mode - Batch scan mode
793**                  ref_value - Reference value
794**
795** Returns          tBTM_STATUS
796**
797*******************************************************************************/
798tBTM_STATUS BTM_BleReadScanReports(tBTM_BLE_BATCH_SCAN_MODE scan_mode,
799                                             tBTM_BLE_REF_VALUE ref_value)
800{
801    tBTM_STATUS     status = BTM_NO_RESOURCES;
802    tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
803    UINT8 read_scan_mode = 0;
804    UINT8  *p_data = NULL, report_format = 0, num_records = 0;
805    UINT16 data_len = 0;
806
807    BTM_TRACE_EVENT (" BTM_BleReadScanReports; %d, %d", scan_mode, ref_value);
808
809    if (!HCI_LE_HOST_SUPPORTED(btm_cb.devcb.local_lmp_features[HCI_EXT_FEATURES_PAGE_1]))
810        return BTM_ILLEGAL_VALUE;
811
812    BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
813
814    if (0 == cmn_ble_vsc_cb.tot_scan_results_strg)
815    {
816        BTM_TRACE_ERROR("Controller does not support batch scan");
817        return BTM_ERR_PROCESSING;
818    }
819
820    /*  Check if the requested scan mode has already been setup by the user */
821    read_scan_mode = ble_batchscan_cb.scan_mode & BTM_BLE_BATCH_SCAN_MODE_ACTI;
822    if (0 == read_scan_mode)
823        read_scan_mode = ble_batchscan_cb.scan_mode & BTM_BLE_BATCH_SCAN_MODE_PASS;
824
825    /* Check only for modes, as scan reports can be called after disabling batch scan */
826    if (read_scan_mode > 0 && (BTM_BLE_BATCH_SCAN_MODE_PASS == scan_mode ||
827        BTM_BLE_BATCH_SCAN_MODE_ACTI == scan_mode))
828    {
829        status = btm_ble_batchscan_enq_rep_q(scan_mode, ref_value);
830        if (BTM_SUCCESS == status)
831        {
832            status = btm_ble_read_batchscan_reports(scan_mode, ref_value);
833            if (BTM_CMD_STARTED != status)
834            {
835                btm_ble_batchscan_deq_rep_data(scan_mode, &ref_value,
836                                               &num_records, &p_data, &data_len);
837            }
838        }
839    }
840    else
841    {
842        BTM_TRACE_ERROR("Illegal read scan params: %d, %d, %d", read_scan_mode, scan_mode,
843            ble_batchscan_cb.cur_state);
844        return BTM_ILLEGAL_VALUE;
845    }
846    return status;
847}
848
849
850/*******************************************************************************
851**
852** Function         BTM_BleTrackAdvertiser
853**
854** Description      This function is called to setup the callback for tracking advertisers
855**
856** Parameters:      p_track_cback - Tracking callback pointer
857**                  ref_value - Reference value
858**
859** Returns          tBTM_STATUS
860**
861*******************************************************************************/
862tBTM_STATUS BTM_BleTrackAdvertiser(tBTM_BLE_TRACK_ADV_CBACK *p_track_cback,
863                                        tBTM_BLE_REF_VALUE ref_value)
864{
865    tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
866    BTM_TRACE_EVENT (" BTM_BleTrackAdvertiser");
867    if (!HCI_LE_HOST_SUPPORTED(btm_cb.devcb.local_lmp_features[HCI_EXT_FEATURES_PAGE_1]))
868        return BTM_ILLEGAL_VALUE;
869
870    BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
871
872    if (0 == cmn_ble_vsc_cb.tot_scan_results_strg)
873    {
874        BTM_TRACE_ERROR("Controller does not support scan storage");
875        return BTM_ERR_PROCESSING;
876    }
877
878    ble_advtrack_cb.p_track_cback = p_track_cback;
879    ble_advtrack_cb.ref_value = ref_value;
880    return BTM_SUCCESS;
881}
882
883/*******************************************************************************
884**
885** Function         btm_ble_batchscan_init
886**
887** Description      This function initialize the batch scan control block.
888**
889** Parameters       None
890**
891** Returns          status
892**
893*******************************************************************************/
894void btm_ble_batchscan_init(void)
895{
896    BTM_TRACE_EVENT (" btm_ble_batchscan_init");
897    memset(&ble_batchscan_cb, 0, sizeof(tBTM_BLE_BATCH_SCAN_CB));
898    memset(&ble_advtrack_cb, 0, sizeof(tBTM_BLE_ADV_TRACK_CB));
899    BTM_RegisterForVSEvents(btm_ble_batchscan_filter_track_adv_vse_cback, TRUE);
900}
901
902/*******************************************************************************
903**
904** Function         btm_ble_batchscan_cleanup
905**
906** Description      This function cleans the batch scan control block.
907**
908** Parameters       None
909**
910** Returns          void
911**
912*******************************************************************************/
913void btm_ble_batchscan_cleanup(void)
914{
915    int index = 0;
916    BTM_TRACE_EVENT (" btm_ble_batchscan_cleanup");
917
918    for (index = 0; index < BTM_BLE_BATCH_REP_MAIN_Q_SIZE; index++)
919    {
920        if (NULL != ble_batchscan_cb.main_rep_q.p_data[index])
921            GKI_freebuf(ble_batchscan_cb.main_rep_q.p_data[index]);
922        ble_batchscan_cb.main_rep_q.p_data[index] = NULL;
923    }
924
925    memset(&ble_batchscan_cb, 0, sizeof(tBTM_BLE_BATCH_SCAN_CB));
926    memset(&ble_advtrack_cb, 0, sizeof(tBTM_BLE_ADV_TRACK_CB));
927}
928
929#endif
930