1 /****************************************************************************** 2 * 3 * Copyright 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 <base/bind.h> 19 #include <stddef.h> 20 #include <stdio.h> 21 #include <string.h> 22 #include <vector> 23 #include "bt_target.h" 24 25 #include "bt_types.h" 26 #include "bt_utils.h" 27 #include "btm_ble_api.h" 28 #include "btm_int.h" 29 #include "btu.h" 30 #include "device/include/controller.h" 31 #include "hcimsgs.h" 32 33 using base::Bind; 34 using base::Callback; 35 using hci_cmd_cb = base::Callback<void(uint8_t* /* return_parameters */, 36 uint16_t /* return_parameters_length*/)>; 37 38 tBTM_BLE_BATCH_SCAN_CB ble_batchscan_cb; 39 tBTM_BLE_ADV_TRACK_CB ble_advtrack_cb; 40 41 /* length of each batch scan command */ 42 #define BTM_BLE_BATCH_SCAN_STORAGE_CFG_LEN 4 43 #define BTM_BLE_BATCH_SCAN_PARAM_CONFIG_LEN 12 44 #define BTM_BLE_BATCH_SCAN_ENB_DISB_LEN 2 45 #define BTM_BLE_BATCH_SCAN_READ_RESULTS_LEN 2 46 47 namespace { 48 49 bool can_do_batch_scan() { 50 if (!controller_get_interface()->supports_ble()) return false; 51 52 tBTM_BLE_VSC_CB cmn_ble_vsc_cb; 53 BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb); 54 55 if (cmn_ble_vsc_cb.tot_scan_results_strg == 0) return false; 56 57 return true; 58 } 59 60 /* VSE callback for batch scan, filter, and tracking events */ 61 void btm_ble_batchscan_filter_track_adv_vse_cback(uint8_t len, uint8_t* p) { 62 tBTM_BLE_TRACK_ADV_DATA adv_data; 63 64 uint8_t sub_event = 0; 65 tBTM_BLE_VSC_CB cmn_ble_vsc_cb; 66 STREAM_TO_UINT8(sub_event, p); 67 68 BTM_TRACE_EVENT( 69 "btm_ble_batchscan_filter_track_adv_vse_cback called with event:%x", 70 sub_event); 71 if (HCI_VSE_SUBCODE_BLE_THRESHOLD_SUB_EVT == sub_event && 72 NULL != ble_batchscan_cb.p_thres_cback) { 73 ble_batchscan_cb.p_thres_cback(ble_batchscan_cb.ref_value); 74 return; 75 } 76 77 if (HCI_VSE_SUBCODE_BLE_TRACKING_SUB_EVT == sub_event && 78 NULL != ble_advtrack_cb.p_track_cback) { 79 if (len < 10) return; 80 81 memset(&adv_data, 0, sizeof(tBTM_BLE_TRACK_ADV_DATA)); 82 BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb); 83 adv_data.client_if = (uint8_t)ble_advtrack_cb.ref_value; 84 if (cmn_ble_vsc_cb.version_supported > BTM_VSC_CHIP_CAPABILITY_L_VERSION) { 85 STREAM_TO_UINT8(adv_data.filt_index, p); 86 STREAM_TO_UINT8(adv_data.advertiser_state, p); 87 STREAM_TO_UINT8(adv_data.advertiser_info_present, p); 88 STREAM_TO_BDADDR(adv_data.bd_addr, p); 89 STREAM_TO_UINT8(adv_data.addr_type, p); 90 91 /* Extract the adv info details */ 92 if (ADV_INFO_PRESENT == adv_data.advertiser_info_present) { 93 STREAM_TO_UINT8(adv_data.tx_power, p); 94 STREAM_TO_UINT8(adv_data.rssi_value, p); 95 STREAM_TO_UINT16(adv_data.time_stamp, p); 96 97 STREAM_TO_UINT8(adv_data.adv_pkt_len, p); 98 if (adv_data.adv_pkt_len > 0) { 99 adv_data.p_adv_pkt_data = 100 static_cast<uint8_t*>(osi_malloc(adv_data.adv_pkt_len)); 101 memcpy(adv_data.p_adv_pkt_data, p, adv_data.adv_pkt_len); 102 } 103 104 STREAM_TO_UINT8(adv_data.scan_rsp_len, p); 105 if (adv_data.scan_rsp_len > 0) { 106 adv_data.p_scan_rsp_data = 107 static_cast<uint8_t*>(osi_malloc(adv_data.scan_rsp_len)); 108 memcpy(adv_data.p_scan_rsp_data, p, adv_data.scan_rsp_len); 109 } 110 } 111 } else { 112 /* Based on L-release version */ 113 STREAM_TO_UINT8(adv_data.filt_index, p); 114 STREAM_TO_UINT8(adv_data.addr_type, p); 115 STREAM_TO_BDADDR(adv_data.bd_addr, p); 116 STREAM_TO_UINT8(adv_data.advertiser_state, p); 117 } 118 119 BTM_TRACE_EVENT("track_adv_vse_cback called: %d, %d, %d", 120 adv_data.filt_index, adv_data.addr_type, 121 adv_data.advertiser_state); 122 123 // Make sure the device is known 124 BTM_SecAddBleDevice(adv_data.bd_addr, NULL, BT_DEVICE_TYPE_BLE, 125 adv_data.addr_type); 126 127 ble_advtrack_cb.p_track_cback(&adv_data); 128 return; 129 } 130 } 131 132 void feat_enable_cb(uint8_t* p, uint16_t len) { 133 if (len < 2) { 134 BTM_TRACE_ERROR("%s: wrong length", __func__); 135 return; 136 } 137 138 uint8_t status, subcode; 139 STREAM_TO_UINT8(status, p); 140 STREAM_TO_UINT8(subcode, p); 141 142 uint8_t expected_opcode = BTM_BLE_BATCH_SCAN_ENB_DISAB_CUST_FEATURE; 143 if (subcode != expected_opcode) { 144 BTM_TRACE_ERROR("%s: bad subcode, expected: %d got: %d", __func__, 145 expected_opcode, subcode); 146 return; 147 } 148 149 if (ble_batchscan_cb.cur_state != BTM_BLE_SCAN_ENABLE_CALLED) 150 BTM_TRACE_ERROR("%s: state should be ENABLE_CALLED", __func__); 151 152 ble_batchscan_cb.cur_state = BTM_BLE_SCAN_ENABLED_STATE; 153 } 154 155 void storage_config_cb(Callback<void(uint8_t /* status */)> cb, uint8_t* p, 156 uint16_t len) { 157 if (len < 2) { 158 BTM_TRACE_ERROR("%s: wrong length", __func__); 159 return; 160 } 161 162 uint8_t status, subcode; 163 STREAM_TO_UINT8(status, p); 164 STREAM_TO_UINT8(subcode, p); 165 166 uint8_t expected_opcode = BTM_BLE_BATCH_SCAN_SET_STORAGE_PARAM; 167 if (subcode != expected_opcode) { 168 BTM_TRACE_ERROR("%s: bad subcode, expected: %d got: %d", __func__, 169 expected_opcode, subcode); 170 return; 171 } 172 173 cb.Run(status); 174 } 175 176 void param_enable_cb(Callback<void(uint8_t /* status */)> cb, uint8_t* p, 177 uint16_t len) { 178 if (len < 2) { 179 BTM_TRACE_ERROR("%s: wrong length", __func__); 180 return; 181 } 182 183 uint8_t status, subcode; 184 STREAM_TO_UINT8(status, p); 185 STREAM_TO_UINT8(subcode, p); 186 187 uint8_t expected_opcode = BTM_BLE_BATCH_SCAN_SET_PARAMS; 188 if (subcode != expected_opcode) { 189 BTM_TRACE_ERROR("%s: bad subcode: 0x%02x 0x%02x", __func__, expected_opcode, 190 subcode); 191 return; 192 } 193 194 cb.Run(status); 195 } 196 197 void disable_cb(base::Callback<void(uint8_t /* status */)> cb, uint8_t* p, 198 uint16_t len) { 199 if (len < 2) { 200 BTM_TRACE_ERROR("%s: wrong length", __func__); 201 return; 202 } 203 204 uint8_t status, subcode; 205 STREAM_TO_UINT8(status, p); 206 STREAM_TO_UINT8(subcode, p); 207 208 uint8_t expected_opcode = BTM_BLE_BATCH_SCAN_SET_PARAMS; 209 if (subcode != expected_opcode) { 210 BTM_TRACE_ERROR("%s: bad subcode: 0x%02x 0x%02x", __func__, expected_opcode, 211 subcode); 212 return; 213 } 214 215 if (ble_batchscan_cb.cur_state != BTM_BLE_SCAN_DISABLE_CALLED) { 216 BTM_TRACE_ERROR("%s: state should be DISABLE_CALLED", __func__); 217 } 218 219 if (BTM_SUCCESS == status) { 220 ble_batchscan_cb.cur_state = BTM_BLE_SCAN_DISABLED_STATE; 221 } else { 222 BTM_TRACE_ERROR("%s: Invalid state after disabled", __func__); 223 ble_batchscan_cb.cur_state = BTM_BLE_SCAN_INVALID_STATE; 224 } 225 226 cb.Run(status); 227 } 228 229 /** 230 * This function reads the reports from controller. |scan_mode| is the mode for 231 * which the reports are to be read 232 */ 233 void btm_ble_read_batchscan_reports(tBTM_BLE_BATCH_SCAN_MODE scan_mode, 234 hci_cmd_cb cb) { 235 uint8_t len = BTM_BLE_BATCH_SCAN_READ_RESULTS_LEN; 236 uint8_t param[len]; 237 memset(param, 0, len); 238 239 uint8_t* pp = param; 240 UINT8_TO_STREAM(pp, BTM_BLE_BATCH_SCAN_READ_RESULTS); 241 UINT8_TO_STREAM(pp, scan_mode); 242 243 btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_BLE_BATCH_SCAN_OCF, param, len, cb); 244 } 245 246 /* read reports. data is accumulated in |data_all|, number of records is 247 * accumulated in |num_records_all| */ 248 void read_reports_cb(std::vector<uint8_t> data_all, uint8_t num_records_all, 249 tBTM_BLE_SCAN_REP_CBACK cb, uint8_t* p, uint16_t len) { 250 if (len < 2) { 251 BTM_TRACE_ERROR("%s: wrong length", __func__); 252 return; 253 } 254 255 uint8_t status, subcode; 256 STREAM_TO_UINT8(status, p); 257 STREAM_TO_UINT8(subcode, p); 258 259 uint8_t expected_opcode = BTM_BLE_BATCH_SCAN_READ_RESULTS; 260 if (subcode != expected_opcode) { 261 BTM_TRACE_ERROR("%s: bad subcode, expected: %d got: %d", __func__, 262 expected_opcode, subcode); 263 return; 264 } 265 266 uint8_t report_format, num_records; 267 STREAM_TO_UINT8(report_format, p); 268 STREAM_TO_UINT8(num_records, p); 269 270 BTM_TRACE_DEBUG("%s: status=%d,len=%d,rec=%d", __func__, status, len - 4, 271 num_records); 272 273 if (num_records == 0) { 274 cb.Run(status, report_format, num_records_all, data_all); 275 return; 276 } 277 278 if (len > 4) { 279 data_all.insert(data_all.end(), p, p + len - 4); 280 num_records_all += num_records; 281 282 /* More records could be in the buffer and needs to be pulled out */ 283 btm_ble_read_batchscan_reports( 284 report_format, base::Bind(&read_reports_cb, std::move(data_all), 285 num_records_all, std::move(cb))); 286 } 287 } 288 289 /** 290 * This function writes the storage configuration in controller 291 * 292 * Parameters batch_scan_full_max - Max storage space (in %) allocated to 293 * full scanning 294 * batch_scan_trunc_max - Max storage space (in %) allocated to 295 * truncated scanning 296 * batch_scan_notify_threshold - Set up notification level 297 * based on total space 298 * 299 **/ 300 void btm_ble_set_storage_config(uint8_t batch_scan_full_max, 301 uint8_t batch_scan_trunc_max, 302 uint8_t batch_scan_notify_threshold, 303 hci_cmd_cb cb) { 304 uint8_t len = BTM_BLE_BATCH_SCAN_STORAGE_CFG_LEN; 305 uint8_t param[len]; 306 memset(param, 0, len); 307 308 uint8_t* pp = param; 309 UINT8_TO_STREAM(pp, BTM_BLE_BATCH_SCAN_SET_STORAGE_PARAM); 310 UINT8_TO_STREAM(pp, batch_scan_full_max); 311 UINT8_TO_STREAM(pp, batch_scan_trunc_max); 312 UINT8_TO_STREAM(pp, batch_scan_notify_threshold); 313 314 btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_BLE_BATCH_SCAN_OCF, param, len, cb); 315 } 316 317 /* This function writes the batch scan params in controller */ 318 void btm_ble_set_batchscan_param(tBTM_BLE_BATCH_SCAN_MODE scan_mode, 319 uint32_t scan_interval, uint32_t scan_window, 320 tBLE_ADDR_TYPE addr_type, 321 tBTM_BLE_DISCARD_RULE discard_rule, 322 hci_cmd_cb cb) { 323 // Override param and decide addr_type based on own addr type 324 // TODO: Remove upper layer parameter? 325 addr_type = btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type; 326 327 uint8_t len = BTM_BLE_BATCH_SCAN_PARAM_CONFIG_LEN; 328 uint8_t param[len]; 329 memset(param, 0, len); 330 331 uint8_t* p = param; 332 UINT8_TO_STREAM(p, BTM_BLE_BATCH_SCAN_SET_PARAMS); 333 UINT8_TO_STREAM(p, scan_mode); 334 UINT32_TO_STREAM(p, scan_window); 335 UINT32_TO_STREAM(p, scan_interval); 336 UINT8_TO_STREAM(p, addr_type); 337 UINT8_TO_STREAM(p, discard_rule); 338 339 btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_BLE_BATCH_SCAN_OCF, param, len, cb); 340 } 341 342 /* This function enables the customer specific feature in controller */ 343 void btm_ble_enable_batchscan(hci_cmd_cb cb) { 344 uint8_t len = BTM_BLE_BATCH_SCAN_ENB_DISB_LEN; 345 uint8_t param[len]; 346 memset(param, 0, len); 347 348 uint8_t* p = param; 349 UINT8_TO_STREAM(p, BTM_BLE_BATCH_SCAN_ENB_DISAB_CUST_FEATURE); 350 UINT8_TO_STREAM(p, 0x01 /* enable */); 351 352 btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_BLE_BATCH_SCAN_OCF, param, len, cb); 353 } 354 355 } // namespace 356 357 /******************************************************************************* 358 * 359 * Description This function is called to write storage config params. 360 * 361 * Parameters: batch_scan_full_max - Max storage space (in %) allocated to 362 * full style 363 * batch_scan_trunc_max - Max storage space (in %) allocated to 364 * trunc style 365 * batch_scan_notify_threshold - Setup notification level based 366 * on total space 367 * cb - Setup callback pointer 368 * p_thres_cback - Threshold callback pointer 369 * ref_value - Reference value 370 * 371 ******************************************************************************/ 372 void BTM_BleSetStorageConfig(uint8_t batch_scan_full_max, 373 uint8_t batch_scan_trunc_max, 374 uint8_t batch_scan_notify_threshold, 375 Callback<void(uint8_t /* status */)> cb, 376 tBTM_BLE_SCAN_THRESHOLD_CBACK* p_thres_cback, 377 tBTM_BLE_REF_VALUE ref_value) { 378 if (!can_do_batch_scan()) { 379 cb.Run(BTM_ERR_PROCESSING); 380 return; 381 } 382 383 BTM_TRACE_EVENT("%s: %d, %d, %d, %d, %d", __func__, 384 ble_batchscan_cb.cur_state, ref_value, batch_scan_full_max, 385 batch_scan_trunc_max, batch_scan_notify_threshold); 386 387 ble_batchscan_cb.p_thres_cback = p_thres_cback; 388 ble_batchscan_cb.ref_value = ref_value; 389 390 if (batch_scan_full_max > BTM_BLE_ADV_SCAN_FULL_MAX || 391 batch_scan_trunc_max > BTM_BLE_ADV_SCAN_TRUNC_MAX || 392 batch_scan_notify_threshold > BTM_BLE_ADV_SCAN_THR_MAX) { 393 BTM_TRACE_ERROR("Illegal set storage config params"); 394 cb.Run(BTM_ILLEGAL_VALUE); 395 return; 396 } 397 398 if (BTM_BLE_SCAN_INVALID_STATE == ble_batchscan_cb.cur_state || 399 BTM_BLE_SCAN_DISABLED_STATE == ble_batchscan_cb.cur_state || 400 BTM_BLE_SCAN_DISABLE_CALLED == ble_batchscan_cb.cur_state) { 401 btm_ble_enable_batchscan(Bind(&feat_enable_cb)); 402 ble_batchscan_cb.cur_state = BTM_BLE_SCAN_ENABLE_CALLED; 403 } 404 405 btm_ble_set_storage_config(batch_scan_full_max, batch_scan_trunc_max, 406 batch_scan_notify_threshold, 407 Bind(&storage_config_cb, cb)); 408 return; 409 } 410 411 /* This function is called to configure and enable batch scanning */ 412 void BTM_BleEnableBatchScan(tBTM_BLE_BATCH_SCAN_MODE scan_mode, 413 uint32_t scan_interval, uint32_t scan_window, 414 tBLE_ADDR_TYPE addr_type, 415 tBTM_BLE_DISCARD_RULE discard_rule, 416 Callback<void(uint8_t /* status */)> cb) { 417 BTM_TRACE_EVENT("%s: %d, %d, %d, %d, %d, %d", __func__, scan_mode, 418 scan_interval, scan_window, addr_type, discard_rule); 419 420 if (!can_do_batch_scan()) { 421 cb.Run(BTM_ERR_PROCESSING); 422 return; 423 } 424 425 BTM_TRACE_DEBUG("%s: %d, %x, %x, %d, %d", __func__, scan_mode, scan_interval, 426 scan_window, discard_rule, ble_batchscan_cb.cur_state); 427 428 /* Only 16 bits will be used for scan interval and scan window as per 429 * agreement with Google */ 430 /* So the standard LE range would suffice for scan interval and scan window */ 431 if ((BTM_BLE_ISVALID_PARAM(scan_interval, BTM_BLE_SCAN_INT_MIN, 432 BTM_BLE_SCAN_INT_MAX) || 433 BTM_BLE_ISVALID_PARAM(scan_window, BTM_BLE_SCAN_WIN_MIN, 434 BTM_BLE_SCAN_WIN_MAX)) && 435 (BTM_BLE_BATCH_SCAN_MODE_PASS == scan_mode || 436 BTM_BLE_BATCH_SCAN_MODE_ACTI == scan_mode || 437 BTM_BLE_BATCH_SCAN_MODE_PASS_ACTI == scan_mode) && 438 (BTM_BLE_DISCARD_OLD_ITEMS == discard_rule || 439 BTM_BLE_DISCARD_LOWER_RSSI_ITEMS == discard_rule)) { 440 } else { 441 BTM_TRACE_ERROR("%s: Illegal enable scan params", __func__); 442 cb.Run(BTM_ILLEGAL_VALUE); 443 return; 444 } 445 446 if (BTM_BLE_SCAN_INVALID_STATE == ble_batchscan_cb.cur_state || 447 BTM_BLE_SCAN_DISABLED_STATE == ble_batchscan_cb.cur_state || 448 BTM_BLE_SCAN_DISABLE_CALLED == ble_batchscan_cb.cur_state) { 449 btm_ble_enable_batchscan(Bind(&feat_enable_cb)); 450 ble_batchscan_cb.cur_state = BTM_BLE_SCAN_ENABLE_CALLED; 451 } 452 453 ble_batchscan_cb.scan_mode = scan_mode; 454 ble_batchscan_cb.scan_interval = scan_interval; 455 ble_batchscan_cb.scan_window = scan_window; 456 ble_batchscan_cb.addr_type = addr_type; 457 ble_batchscan_cb.discard_rule = discard_rule; 458 /* This command starts batch scanning, if enabled */ 459 btm_ble_set_batchscan_param(scan_mode, scan_interval, scan_window, addr_type, 460 discard_rule, Bind(¶m_enable_cb, cb)); 461 } 462 463 /* This function is called to disable batch scanning */ 464 void BTM_BleDisableBatchScan(base::Callback<void(uint8_t /* status */)> cb) { 465 BTM_TRACE_EVENT(" BTM_BleDisableBatchScan"); 466 467 if (!can_do_batch_scan()) { 468 cb.Run(BTM_ERR_PROCESSING); 469 return; 470 } 471 472 btm_ble_set_batchscan_param( 473 BTM_BLE_BATCH_SCAN_MODE_DISABLE, ble_batchscan_cb.scan_interval, 474 ble_batchscan_cb.scan_window, ble_batchscan_cb.addr_type, 475 ble_batchscan_cb.discard_rule, Bind(&disable_cb, cb)); 476 ble_batchscan_cb.cur_state = BTM_BLE_SCAN_DISABLE_CALLED; 477 } 478 479 /* This function is called to start reading batch scan reports */ 480 void BTM_BleReadScanReports(tBTM_BLE_BATCH_SCAN_MODE scan_mode, 481 tBTM_BLE_SCAN_REP_CBACK cb) { 482 uint8_t read_scan_mode = 0; 483 484 BTM_TRACE_EVENT("%s; %d", __func__, scan_mode); 485 486 if (!can_do_batch_scan()) { 487 BTM_TRACE_ERROR("Controller does not support batch scan"); 488 cb.Run(BTM_ERR_PROCESSING, 0, 0, {}); 489 return; 490 } 491 492 /* Check if the requested scan mode has already been setup by the user */ 493 read_scan_mode = ble_batchscan_cb.scan_mode & BTM_BLE_BATCH_SCAN_MODE_ACTI; 494 if (0 == read_scan_mode) 495 read_scan_mode = ble_batchscan_cb.scan_mode & BTM_BLE_BATCH_SCAN_MODE_PASS; 496 497 /* Check only for modes, as scan reports can be called after disabling batch 498 * scan */ 499 if (scan_mode != BTM_BLE_BATCH_SCAN_MODE_PASS && 500 scan_mode != BTM_BLE_BATCH_SCAN_MODE_ACTI) { 501 BTM_TRACE_ERROR("Illegal read scan params: %d, %d, %d", read_scan_mode, 502 scan_mode, ble_batchscan_cb.cur_state); 503 cb.Run(BTM_ILLEGAL_VALUE, 0, 0, {}); 504 return; 505 } 506 507 btm_ble_read_batchscan_reports( 508 scan_mode, base::Bind(&read_reports_cb, std::vector<uint8_t>(), 0, cb)); 509 return; 510 } 511 512 /* This function is called to setup the callback for tracking */ 513 void BTM_BleTrackAdvertiser(tBTM_BLE_TRACK_ADV_CBACK* p_track_cback, 514 tBTM_BLE_REF_VALUE ref_value) { 515 BTM_TRACE_EVENT("%s:", __func__); 516 517 if (!can_do_batch_scan()) { 518 BTM_TRACE_ERROR("Controller does not support batch scan"); 519 520 tBTM_BLE_TRACK_ADV_DATA track_adv_data; 521 memset(&track_adv_data, 0, sizeof(tBTM_BLE_TRACK_ADV_DATA)); 522 track_adv_data.advertiser_info_present = 523 NO_ADV_INFO_PRESENT; /* Indicates failure */ 524 track_adv_data.client_if = (uint8_t)ref_value; 525 p_track_cback(&track_adv_data); 526 return; 527 } 528 529 ble_advtrack_cb.p_track_cback = p_track_cback; 530 ble_advtrack_cb.ref_value = ref_value; 531 return; 532 } 533 534 /** 535 * This function initialize the batch scan control block. 536 **/ 537 void btm_ble_batchscan_init(void) { 538 BTM_TRACE_EVENT(" btm_ble_batchscan_init"); 539 memset(&ble_batchscan_cb, 0, sizeof(tBTM_BLE_BATCH_SCAN_CB)); 540 memset(&ble_advtrack_cb, 0, sizeof(tBTM_BLE_ADV_TRACK_CB)); 541 BTM_RegisterForVSEvents(btm_ble_batchscan_filter_track_adv_vse_cback, true); 542 } 543 544 /** 545 * This function cleans the batch scan control block. 546 **/ 547 void btm_ble_batchscan_cleanup(void) { 548 BTM_TRACE_EVENT("%s", __func__); 549 550 memset(&ble_batchscan_cb, 0, sizeof(tBTM_BLE_BATCH_SCAN_CB)); 551 memset(&ble_advtrack_cb, 0, sizeof(tBTM_BLE_ADV_TRACK_CB)); 552 } 553