| /* |
| * Copyright 2019 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| #include <memory> |
| #include <mutex> |
| #include <set> |
| |
| #include "hci/controller.h" |
| #include "hci/hci_layer.h" |
| #include "hci/hci_packets.h" |
| #include "hci/le_scanning_interface.h" |
| #include "hci/le_scanning_manager.h" |
| #include "module.h" |
| #include "os/handler.h" |
| #include "os/log.h" |
| |
| namespace bluetooth { |
| namespace hci { |
| |
| const ModuleFactory LeScanningManager::Factory = ModuleFactory([]() { return new LeScanningManager(); }); |
| |
| enum class ScanApiType { |
| LE_4_0 = 1, |
| ANDROID_HCI = 2, |
| LE_5_0 = 3, |
| }; |
| |
| struct LeScanningManager::impl { |
| impl(Module* module) : module_(module), le_scanning_interface_(nullptr) {} |
| |
| void start(os::Handler* handler, hci::HciLayer* hci_layer, hci::Controller* controller) { |
| module_handler_ = handler; |
| hci_layer_ = hci_layer; |
| controller_ = controller; |
| le_scanning_interface_ = hci_layer_->GetLeScanningInterface( |
| common::Bind(&LeScanningManager::impl::handle_scan_results, common::Unretained(this)), module_handler_); |
| if (controller_->IsSupported(OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS)) { |
| api_type_ = ScanApiType::LE_5_0; |
| } else if (controller_->IsSupported(OpCode::LE_EXTENDED_SCAN_PARAMS)) { |
| api_type_ = ScanApiType::ANDROID_HCI; |
| } else { |
| api_type_ = ScanApiType::LE_4_0; |
| } |
| configure_scan(); |
| } |
| |
| void handle_scan_results(LeMetaEventView event) { |
| switch (event.GetSubeventCode()) { |
| case hci::SubeventCode::ADVERTISING_REPORT: |
| handle_advertising_report<LeAdvertisingReportView, LeAdvertisingReport, LeReport>( |
| LeAdvertisingReportView::Create(event)); |
| break; |
| case hci::SubeventCode::DIRECTED_ADVERTISING_REPORT: |
| handle_advertising_report<LeDirectedAdvertisingReportView, LeDirectedAdvertisingReport, DirectedLeReport>( |
| LeDirectedAdvertisingReportView::Create(event)); |
| break; |
| case hci::SubeventCode::EXTENDED_ADVERTISING_REPORT: |
| handle_advertising_report<LeExtendedAdvertisingReportView, LeExtendedAdvertisingReport, ExtendedLeReport>( |
| LeExtendedAdvertisingReportView::Create(event)); |
| break; |
| case hci::SubeventCode::SCAN_TIMEOUT: |
| if (registered_callback_ != nullptr) { |
| registered_callback_->handler->Post( |
| common::BindOnce(&LeScanningManagerCallbacks::on_timeout, common::Unretained(registered_callback_))); |
| registered_callback_ = nullptr; |
| } |
| break; |
| default: |
| LOG_ALWAYS_FATAL("Unknown advertising subevent %s", hci::SubeventCodeText(event.GetSubeventCode()).c_str()); |
| } |
| } |
| |
| template <class EventType, class ReportStructType, class ReportType> |
| void handle_advertising_report(EventType event_view) { |
| if (registered_callback_ == nullptr) { |
| LOG_INFO("Dropping advertising event (no registered handler)"); |
| return; |
| } |
| if (!event_view.IsValid()) { |
| LOG_INFO("Dropping invalid advertising event"); |
| return; |
| } |
| std::vector<ReportStructType> report_vector = event_view.GetAdvertisingReports(); |
| if (report_vector.empty()) { |
| LOG_INFO("Zero results in advertising event"); |
| return; |
| } |
| std::vector<std::shared_ptr<LeReport>> param; |
| param.reserve(report_vector.size()); |
| for (const ReportStructType& report : report_vector) { |
| param.push_back(std::shared_ptr<LeReport>(static_cast<LeReport*>(new ReportType(report)))); |
| } |
| registered_callback_->handler->Post(common::BindOnce(&LeScanningManagerCallbacks::on_advertisements, |
| common::Unretained(registered_callback_), param)); |
| } |
| |
| void configure_scan() { |
| std::vector<PhyScanParameters> parameter_vector; |
| PhyScanParameters phy_scan_parameters; |
| phy_scan_parameters.le_scan_window_ = 0; |
| phy_scan_parameters.le_scan_interval_ = 0; |
| phy_scan_parameters.le_scan_type_ = LeScanType::ACTIVE; |
| parameter_vector.push_back(phy_scan_parameters); |
| uint8_t phys_in_use = 1; |
| |
| switch (api_type_) { |
| case ScanApiType::LE_5_0: |
| le_scanning_interface_->EnqueueCommand(hci::LeSetExtendedScanParametersBuilder::Create( |
| own_address_type_, filter_policy_, phys_in_use, parameter_vector), |
| common::BindOnce(impl::check_status), module_handler_); |
| break; |
| case ScanApiType::ANDROID_HCI: |
| le_scanning_interface_->EnqueueCommand( |
| hci::LeExtendedScanParamsBuilder::Create(LeScanType::ACTIVE, interval_ms_, window_ms_, own_address_type_, |
| filter_policy_), |
| common::BindOnce(impl::check_status), module_handler_); |
| |
| break; |
| case ScanApiType::LE_4_0: |
| le_scanning_interface_->EnqueueCommand( |
| hci::LeSetScanParametersBuilder::Create(LeScanType::ACTIVE, interval_ms_, window_ms_, own_address_type_, |
| filter_policy_), |
| common::BindOnce(impl::check_status), module_handler_); |
| break; |
| } |
| } |
| |
| void start_scan(LeScanningManagerCallbacks* le_scanning_manager_callbacks) { |
| registered_callback_ = le_scanning_manager_callbacks; |
| switch (api_type_) { |
| case ScanApiType::LE_5_0: |
| le_scanning_interface_->EnqueueCommand( |
| hci::LeSetExtendedScanEnableBuilder::Create(Enable::ENABLED, |
| FilterDuplicates::DISABLED /* filter duplicates */, 0, 0), |
| common::BindOnce(impl::check_status), module_handler_); |
| break; |
| case ScanApiType::ANDROID_HCI: |
| case ScanApiType::LE_4_0: |
| le_scanning_interface_->EnqueueCommand( |
| hci::LeSetScanEnableBuilder::Create(Enable::ENABLED, Enable::DISABLED /* filter duplicates */), |
| common::BindOnce(impl::check_status), module_handler_); |
| break; |
| } |
| } |
| |
| void stop_scan(common::Callback<void()> on_stopped) { |
| if (registered_callback_ == nullptr) { |
| return; |
| } |
| registered_callback_->handler->Post(std::move(on_stopped)); |
| switch (api_type_) { |
| case ScanApiType::LE_5_0: |
| le_scanning_interface_->EnqueueCommand( |
| hci::LeSetExtendedScanEnableBuilder::Create(Enable::DISABLED, |
| FilterDuplicates::DISABLED /* filter duplicates */, 0, 0), |
| common::BindOnce(impl::check_status), module_handler_); |
| registered_callback_->handler = nullptr; |
| break; |
| case ScanApiType::ANDROID_HCI: |
| case ScanApiType::LE_4_0: |
| le_scanning_interface_->EnqueueCommand( |
| hci::LeSetScanEnableBuilder::Create(Enable::DISABLED, Enable::DISABLED /* filter duplicates */), |
| common::BindOnce(impl::check_status), module_handler_); |
| registered_callback_->handler = nullptr; |
| break; |
| } |
| } |
| |
| ScanApiType api_type_; |
| |
| LeScanningManagerCallbacks* registered_callback_; |
| Module* module_; |
| os::Handler* module_handler_; |
| hci::HciLayer* hci_layer_; |
| hci::Controller* controller_; |
| hci::LeScanningInterface* le_scanning_interface_; |
| |
| uint32_t interval_ms_{1000}; |
| uint16_t window_ms_{1000}; |
| AddressType own_address_type_{AddressType::PUBLIC_DEVICE_ADDRESS}; |
| LeSetScanningFilterPolicy filter_policy_{LeSetScanningFilterPolicy::ACCEPT_ALL}; |
| |
| static void check_status(CommandCompleteView view) { |
| switch (view.GetCommandOpCode()) { |
| case (OpCode::LE_SET_SCAN_ENABLE): { |
| auto status_view = LeSetScanEnableCompleteView::Create(view); |
| ASSERT(status_view.IsValid()); |
| ASSERT(status_view.GetStatus() == ErrorCode::SUCCESS); |
| } break; |
| case (OpCode::LE_SET_EXTENDED_SCAN_ENABLE): { |
| auto status_view = LeSetExtendedScanEnableCompleteView::Create(view); |
| ASSERT(status_view.IsValid()); |
| ASSERT(status_view.GetStatus() == ErrorCode::SUCCESS); |
| } break; |
| case (OpCode::LE_SET_SCAN_PARAMETERS): { |
| auto status_view = LeSetScanParametersCompleteView::Create(view); |
| ASSERT(status_view.IsValid()); |
| ASSERT(status_view.GetStatus() == ErrorCode::SUCCESS); |
| } break; |
| case (OpCode::LE_EXTENDED_SCAN_PARAMS): { |
| auto status_view = LeExtendedScanParamsCompleteView::Create(view); |
| ASSERT(status_view.IsValid()); |
| ASSERT(status_view.GetStatus() == ErrorCode::SUCCESS); |
| } break; |
| case (OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS): { |
| auto status_view = LeSetExtendedScanParametersCompleteView::Create(view); |
| ASSERT(status_view.IsValid()); |
| ASSERT(status_view.GetStatus() == ErrorCode::SUCCESS); |
| } break; |
| default: |
| LOG_ALWAYS_FATAL("Unhandled event %s", OpCodeText(view.GetCommandOpCode()).c_str()); |
| } |
| } |
| }; |
| |
| LeScanningManager::LeScanningManager() { |
| pimpl_ = std::make_unique<impl>(this); |
| } |
| |
| void LeScanningManager::ListDependencies(ModuleList* list) { |
| list->add<hci::HciLayer>(); |
| list->add<hci::Controller>(); |
| } |
| |
| void LeScanningManager::Start() { |
| pimpl_->start(GetHandler(), GetDependency<hci::HciLayer>(), GetDependency<hci::Controller>()); |
| } |
| |
| void LeScanningManager::Stop() { |
| pimpl_.reset(); |
| } |
| |
| std::string LeScanningManager::ToString() const { |
| return "Le Scanning Manager"; |
| } |
| |
| void LeScanningManager::StartScan(LeScanningManagerCallbacks* callbacks) { |
| GetHandler()->Post(common::Bind(&impl::start_scan, common::Unretained(pimpl_.get()), callbacks)); |
| } |
| |
| void LeScanningManager::StopScan(common::Callback<void()> on_stopped) { |
| GetHandler()->Post(common::Bind(&impl::stop_scan, common::Unretained(pimpl_.get()), on_stopped)); |
| } |
| |
| } // namespace hci |
| } // namespace bluetooth |