btm_ble_batchscan.c revision 16fe0822ccd3eb6f66d3afd9965d25a0a0cb4c30
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);
51
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
176        if (NULL != p_orig_data)
177        {
178            p_app_data = GKI_getbuf(len + data_len);
179            memcpy(p_app_data, p_orig_data, len);
180            memcpy(p_app_data+len, p_data, data_len);
181            GKI_freebuf(p_orig_data);
182            ble_batchscan_cb.main_rep_q.p_data[index] = p_app_data;
183        }
184        else
185        {
186            p_app_data = GKI_getbuf(data_len);
187            memcpy(p_app_data, p_data, data_len);
188            ble_batchscan_cb.main_rep_q.p_data[index] = p_app_data;
189        }
190
191        ble_batchscan_cb.main_rep_q.num_records[index] += num_records;
192        ble_batchscan_cb.main_rep_q.data_len[index] += data_len;
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             if (BTM_SUCCESS == status && BTM_BLE_SCAN_DISABLE_CALLED == cur_state)
365                ble_batchscan_cb.cur_state = BTM_BLE_SCAN_DISABLED_STATE;
366             else
367             if (BTM_BLE_SCAN_DISABLE_CALLED == cur_state)
368             {
369                BTM_TRACE_ERROR("SCAN_ENB_DISAB_CUST_FEATURE - Invalid state after disabled");
370                ble_batchscan_cb.cur_state = BTM_BLE_SCAN_INVALID_STATE;
371             }
372             BTM_TRACE_DEBUG("BTM_BLE_BATCH_SCAN_ENB_DISAB_CUST_FEAT status = %d, state: %d,evt=%d",
373                                status, ble_batchscan_cb.cur_state, cb_evt);
374             if (cb_evt != 0 && NULL != ble_batchscan_cb.p_setup_cback)
375                ble_batchscan_cb.p_setup_cback(cb_evt, ref_value, status);
376             break;
377        }
378
379        case BTM_BLE_BATCH_SCAN_SET_STORAGE_PARAM:
380        {
381            BTM_TRACE_DEBUG("BTM_BLE_BATCH_SCAN_SET_STORAGE_PARAM status = %d, evt=%d",
382                            status, cb_evt);
383            if (cb_evt != 0 && NULL != ble_batchscan_cb.p_setup_cback)
384                ble_batchscan_cb.p_setup_cback(cb_evt, ref_value, status);
385            break;
386        }
387
388        case BTM_BLE_BATCH_SCAN_SET_PARAMS:
389        {
390            BTM_TRACE_DEBUG("BTM_BLE_BATCH_SCAN_SET_PARAMS status = %d,evt=%d", status, cb_evt);
391            if (cb_evt != 0 && NULL != ble_batchscan_cb.p_setup_cback)
392               ble_batchscan_cb.p_setup_cback(cb_evt, ref_value, status);
393            break;
394        }
395
396        case BTM_BLE_BATCH_SCAN_READ_RESULTS:
397        {
398            if (cb_evt != 0 && NULL != ble_batchscan_cb.p_scan_rep_cback)
399            {
400                STREAM_TO_UINT8(report_format,p);
401                STREAM_TO_UINT8(num_records, p);
402                p = (uint8_t *)(p_params->p_param_buf + 4);
403                BTM_TRACE_DEBUG("BTM_BLE_BATCH_SCAN_READ_RESULTS status=%d,len=%d,rec=%d",
404                    status, len-4, num_records);
405
406                if (0 == num_records)
407                {
408                    btm_ble_batchscan_deq_rep_data(report_format, &ref_value, &num_records,
409                                                   &p_data, &data_len);
410                    if (NULL != ble_batchscan_cb.p_scan_rep_cback)
411                        ble_batchscan_cb.p_scan_rep_cback(ref_value,report_format, num_records,
412                                                          data_len, p_data, status);
413                }
414                else
415                {
416                    if ((len-4) > 0)
417                    {
418                        btm_ble_batchscan_enq_rep_data(report_format, num_records, p, len-4);
419                        /* More records could be in the buffer and needs to be pulled out */
420                        btm_status = btm_ble_read_batchscan_reports(report_format, ref_value);
421                        if (BTM_CMD_STARTED != btm_status)
422                        {
423                            btm_ble_batchscan_deq_rep_data(report_format, &ref_value, &num_records,
424                                                           &p_data, &data_len);
425                            /* Send whatever is available, in case of a command failure */
426                            if (NULL != ble_batchscan_cb.p_scan_rep_cback && NULL != p_data)
427                                ble_batchscan_cb.p_scan_rep_cback(ref_value,report_format,
428                                                 num_records, data_len, p_data, status);
429                        }
430                    }
431                }
432            }
433            break;
434        }
435
436        default:
437            break;
438    }
439
440    return;
441}
442
443/*******************************************************************************
444**
445** Function         btm_ble_set_storage_config
446**
447** Description      This function writes the storage configuration in controller
448**
449** Parameters       batch_scan_full_max -Max storage space (in %) allocated to full scanning
450**                  batch_scan_trunc_max -Max storage space (in %) allocated to truncated scanning
451**                  batch_scan_notify_threshold - Setup notification level based on total space
452**
453** Returns          status
454**
455*******************************************************************************/
456tBTM_STATUS btm_ble_set_storage_config(UINT8 batch_scan_full_max, UINT8 batch_scan_trunc_max,
457                                       UINT8 batch_scan_notify_threshold)
458{
459    tBTM_STATUS     status = BTM_NO_RESOURCES;
460    UINT8 param[BTM_BLE_BATCH_SCAN_STORAGE_CFG_LEN], *pp;
461
462    pp = param;
463    memset(param, 0, BTM_BLE_BATCH_SCAN_STORAGE_CFG_LEN);
464
465    UINT8_TO_STREAM (pp, BTM_BLE_BATCH_SCAN_SET_STORAGE_PARAM);
466    UINT8_TO_STREAM (pp, batch_scan_full_max);
467    UINT8_TO_STREAM (pp, batch_scan_trunc_max);
468    UINT8_TO_STREAM (pp, batch_scan_notify_threshold);
469
470    if ((status = BTM_VendorSpecificCommand (HCI_BLE_BATCH_SCAN_OCF,
471                BTM_BLE_BATCH_SCAN_STORAGE_CFG_LEN, param,
472                btm_ble_batchscan_vsc_cmpl_cback))!= BTM_CMD_STARTED)
473    {
474        BTM_TRACE_ERROR("btm_ble_set_storage_config %d", status);
475        return BTM_ILLEGAL_VALUE;
476    }
477
478    return status;
479}
480
481/*******************************************************************************
482**
483** Function         btm_ble_set_batchscan_param
484**
485** Description      This function writes the batch scan params in controller
486**
487** Parameters       scan_mode -Batch scan mode
488**                  scan_interval - Scan interval
489**                  scan_window  - Scan window
490**                  discard_rule -Discard rules
491**                  addr_type - Address type
492**
493** Returns          status
494**
495*******************************************************************************/
496tBTM_STATUS btm_ble_set_batchscan_param(tBTM_BLE_BATCH_SCAN_MODE scan_mode,
497                     UINT32 scan_interval, UINT32 scan_window, tBLE_ADDR_TYPE addr_type,
498                     tBTM_BLE_DISCARD_RULE discard_rule)
499{
500    tBTM_STATUS     status = BTM_NO_RESOURCES;
501    UINT8 scan_param[BTM_BLE_BATCH_SCAN_PARAM_CONFIG_LEN], *pp_scan;
502
503    pp_scan = scan_param;
504    memset(scan_param, 0, BTM_BLE_BATCH_SCAN_PARAM_CONFIG_LEN);
505
506    UINT8_TO_STREAM (pp_scan, BTM_BLE_BATCH_SCAN_SET_PARAMS);
507    UINT8_TO_STREAM (pp_scan, scan_mode);
508    UINT32_TO_STREAM (pp_scan, scan_interval);
509    UINT32_TO_STREAM (pp_scan, scan_window);
510    UINT8_TO_STREAM (pp_scan, addr_type);
511    UINT8_TO_STREAM (pp_scan, discard_rule);
512
513    if ((status = BTM_VendorSpecificCommand (HCI_BLE_BATCH_SCAN_OCF,
514            BTM_BLE_BATCH_SCAN_PARAM_CONFIG_LEN,
515            scan_param, btm_ble_batchscan_vsc_cmpl_cback))!= BTM_CMD_STARTED)
516    {
517        BTM_TRACE_ERROR("btm_ble_set_batchscan_param %d", status);
518        return BTM_ILLEGAL_VALUE;
519    }
520
521    return status;
522}
523
524/*******************************************************************************
525**
526** Function         btm_ble_enable_disable_batchscan
527**
528** Description      This function enables the customer specific feature in controller
529**
530** Parameters       enable_disable: true - enable, false - disable
531**
532** Returns          status
533**
534*******************************************************************************/
535tBTM_STATUS btm_ble_enable_disable_batchscan(BOOLEAN enable_disable)
536{
537    tBTM_STATUS     status = BTM_NO_RESOURCES;
538    UINT8 enb_disble = 0x01;
539    UINT8 enable_param[BTM_BLE_BATCH_SCAN_ENB_DISB_LEN], *pp_enable;
540
541    if (!enable_disable)
542        enb_disble = 0x00;
543
544    pp_enable = enable_param;
545    memset(enable_param, 0, BTM_BLE_BATCH_SCAN_ENB_DISB_LEN);
546
547    UINT8_TO_STREAM (pp_enable, BTM_BLE_BATCH_SCAN_ENB_DISAB_CUST_FEATURE);
548    UINT8_TO_STREAM (pp_enable, enb_disble);
549
550    if ((status = BTM_VendorSpecificCommand (HCI_BLE_BATCH_SCAN_OCF,
551             BTM_BLE_BATCH_SCAN_ENB_DISB_LEN, enable_param,
552             btm_ble_batchscan_vsc_cmpl_cback))!= BTM_CMD_STARTED)
553    {
554        status = BTM_MODE_UNSUPPORTED;
555        BTM_TRACE_ERROR("btm_ble_enable_disable_batchscan %d", status);
556        return BTM_ILLEGAL_VALUE;
557    }
558
559    if (enable_disable)
560        ble_batchscan_cb.cur_state = BTM_BLE_SCAN_ENABLE_CALLED;
561    else
562        ble_batchscan_cb.cur_state = BTM_BLE_SCAN_DISABLE_CALLED;
563    return status;
564}
565
566/*******************************************************************************
567**
568** Function         BTM_BleSetStorageConfig
569**
570** Description      This function is called to write storage config params.
571**
572** Parameters:      batch_scan_full_max - Max storage space (in %) allocated to full style
573**                  batch_scan_trunc_max - Max storage space (in %) allocated to trunc style
574**                  batch_scan_notify_threshold - Setup notification level based on total space
575**                  p_setup_cback - Setup callback pointer
576**                  p_thres_cback - Threshold callback pointer
577**                  p_rep_cback - Reports callback pointer
578**                  ref_value - Reference value
579**
580** Returns          tBTM_STATUS
581**
582*******************************************************************************/
583tBTM_STATUS BTM_BleSetStorageConfig(UINT8 batch_scan_full_max, UINT8 batch_scan_trunc_max,
584                                        UINT8 batch_scan_notify_threshold,
585                                        tBTM_BLE_SCAN_SETUP_CBACK *p_setup_cback,
586                                        tBTM_BLE_SCAN_THRESHOLD_CBACK *p_thres_cback,
587                                        tBTM_BLE_SCAN_REP_CBACK* p_rep_cback,
588                                        tBTM_BLE_REF_VALUE ref_value)
589{
590    tBTM_STATUS     status = BTM_NO_RESOURCES;
591    tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
592
593    BTM_TRACE_EVENT (" BTM_BleSetStorageConfig: %d, %d, %d, %d, %d",
594        ble_batchscan_cb.cur_state, ref_value, batch_scan_full_max, batch_scan_trunc_max,
595        batch_scan_notify_threshold);
596
597    if (!HCI_LE_HOST_SUPPORTED(btm_cb.devcb.local_lmp_features[HCI_EXT_FEATURES_PAGE_1]))
598        return BTM_ILLEGAL_VALUE;
599
600    BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
601
602    if (0 == cmn_ble_vsc_cb.tot_scan_results_strg)
603    {
604        BTM_TRACE_ERROR("Controller does not support batch scan");
605        return BTM_ERR_PROCESSING;
606    }
607
608    ble_batchscan_cb.p_setup_cback = p_setup_cback;
609    ble_batchscan_cb.p_thres_cback = p_thres_cback;
610    ble_batchscan_cb.p_scan_rep_cback = p_rep_cback;
611    ble_batchscan_cb.ref_value = ref_value;
612
613    if (batch_scan_full_max > BTM_BLE_ADV_SCAN_FULL_MAX ||
614        batch_scan_trunc_max > BTM_BLE_ADV_SCAN_TRUNC_MAX ||
615        batch_scan_notify_threshold > BTM_BLE_ADV_SCAN_THR_MAX)
616    {
617        BTM_TRACE_ERROR("Illegal set storage config params");
618        return BTM_ILLEGAL_VALUE;
619    }
620
621     if (BTM_BLE_SCAN_INVALID_STATE == ble_batchscan_cb.cur_state ||
622         BTM_BLE_SCAN_DISABLED_STATE == ble_batchscan_cb.cur_state ||
623         BTM_BLE_SCAN_DISABLE_CALLED == ble_batchscan_cb.cur_state)
624    {
625         status = btm_ble_enable_disable_batchscan(TRUE);
626        if (BTM_CMD_STARTED != status)
627            return status;
628         ble_batchscan_cb.cur_state = BTM_BLE_SCAN_ENABLE_CALLED;
629         btm_ble_batchscan_enq_op_q(BTM_BLE_BATCH_SCAN_ENB_DISAB_CUST_FEATURE,
630                                    BTM_BLE_SCAN_ENABLE_CALLED, 0, ref_value);
631    }
632
633    status = btm_ble_set_storage_config(batch_scan_full_max, batch_scan_trunc_max,
634                                        batch_scan_notify_threshold);
635    if (BTM_CMD_STARTED != status)
636       return status;
637            /* The user needs to be provided scan config storage event */
638     btm_ble_batchscan_enq_op_q(BTM_BLE_BATCH_SCAN_SET_STORAGE_PARAM, ble_batchscan_cb.cur_state,
639                                   BTM_BLE_BATCH_SCAN_CFG_STRG_EVT, ref_value);
640
641    return status;
642}
643
644
645/*******************************************************************************
646**
647** Function         BTM_BleEnableBatchScan
648**
649** Description      This function is called to configure and enable batch scanning
650**
651** Parameters:      scan_mode -Batch scan mode
652**                  scan_interval - Scan interval value
653**                  scan_window - Scan window value
654**                  discard_rule - Data discard rule
655**                  ref_value - Reference value
656**
657** Returns          tBTM_STATUS
658**
659*******************************************************************************/
660tBTM_STATUS BTM_BleEnableBatchScan(tBTM_BLE_BATCH_SCAN_MODE scan_mode,
661            UINT32 scan_interval, UINT32 scan_window, tBLE_ADDR_TYPE addr_type,
662            tBTM_BLE_DISCARD_RULE discard_rule, tBTM_BLE_REF_VALUE ref_value)
663{
664    tBTM_STATUS     status = BTM_NO_RESOURCES;
665    tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
666    BTM_TRACE_EVENT (" BTM_BleEnableBatchScan: %d, %d, %d, %d, %d, %d",
667        scan_mode, scan_interval, scan_window, addr_type, discard_rule, ref_value);
668
669    if (!HCI_LE_HOST_SUPPORTED(btm_cb.devcb.local_lmp_features[HCI_EXT_FEATURES_PAGE_1]))
670        return BTM_ILLEGAL_VALUE;
671
672    BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
673
674    if (0 == cmn_ble_vsc_cb.tot_scan_results_strg)
675    {
676        BTM_TRACE_ERROR("Controller does not support batch scan");
677        return BTM_ERR_PROCESSING;
678    }
679
680    BTM_TRACE_DEBUG("BTM_BleEnableBatchScan: %d, %x, %x, %d, %d", scan_mode, scan_interval,
681                                        scan_window, discard_rule, ble_batchscan_cb.cur_state);
682
683    /* Only 16 bits will be used for scan interval and scan window as per agreement with Google */
684    /* So the standard LE range would suffice for scan interval and scan window */
685    if ((BTM_BLE_VALID_PRAM(scan_interval, BTM_BLE_SCAN_INT_MIN, BTM_BLE_SCAN_INT_MAX) ||
686        BTM_BLE_VALID_PRAM(scan_window, BTM_BLE_SCAN_WIN_MIN, BTM_BLE_SCAN_WIN_MAX))
687        && (BTM_BLE_BATCH_SCAN_MODE_PASS == scan_mode || BTM_BLE_BATCH_SCAN_MODE_ACTI == scan_mode
688        || BTM_BLE_BATCH_SCAN_MODE_PASS_ACTI == scan_mode)
689        && (BTM_BLE_DISCARD_OLD_ITEMS == discard_rule ||
690        BTM_BLE_DISCARD_LOWER_RSSI_ITEMS == discard_rule))
691    {
692        if (BTM_BLE_SCAN_INVALID_STATE == ble_batchscan_cb.cur_state
693            || BTM_BLE_SCAN_DISABLED_STATE == ble_batchscan_cb.cur_state ||
694            BTM_BLE_SCAN_DISABLE_CALLED == ble_batchscan_cb.cur_state)
695        {
696            status = btm_ble_enable_disable_batchscan(TRUE);
697            if (BTM_CMD_STARTED != status)
698               return status;
699            btm_ble_batchscan_enq_op_q(BTM_BLE_BATCH_SCAN_ENB_DISAB_CUST_FEATURE,
700                                       BTM_BLE_SCAN_ENABLE_CALLED, 0, ref_value);
701        }
702
703        ble_batchscan_cb.scan_mode = scan_mode;
704        /* This command starts batch scanning, if enabled */
705        status = btm_ble_set_batchscan_param(scan_mode, scan_interval, scan_window, addr_type,
706                    discard_rule);
707        if (BTM_CMD_STARTED != status)
708            return status;
709
710        /* The user needs to be provided scan enable event */
711        btm_ble_batchscan_enq_op_q(BTM_BLE_BATCH_SCAN_SET_PARAMS, ble_batchscan_cb.cur_state,
712                                   BTM_BLE_BATCH_SCAN_ENABLE_EVT, ref_value);
713    }
714    else
715    {
716        BTM_TRACE_ERROR("Illegal enable scan params");
717        return BTM_ILLEGAL_VALUE;
718    }
719    return status;
720}
721
722/*******************************************************************************
723**
724** Function         BTM_BleDisableBatchScan
725**
726** Description      This function is called to disable batch scanning
727**
728** Parameters:      ref_value - Reference value
729**
730** Returns          tBTM_STATUS
731**
732*******************************************************************************/
733tBTM_STATUS BTM_BleDisableBatchScan(tBTM_BLE_REF_VALUE ref_value)
734{
735    tBTM_STATUS     status = BTM_NO_RESOURCES;
736    tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
737    BTM_TRACE_EVENT (" BTM_BleDisableBatchScan");
738
739    if (!HCI_LE_HOST_SUPPORTED(btm_cb.devcb.local_lmp_features[HCI_EXT_FEATURES_PAGE_1]))
740        return BTM_ILLEGAL_VALUE;
741
742    BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
743
744    if (0 == cmn_ble_vsc_cb.tot_scan_results_strg)
745    {
746        BTM_TRACE_ERROR("Controller does not support batch scan");
747        return BTM_ERR_PROCESSING;
748    }
749
750    status = btm_ble_enable_disable_batchscan(FALSE);
751    if (BTM_CMD_STARTED == status)
752    {
753       /* The user needs to be provided scan disable event */
754       btm_ble_batchscan_enq_op_q(BTM_BLE_BATCH_SCAN_ENB_DISAB_CUST_FEATURE,
755                                  BTM_BLE_SCAN_DISABLE_CALLED, BTM_BLE_BATCH_SCAN_DISABLE_EVT,
756                                  ref_value);
757    }
758
759    return status;
760}
761
762/*******************************************************************************
763**
764** Function         BTM_BleReadScanReports
765**
766** Description      This function is called to start reading batch scan reports
767**
768** Parameters:      scan_mode - Batch scan mode
769**                  ref_value - Reference value
770**
771** Returns          tBTM_STATUS
772**
773*******************************************************************************/
774tBTM_STATUS BTM_BleReadScanReports(tBTM_BLE_BATCH_SCAN_MODE scan_mode,
775                                             tBTM_BLE_REF_VALUE ref_value)
776{
777    tBTM_STATUS     status = BTM_NO_RESOURCES;
778    tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
779    UINT8 read_scan_mode = 0;
780    UINT8  *p_data = NULL, report_format = 0, num_records = 0;
781    UINT16 data_len = 0;
782
783    BTM_TRACE_EVENT (" BTM_BleReadScanReports; %d, %d", scan_mode, ref_value);
784
785    if (!HCI_LE_HOST_SUPPORTED(btm_cb.devcb.local_lmp_features[HCI_EXT_FEATURES_PAGE_1]))
786        return BTM_ILLEGAL_VALUE;
787
788    BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
789
790    if (0 == cmn_ble_vsc_cb.tot_scan_results_strg)
791    {
792        BTM_TRACE_ERROR("Controller does not support batch scan");
793        return BTM_ERR_PROCESSING;
794    }
795
796    /*  Check if the requested scan mode has already been setup by the user */
797    read_scan_mode = ble_batchscan_cb.scan_mode & BTM_BLE_BATCH_SCAN_MODE_ACTI;
798    if (0 == read_scan_mode)
799        read_scan_mode = ble_batchscan_cb.scan_mode & BTM_BLE_BATCH_SCAN_MODE_PASS;
800
801    if (read_scan_mode > 0 && (BTM_BLE_BATCH_SCAN_MODE_PASS == scan_mode ||
802        BTM_BLE_BATCH_SCAN_MODE_ACTI == scan_mode)
803        && (BTM_BLE_SCAN_ENABLED_STATE == ble_batchscan_cb.cur_state ||
804            BTM_BLE_SCAN_ENABLE_CALLED == ble_batchscan_cb.cur_state))
805    {
806        status = btm_ble_read_batchscan_reports(scan_mode, ref_value);
807        if (BTM_CMD_STARTED == status)
808        {
809            if (BTM_CMD_STARTED != status)
810                btm_ble_batchscan_deq_rep_data(scan_mode, &ref_value,
811                                               &num_records, &p_data, &data_len);
812        }
813    }
814    else
815    {
816        BTM_TRACE_ERROR("Illegal read scan params: %d, %d, %d", read_scan_mode, scan_mode,
817            ble_batchscan_cb.cur_state);
818        return BTM_ILLEGAL_VALUE;
819    }
820    return status;
821}
822
823
824/*******************************************************************************
825**
826** Function         BTM_BleTrackAdvertiser
827**
828** Description      This function is called to setup the callback for tracking advertisers
829**
830** Parameters:      p_track_cback - Tracking callback pointer
831**                  ref_value - Reference value
832**
833** Returns          tBTM_STATUS
834**
835*******************************************************************************/
836tBTM_STATUS BTM_BleTrackAdvertiser(tBTM_BLE_TRACK_ADV_CBACK *p_track_cback,
837                                        tBTM_BLE_REF_VALUE ref_value)
838{
839    tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
840    BTM_TRACE_EVENT (" BTM_BleTrackAdvertiser");
841    if (!HCI_LE_HOST_SUPPORTED(btm_cb.devcb.local_lmp_features[HCI_EXT_FEATURES_PAGE_1]))
842        return BTM_ILLEGAL_VALUE;
843
844    BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
845
846    if (0 == cmn_ble_vsc_cb.tot_scan_results_strg)
847    {
848        BTM_TRACE_ERROR("Controller does not support scan storage");
849        return BTM_ERR_PROCESSING;
850    }
851
852    ble_advtrack_cb.p_track_cback = p_track_cback;
853    ble_advtrack_cb.ref_value = ref_value;
854    return BTM_SUCCESS;
855}
856
857/*******************************************************************************
858**
859** Function         btm_ble_batchscan_init
860**
861** Description      This function initialize the batch scan control block.
862**
863** Parameters       None
864**
865** Returns          status
866**
867*******************************************************************************/
868void btm_ble_batchscan_init(void)
869{
870    BTM_TRACE_EVENT (" btm_ble_batchscan_init");
871    memset(&ble_batchscan_cb, 0, sizeof(tBTM_BLE_BATCH_SCAN_CB));
872    memset(&ble_advtrack_cb, 0, sizeof(tBTM_BLE_ADV_TRACK_CB));
873    BTM_RegisterForVSEvents(btm_ble_batchscan_filter_track_adv_vse_cback, TRUE);
874}
875
876#endif
877