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
32 tBTM_BLE_BATCH_SCAN_CB ble_batchscan_cb;
33 tBTM_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 *******************************************************************************/
50 void btm_ble_batchscan_vsc_cmpl_cback (tBTM_VSC_CMPL *p_params);
51 void 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 *******************************************************************************/
btm_ble_batchscan_filter_track_adv_vse_cback(UINT8 len,UINT8 * p)62 void 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 *******************************************************************************/
btm_ble_batchscan_enq_op_q(UINT8 opcode,tBTM_BLE_BATCH_SCAN_STATE cur_state,UINT8 cb_evt,tBTM_BLE_REF_VALUE ref_value)101 void 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 *******************************************************************************/
btm_ble_batchscan_enq_rep_q(UINT8 report_format,tBTM_BLE_REF_VALUE ref_value)125 tBTM_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 *******************************************************************************/
btm_ble_batchscan_enq_rep_data(UINT8 report_format,UINT8 num_records,UINT8 * p_data,UINT8 data_len)156 void 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 *******************************************************************************/
btm_ble_batchscan_deq_rep_data(UINT8 report_format,tBTM_BLE_REF_VALUE * p_ref_value,UINT8 * p_num_records,UINT8 ** p_data,UINT16 * p_data_len)206 void 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 *******************************************************************************/
btm_ble_batchscan_deq_op_q(UINT8 * p_opcode,tBTM_BLE_BATCH_SCAN_STATE * cur_state,UINT8 * p_cb_evt,tBTM_BLE_REF_VALUE * p_ref)251 void 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 *******************************************************************************/
btm_ble_read_batchscan_reports(tBTM_BLE_BATCH_SCAN_MODE scan_mode,tBTM_BLE_REF_VALUE ref_value)275 tBTM_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 *******************************************************************************/
btm_ble_batchscan_vsc_cmpl_cback(tBTM_VSC_CMPL * p_params)316 void 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 *******************************************************************************/
btm_ble_set_storage_config(UINT8 batch_scan_full_max,UINT8 batch_scan_trunc_max,UINT8 batch_scan_notify_threshold)463 tBTM_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 *******************************************************************************/
btm_ble_set_batchscan_param(tBTM_BLE_BATCH_SCAN_MODE scan_mode,UINT32 scan_interval,UINT32 scan_window,tBLE_ADDR_TYPE addr_type,tBTM_BLE_DISCARD_RULE discard_rule)503 tBTM_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 *******************************************************************************/
btm_ble_enable_disable_batchscan(BOOLEAN should_enable)542 tBTM_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 *******************************************************************************/
BTM_BleSetStorageConfig(UINT8 batch_scan_full_max,UINT8 batch_scan_trunc_max,UINT8 batch_scan_notify_threshold,tBTM_BLE_SCAN_SETUP_CBACK * p_setup_cback,tBTM_BLE_SCAN_THRESHOLD_CBACK * p_thres_cback,tBTM_BLE_SCAN_REP_CBACK * p_rep_cback,tBTM_BLE_REF_VALUE ref_value)602 tBTM_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 *******************************************************************************/
BTM_BleEnableBatchScan(tBTM_BLE_BATCH_SCAN_MODE scan_mode,UINT32 scan_interval,UINT32 scan_window,tBLE_ADDR_TYPE addr_type,tBTM_BLE_DISCARD_RULE discard_rule,tBTM_BLE_REF_VALUE ref_value)680 tBTM_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 *******************************************************************************/
BTM_BleDisableBatchScan(tBTM_BLE_REF_VALUE ref_value)757 tBTM_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 *******************************************************************************/
BTM_BleReadScanReports(tBTM_BLE_BATCH_SCAN_MODE scan_mode,tBTM_BLE_REF_VALUE ref_value)798 tBTM_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 *******************************************************************************/
BTM_BleTrackAdvertiser(tBTM_BLE_TRACK_ADV_CBACK * p_track_cback,tBTM_BLE_REF_VALUE ref_value)862 tBTM_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 *******************************************************************************/
btm_ble_batchscan_init(void)894 void 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 *******************************************************************************/
btm_ble_batchscan_cleanup(void)913 void 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