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