diff --git a/gd/hci/facade/le_scanning_manager_facade.cc b/gd/hci/facade/le_scanning_manager_facade.cc index 448ec891ed..bdab7c182d 100644 --- a/gd/hci/facade/le_scanning_manager_facade.cc +++ b/gd/hci/facade/le_scanning_manager_facade.cc @@ -90,6 +90,7 @@ class LeScanningManagerFacadeService : public LeScanningManagerFacade::Service, }; void OnTrackAdvFoundLost(){}; void OnBatchScanReports(int client_if, int status, int report_format, int num_records, std::vector data){}; + void OnBatchScanThresholdCrossed(int client_if){}; void OnTimeout(){}; void OnFilterEnable(Enable enable, uint8_t status){}; void OnFilterParamSetup(uint8_t available_spaces, ApcfAction action, uint8_t status){}; diff --git a/gd/hci/hci_packets.pdl b/gd/hci/hci_packets.pdl index cec7dd67bd..e3395f22b7 100644 --- a/gd/hci/hci_packets.pdl +++ b/gd/hci/hci_packets.pdl @@ -4506,7 +4506,8 @@ enum BatchScanOpcode : 8 { READ_RESULT_PARAMETERS = 0x04, } -packet LeBatchScan : VendorCommand (op_code = LE_BATCH_SCAN) { +// https://source.android.com/devices/bluetooth/hci_requirements#batching-of-scan-results +packet LeBatchScan : LeScanningCommand (op_code = LE_BATCH_SCAN) { batch_scan_opcode : BatchScanOpcode, _body_, } @@ -4551,8 +4552,24 @@ packet LeBatchScanSetScanParameters : LeBatchScan (batch_scan_opcode = SET_SCAN_ packet LeBatchScanSetScanParametersComplete : LeBatchScanComplete (batch_scan_opcode = SET_SCAN_PARAMETERS) { } -packet LeBatchScanReadTruncatedResultParameters : LeBatchScan (batch_scan_opcode = READ_RESULT_PARAMETERS) { - _fixed_ = 0x01 : 8, +enum BatchScanDataRead : 8 { + TRUNCATED_MODE_DATA = 0x01, + FULL_MODE_DATA = 0x02, +} + +packet LeBatchScanReadResultParameters : LeBatchScan (batch_scan_opcode = READ_RESULT_PARAMETERS) { + batch_scan_data_read : BatchScanDataRead, +} + +packet LeBatchScanReadResultParametersCompleteRaw : LeBatchScanComplete (batch_scan_opcode = READ_RESULT_PARAMETERS) { + batch_scan_data_read : BatchScanDataRead, + num_of_records : 8, + raw_data : 8[], +} + +packet LeBatchScanReadResultParametersComplete : LeBatchScanComplete (batch_scan_opcode = READ_RESULT_PARAMETERS) { + batch_scan_data_read : BatchScanDataRead, + _body_, } struct TruncatedResult { @@ -4563,12 +4580,7 @@ struct TruncatedResult { timestamp : 16, } -packet LeBatchScanReadTruncatedResultParametersComplete : LeBatchScanComplete (batch_scan_opcode = READ_RESULT_PARAMETERS) { - _fixed_ = 0x01 : 8, -} - -packet LeBatchScanReadFullResultParameters : LeBatchScan (batch_scan_opcode = READ_RESULT_PARAMETERS) { - _fixed_ = 0x02 : 8, +packet LeBatchScanReadTruncatedResultParametersComplete : LeBatchScanReadResultParametersComplete (batch_scan_data_read = TRUNCATED_MODE_DATA) { _count_(results) : 8, results : TruncatedResult[], } @@ -4585,8 +4597,7 @@ struct FullResult { scan_response : 8[], } -packet LeBatchScanReadFullResultParametersComplete : LeBatchScanComplete (batch_scan_opcode = READ_RESULT_PARAMETERS) { - _fixed_ = 0x02 : 8, +packet LeBatchScanReadFullResultParametersComplete : LeBatchScanReadResultParametersComplete (batch_scan_data_read = FULL_MODE_DATA) { _count_(results) : 8, results : FullResult[], } @@ -5617,6 +5628,28 @@ packet VendorSpecificEvent : Event (event_code = VENDOR_SPECIFIC) { _payload_, } +packet StorageThresholdBreachEvent : VendorSpecificEvent (subevent_code = BLE_THRESHOLD) { +} + +packet LEAdvertisementTrackingEvent : VendorSpecificEvent (subevent_code = BLE_TRACKING) { + apcf_filter_index : 8, + advertiser_state : 8, + advt_info_present : 8, + advertiser_address : Address, + advertiser_address_type : 8, + _body_, +} + +packet LEAdvertisementTrackingWithInfoEvent : LEAdvertisementTrackingEvent { + tx_power : 8, + rssi : 8, + timestamp : 8, + _size_(adv_packet) : 8, + adv_packet : 8[], + _size_(scan_response) : 8, + scan_response : 8[], +} + enum QualityReportId : 8 { MONITOR_MODE = 0x01, APPROACH_LSTO = 0x02, diff --git a/gd/hci/le_scanning_manager.cc b/gd/hci/le_scanning_manager.cc index d84faca38e..aef29f9534 100644 --- a/gd/hci/le_scanning_manager.cc +++ b/gd/hci/le_scanning_manager.cc @@ -155,6 +155,9 @@ class NullScanningCallback : public ScanningCallback { void OnBatchScanReports(int client_if, int status, int report_format, int num_records, std::vector data) { LOG_INFO("OnBatchScanReports in NullScanningCallback"); } + void OnBatchScanThresholdCrossed(int client_if) { + LOG_INFO("OnBatchScanThresholdCrossed in NullScanningCallback"); + } void OnTimeout() { LOG_INFO("OnTimeout in NullScanningCallback"); } @@ -170,6 +173,27 @@ class NullScanningCallback : public ScanningCallback { } }; +enum class BatchScanState { + ERROR_STATE = 0, + ENABLE_CALLED = 1, + ENABLED_STATE = 2, + DISABLE_CALLED = 3, + DISABLED_STATE = 4, +}; + +#define BTM_BLE_BATCH_SCAN_MODE_DISABLE 0 +#define BTM_BLE_BATCH_SCAN_MODE_PASS 1 +#define BTM_BLE_BATCH_SCAN_MODE_ACTI 2 +#define BTM_BLE_BATCH_SCAN_MODE_PASS_ACTI 3 + +struct BatchScanConfig { + BatchScanState current_state; + BatchScanMode scan_mode; + uint32_t scan_interval; + uint32_t scan_window; + BatchScanDiscardRule discard_rule; +}; + struct LeScanningManager::impl : public bluetooth::hci::LeAddressManagerCallback { impl(Module* module) : module_(module), le_scanning_interface_(nullptr) {} @@ -197,11 +221,13 @@ struct LeScanningManager::impl : public bluetooth::hci::LeAddressManagerCallback api_type_ = ScanApiType::LEGACY; } is_filter_support_ = controller_->IsSupported(OpCode::LE_ADV_FILTER); + is_batch_scan_support_ = controller->IsSupported(OpCode::LE_BATCH_SCAN); scanners_ = std::vector(kMaxAppNum + 1); for (size_t i = 0; i < scanners_.size(); i++) { scanners_[i].app_uuid = Uuid::kEmpty; scanners_[i].in_use = false; } + batch_scan_config_.current_state = BatchScanState::DISABLED_STATE; configure_scan(); } @@ -803,6 +829,140 @@ struct LeScanningManager::impl : public bluetooth::hci::LeAddressManagerCallback module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete)); } + void batch_scan_set_storage_parameter( + uint8_t batch_scan_full_max, uint8_t batch_scan_truncated_max, uint8_t batch_scan_notify_threshold) { + if (!is_batch_scan_support_) { + LOG_WARN("Batch scan is not supported"); + return; + } + + if (batch_scan_config_.current_state == BatchScanState::ERROR_STATE || + batch_scan_config_.current_state == BatchScanState::DISABLED_STATE || + batch_scan_config_.current_state == BatchScanState::DISABLE_CALLED) { + batch_scan_config_.current_state = BatchScanState::ENABLE_CALLED; + le_scanning_interface_->EnqueueCommand( + LeBatchScanEnableBuilder::Create(Enable::ENABLED), + module_handler_->BindOnceOn(this, &impl::on_batch_scan_enable_complete)); + } + + le_scanning_interface_->EnqueueCommand( + LeBatchScanSetStorageParametersBuilder::Create( + batch_scan_full_max, batch_scan_truncated_max, batch_scan_notify_threshold), + module_handler_->BindOnceOn(this, &impl::on_batch_scan_complete)); + } + + void batch_scan_enable( + BatchScanMode scan_mode, + uint32_t duty_cycle_scan_window_slots, + uint32_t duty_cycle_scan_interval_slots, + BatchScanDiscardRule batch_scan_discard_rule) { + if (!is_batch_scan_support_) { + LOG_WARN("Batch scan is not supported"); + return; + } + + if (batch_scan_config_.current_state == BatchScanState::ERROR_STATE || + batch_scan_config_.current_state == BatchScanState::DISABLED_STATE || + batch_scan_config_.current_state == BatchScanState::DISABLE_CALLED) { + batch_scan_config_.current_state = BatchScanState::ENABLE_CALLED; + le_scanning_interface_->EnqueueCommand( + LeBatchScanEnableBuilder::Create(Enable::ENABLED), + module_handler_->BindOnceOn(this, &impl::on_batch_scan_enable_complete)); + } + + batch_scan_config_.scan_mode = scan_mode; + batch_scan_config_.scan_interval = duty_cycle_scan_interval_slots; + batch_scan_config_.scan_window = duty_cycle_scan_window_slots; + batch_scan_config_.discard_rule = batch_scan_discard_rule; + /* This command starts batch scanning, if enabled */ + batch_scan_set_scan_parameter( + scan_mode, duty_cycle_scan_window_slots, duty_cycle_scan_interval_slots, batch_scan_discard_rule); + } + + void batch_scan_disable() { + if (!is_batch_scan_support_) { + LOG_WARN("Batch scan is not supported"); + return; + } + batch_scan_config_.current_state = BatchScanState::DISABLE_CALLED; + batch_scan_set_scan_parameter( + BatchScanMode::DISABLE, + batch_scan_config_.scan_window, + batch_scan_config_.scan_interval, + batch_scan_config_.discard_rule); + } + + void batch_scan_set_scan_parameter( + BatchScanMode scan_mode, + uint32_t duty_cycle_scan_window_slots, + uint32_t duty_cycle_scan_interval_slots, + BatchScanDiscardRule batch_scan_discard_rule) { + if (!is_batch_scan_support_) { + LOG_WARN("Batch scan is not supported"); + return; + } + AdvertisingAddressType own_address_type = AdvertisingAddressType::PUBLIC_ADDRESS; + if (own_address_type_ == OwnAddressType::RANDOM_DEVICE_ADDRESS || + own_address_type_ == OwnAddressType::RESOLVABLE_OR_RANDOM_ADDRESS) { + own_address_type = AdvertisingAddressType::RANDOM_ADDRESS; + } + uint8_t truncated_mode_enabled = 0x00; + uint8_t full_mode_enabled = 0x00; + if (scan_mode == BatchScanMode::TRUNCATED || scan_mode == BatchScanMode::TRUNCATED_AND_FULL) { + truncated_mode_enabled = 0x01; + } + if (scan_mode == BatchScanMode::FULL || scan_mode == BatchScanMode::TRUNCATED_AND_FULL) { + full_mode_enabled = 0x01; + } + + if (scan_mode == BatchScanMode::DISABLE) { + le_scanning_interface_->EnqueueCommand( + LeBatchScanSetScanParametersBuilder::Create( + truncated_mode_enabled, + full_mode_enabled, + duty_cycle_scan_window_slots, + duty_cycle_scan_interval_slots, + own_address_type, + batch_scan_discard_rule), + module_handler_->BindOnceOn(this, &impl::on_batch_scan_disable_complete)); + } else { + le_scanning_interface_->EnqueueCommand( + LeBatchScanSetScanParametersBuilder::Create( + truncated_mode_enabled, + full_mode_enabled, + duty_cycle_scan_window_slots, + duty_cycle_scan_interval_slots, + own_address_type, + batch_scan_discard_rule), + module_handler_->BindOnceOn(this, &impl::on_batch_scan_complete)); + } + } + + void batch_scan_read_results(ScannerId scanner_id, uint16_t total_num_of_records, BatchScanMode scan_mode) { + if (!is_batch_scan_support_) { + LOG_WARN("Batch scan is not supported"); + int status = static_cast(ErrorCode::UNSUPORTED_FEATURE_OR_PARAMETER_VALUE); + scanning_callbacks_->OnBatchScanReports(scanner_id, status, 0, 0, {}); + return; + } + + if (scan_mode != BatchScanMode::FULL && scan_mode != BatchScanMode::TRUNCATED) { + LOG_WARN("Invalid scan mode %d", (uint16_t)scan_mode); + int status = static_cast(ErrorCode::INVALID_HCI_COMMAND_PARAMETERS); + scanning_callbacks_->OnBatchScanReports(scanner_id, status, 0, 0, {}); + return; + } + + if (batch_scan_result_cache_.find(scanner_id) == batch_scan_result_cache_.end()) { + std::vector empty_data = {}; + batch_scan_result_cache_.emplace(scanner_id, empty_data); + } + + le_scanning_interface_->EnqueueCommand( + LeBatchScanReadResultParametersBuilder::Create(static_cast(scan_mode)), + module_handler_->BindOnceOn(this, &impl::on_batch_scan_read_result_complete, scanner_id, total_num_of_records)); + } + void register_scanning_callback(ScanningCallback* scanning_callbacks) { scanning_callbacks_ = scanning_callbacks; } @@ -890,6 +1050,68 @@ struct LeScanningManager::impl : public bluetooth::hci::LeAddressManagerCallback } } + void on_batch_scan_complete(CommandCompleteView view) { + ASSERT(view.IsValid()); + auto status_view = LeBatchScanCompleteView::Create(view); + ASSERT(status_view.IsValid()); + if (status_view.GetStatus() != ErrorCode::SUCCESS) { + LOG_INFO( + "Got a Command complete %s, status %s, batch_scan_opcode %s", + OpCodeText(view.GetCommandOpCode()).c_str(), + ErrorCodeText(status_view.GetStatus()).c_str(), + BatchScanOpcodeText(status_view.GetBatchScanOpcode()).c_str()); + } + } + + void on_batch_scan_enable_complete(CommandCompleteView view) { + ASSERT(view.IsValid()); + auto status_view = LeBatchScanCompleteView::Create(view); + ASSERT(status_view.IsValid()); + auto complete_view = LeBatchScanEnableCompleteView::Create(status_view); + ASSERT(complete_view.IsValid()); + if (status_view.GetStatus() != ErrorCode::SUCCESS) { + LOG_INFO("Got batch scan enable complete, status %s", ErrorCodeText(status_view.GetStatus()).c_str()); + batch_scan_config_.current_state = BatchScanState::ERROR_STATE; + } else { + batch_scan_config_.current_state = BatchScanState::ENABLED_STATE; + } + } + + void on_batch_scan_disable_complete(CommandCompleteView view) { + ASSERT(view.IsValid()); + auto status_view = LeBatchScanCompleteView::Create(view); + ASSERT(status_view.IsValid()); + auto complete_view = LeBatchScanSetScanParametersCompleteView::Create(status_view); + ASSERT(complete_view.IsValid()); + ASSERT(status_view.GetStatus() == ErrorCode::SUCCESS); + batch_scan_config_.current_state = BatchScanState::DISABLED_STATE; + } + + void on_batch_scan_read_result_complete( + ScannerId scanner_id, uint16_t total_num_of_records, CommandCompleteView view) { + ASSERT(view.IsValid()); + auto status_view = LeBatchScanCompleteView::Create(view); + ASSERT(status_view.IsValid()); + auto complete_view = LeBatchScanReadResultParametersCompleteRawView::Create(status_view); + ASSERT(complete_view.IsValid()); + if (complete_view.GetStatus() != ErrorCode::SUCCESS) { + LOG_INFO("Got batch scan read result complete, status %s", ErrorCodeText(status_view.GetStatus()).c_str()); + } + uint8_t num_of_records = complete_view.GetNumOfRecords(); + auto report_format = complete_view.GetBatchScanDataRead(); + if (num_of_records == 0) { + scanning_callbacks_->OnBatchScanReports( + scanner_id, 0x00, (int)report_format, total_num_of_records, batch_scan_result_cache_[scanner_id]); + batch_scan_result_cache_.erase(scanner_id); + } else { + auto raw_data = complete_view.GetRawData(); + batch_scan_result_cache_[scanner_id].insert( + batch_scan_result_cache_[scanner_id].end(), raw_data.begin(), raw_data.end()); + total_num_of_records += num_of_records; + batch_scan_read_results(scanner_id, total_num_of_records, static_cast(report_format)); + } + } + void OnPause() override { paused_ = true; scan_on_resume_ = is_scanning_; @@ -926,12 +1148,15 @@ struct LeScanningManager::impl : public bluetooth::hci::LeAddressManagerCallback bool paused_ = false; AdvertisingCache advertising_cache_; bool is_filter_support_ = false; + bool is_batch_scan_support_ = false; LeScanType le_scan_type_ = LeScanType::ACTIVE; uint32_t interval_ms_{1000}; uint16_t window_ms_{1000}; OwnAddressType own_address_type_{OwnAddressType::PUBLIC_DEVICE_ADDRESS}; LeScanningFilterPolicy filter_policy_{LeScanningFilterPolicy::ACCEPT_ALL}; + BatchScanConfig batch_scan_config_; + std::map> batch_scan_result_cache_; static void check_status(CommandCompleteView view) { switch (view.GetCommandOpCode()) { @@ -1020,6 +1245,38 @@ void LeScanningManager::ScanFilterAdd( CallOn(pimpl_.get(), &impl::scan_filter_add, filter_index, filters); } +void LeScanningManager::BatchScanConifgStorage( + uint8_t batch_scan_full_max, uint8_t batch_scan_truncated_max, uint8_t batch_scan_notify_threshold) { + CallOn( + pimpl_.get(), + &impl::batch_scan_set_storage_parameter, + batch_scan_full_max, + batch_scan_truncated_max, + batch_scan_notify_threshold); +} + +void LeScanningManager::BatchScanEnable( + BatchScanMode scan_mode, + uint32_t duty_cycle_scan_window_slots, + uint32_t duty_cycle_scan_interval_slots, + BatchScanDiscardRule batch_scan_discard_rule) { + CallOn( + pimpl_.get(), + &impl::batch_scan_enable, + scan_mode, + duty_cycle_scan_window_slots, + duty_cycle_scan_interval_slots, + batch_scan_discard_rule); +} + +void LeScanningManager::BatchScanDisable() { + CallOn(pimpl_.get(), &impl::batch_scan_disable); +} + +void LeScanningManager::BatchScanReadReport(ScannerId scanner_id, BatchScanMode scan_mode) { + CallOn(pimpl_.get(), &impl::batch_scan_read_results, scanner_id, 0, scan_mode); +} + void LeScanningManager::RegisterScanningCallback(ScanningCallback* scanning_callback) { CallOn(pimpl_.get(), &impl::register_scanning_callback, scanning_callback); } diff --git a/gd/hci/le_scanning_manager.h b/gd/hci/le_scanning_manager.h index 751b7becd6..aea23ae203 100644 --- a/gd/hci/le_scanning_manager.h +++ b/gd/hci/le_scanning_manager.h @@ -53,6 +53,7 @@ class ScanningCallback { virtual void OnTrackAdvFoundLost() = 0; virtual void OnBatchScanReports( int client_if, int status, int report_format, int num_records, std::vector data) = 0; + virtual void OnBatchScanThresholdCrossed(int client_if) = 0; virtual void OnTimeout() = 0; virtual void OnFilterEnable(Enable enable, uint8_t status) = 0; virtual void OnFilterParamSetup(uint8_t available_spaces, ApcfAction action, uint8_t status) = 0; @@ -88,6 +89,13 @@ class AdvertisingFilterParameter { uint16_t num_of_tracking_entries; }; +enum class BatchScanMode : uint8_t { + DISABLE = 0, + TRUNCATED = 1, + FULL = 2, + TRUNCATED_AND_FULL = 3, +}; + class LeScanningManager : public bluetooth::Module { public: static constexpr uint8_t kMaxAppNum = 32; @@ -112,6 +120,17 @@ class LeScanningManager : public bluetooth::Module { void ScanFilterAdd(uint8_t filter_index, std::vector filters); + /*Batch Scan*/ + void BatchScanConifgStorage( + uint8_t batch_scan_full_max, uint8_t batch_scan_truncated_max, uint8_t batch_scan_notify_threshold); + void BatchScanEnable( + BatchScanMode scan_mode, + uint32_t duty_cycle_scan_window_slots, + uint32_t duty_cycle_scan_interval_slots, + BatchScanDiscardRule batch_scan_discard_rule); + void BatchScanDisable(); + void BatchScanReadReport(ScannerId scanner_id, BatchScanMode scan_mode); + void RegisterScanningCallback(ScanningCallback* scanning_callback); static const ModuleFactory Factory; diff --git a/gd/hci/le_scanning_manager_test.cc b/gd/hci/le_scanning_manager_test.cc index 2d52c015c2..5cb60f891c 100644 --- a/gd/hci/le_scanning_manager_test.cc +++ b/gd/hci/le_scanning_manager_test.cc @@ -118,11 +118,19 @@ class TestHciLayer : public HciLayer { registered_events_[event_code] = event_handler; } + void UnregisterEventHandler(EventCode event_code) override { + registered_events_.erase(event_code); + } + void RegisterLeEventHandler(SubeventCode subevent_code, common::ContextualCallback event_handler) override { registered_le_events_[subevent_code] = event_handler; } + void UnregisterLeEventHandler(SubeventCode subevent_code) override { + registered_le_events_.erase(subevent_code); + } + void IncomingEvent(std::unique_ptr event_builder) { auto packet = GetPacketView(std::move(event_builder)); EventView event = EventView::Create(packet); @@ -235,6 +243,9 @@ class LeScanningManagerTest : public ::testing::Test { if (is_filter_support_) { test_controller_->AddSupported(OpCode::LE_ADV_FILTER); } + if (is_batch_scan_support_) { + test_controller_->AddSupported(OpCode::LE_BATCH_SCAN); + } test_acl_manager_ = new TestAclManager; fake_registry_.InjectTestModule(&HciLayer::Factory, test_hci_layer_); fake_registry_.InjectTestModule(&Controller::Factory, test_controller_); @@ -307,6 +318,7 @@ class LeScanningManagerTest : public ::testing::Test { OnBatchScanReports, (int client_if, int status, int report_format, int num_records, std::vector data), (override)); + MOCK_METHOD(void, OnBatchScanThresholdCrossed, (int client_if), (override)); MOCK_METHOD(void, OnTimeout, (), (override)); MOCK_METHOD(void, OnFilterEnable, (Enable enable, uint8_t status), (override)); MOCK_METHOD(void, OnFilterParamSetup, (uint8_t available_spaces, ApcfAction action, uint8_t status), (override)); @@ -320,6 +332,7 @@ class LeScanningManagerTest : public ::testing::Test { OpCode param_opcode_{OpCode::LE_SET_ADVERTISING_PARAMETERS}; OpCode enable_opcode_{OpCode::LE_SET_SCAN_ENABLE}; bool is_filter_support_ = false; + bool is_batch_scan_support_ = false; }; class LeAndroidHciScanningManagerTest : public LeScanningManagerTest { @@ -327,6 +340,7 @@ class LeAndroidHciScanningManagerTest : public LeScanningManagerTest { void SetUp() override { param_opcode_ = OpCode::LE_EXTENDED_SCAN_PARAMS; is_filter_support_ = true; + is_batch_scan_support_ = true; LeScanningManagerTest::SetUp(); test_controller_->AddSupported(OpCode::LE_ADV_FILTER); } @@ -446,6 +460,44 @@ TEST_F(LeAndroidHciScanningManagerTest, scan_filter_add_test) { sync_client_handler(); } +TEST_F(LeAndroidHciScanningManagerTest, read_batch_scan_result) { + // Enable batch scan feature + auto next_command_future = test_hci_layer_->GetCommandFuture(); + le_scanning_manager->BatchScanConifgStorage(100, 0, 95); + auto result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); + ASSERT_EQ(std::future_status::ready, result); + test_hci_layer_->IncomingEvent(LeBatchScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); + test_hci_layer_->IncomingEvent( + LeBatchScanSetStorageParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); + + // Enable batch scan + next_command_future = test_hci_layer_->GetCommandFuture(); + le_scanning_manager->BatchScanEnable(BatchScanMode::FULL, 2400, 2400, BatchScanDiscardRule::OLDEST); + result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); + ASSERT_EQ(std::future_status::ready, result); + test_hci_layer_->IncomingEvent(LeBatchScanSetScanParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); + + // Read batch scan data + next_command_future = test_hci_layer_->GetCommandFuture(); + le_scanning_manager->BatchScanReadReport(0x01, BatchScanMode::FULL); + result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); + ASSERT_EQ(std::future_status::ready, result); + + EXPECT_CALL(mock_callbacks_, OnBatchScanReports); + std::vector raw_data = {0x5c, 0x1f, 0xa2, 0xc3, 0x63, 0x5d, 0x01, 0xf5, 0xb3, 0x5e, 0x00, 0x0c, 0x02, + 0x01, 0x02, 0x05, 0x09, 0x6d, 0x76, 0x38, 0x76, 0x02, 0x0a, 0xf5, 0x00}; + next_command_future = test_hci_layer_->GetCommandFuture(); + // We will send read command while num_of_record != 0 + test_hci_layer_->IncomingEvent(LeBatchScanReadResultParametersCompleteRawBuilder::Create( + uint8_t{1}, ErrorCode::SUCCESS, BatchScanDataRead::FULL_MODE_DATA, 1, raw_data)); + result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); + ASSERT_EQ(std::future_status::ready, result); + + // OnBatchScanReports will be trigger when num_of_record == 0 + test_hci_layer_->IncomingEvent(LeBatchScanReadResultParametersCompleteRawBuilder::Create( + uint8_t{1}, ErrorCode::SUCCESS, BatchScanDataRead::FULL_MODE_DATA, 0, {})); +} + TEST_F(LeExtendedScanningManagerTest, start_scan_test) { auto next_command_future = test_hci_layer_->GetCommandFuture(); le_scanning_manager->Scan(true); diff --git a/main/shim/btm.cc b/main/shim/btm.cc index b1466b8b2b..20f698a908 100644 --- a/main/shim/btm.cc +++ b/main/shim/btm.cc @@ -135,6 +135,8 @@ void Btm::ScanningCallbacks::OnBatchScanReports(int client_if, int status, int report_format, int num_records, std::vector data){}; + +void Btm::ScanningCallbacks::OnBatchScanThresholdCrossed(int client_if){}; void Btm::ScanningCallbacks::OnTimeout(){}; void Btm::ScanningCallbacks::OnFilterEnable(bluetooth::hci::Enable enable, uint8_t status){}; diff --git a/main/shim/btm.h b/main/shim/btm.h index d447a6178b..ca2c4a28bd 100644 --- a/main/shim/btm.h +++ b/main/shim/btm.h @@ -224,6 +224,7 @@ class Btm { void OnTrackAdvFoundLost(); void OnBatchScanReports(int client_if, int status, int report_format, int num_records, std::vector data); + void OnBatchScanThresholdCrossed(int client_if); void OnTimeout(); void OnFilterEnable(bluetooth::hci::Enable enable, uint8_t status); void OnFilterParamSetup(uint8_t available_spaces, diff --git a/main/shim/le_scanning_manager.cc b/main/shim/le_scanning_manager.cc index c2da541b31..948eb80160 100644 --- a/main/shim/le_scanning_manager.cc +++ b/main/shim/le_scanning_manager.cc @@ -55,6 +55,7 @@ class BleScannerInterfaceImpl : public BleScannerInterface, ~BleScannerInterfaceImpl() override{}; void Init() { + LOG_INFO("init BleScannerInterfaceImpl"); bluetooth::shim::GetScanning()->RegisterScanningCallback(this); } @@ -171,6 +172,9 @@ class BleScannerInterfaceImpl : public BleScannerInterface, int batch_scan_trunc_max, int batch_scan_notify_threshold, Callback cb) { LOG(INFO) << __func__ << " in shim layer"; + bluetooth::shim::GetScanning()->BatchScanConifgStorage( + batch_scan_full_max, batch_scan_trunc_max, batch_scan_notify_threshold); + do_in_jni_thread(FROM_HERE, base::Bind(cb, btm_status_value(BTM_SUCCESS))); } /* Enable batchscan */ @@ -178,16 +182,30 @@ class BleScannerInterfaceImpl : public BleScannerInterface, int scan_window, int addr_type, int discard_rule, Callback cb) { LOG(INFO) << __func__ << " in shim layer"; + auto batch_scan_mode = + static_cast(scan_mode); + auto batch_scan_discard_rule = + static_cast(discard_rule); + bluetooth::shim::GetScanning()->BatchScanEnable( + batch_scan_mode, scan_window, scan_interval, batch_scan_discard_rule); + do_in_jni_thread(FROM_HERE, base::Bind(cb, btm_status_value(BTM_SUCCESS))); } /* Disable batchscan */ virtual void BatchscanDisable(Callback cb) { LOG(INFO) << __func__ << " in shim layer"; + bluetooth::shim::GetScanning()->BatchScanDisable(); + do_in_jni_thread(FROM_HERE, base::Bind(cb, btm_status_value(BTM_SUCCESS))); } /* Read out batchscan reports */ void BatchscanReadReports(int client_if, int scan_mode) { LOG(INFO) << __func__ << " in shim layer"; + auto batch_scan_mode = + static_cast(scan_mode); + auto scanner_id = static_cast(client_if); + bluetooth::shim::GetScanning()->BatchScanReadReport(scanner_id, + batch_scan_mode); } void StartSync(uint8_t sid, RawAddress address, uint16_t skip, @@ -249,7 +267,16 @@ class BleScannerInterfaceImpl : public BleScannerInterface, void OnTrackAdvFoundLost() {} void OnBatchScanReports(int client_if, int status, int report_format, - int num_records, std::vector data) {} + int num_records, std::vector data) { + do_in_jni_thread( + FROM_HERE, + base::BindOnce(&ScanningCallbacks::OnBatchScanReports, + base::Unretained(scanning_callbacks_), client_if, status, + report_format, num_records, data)); + } + + void OnBatchScanThresholdCrossed(int client_if) {} + void OnTimeout() {} void OnFilterEnable(bluetooth::hci::Enable enable, uint8_t status){};