/* * 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. */ #define LOG_TAG "bt_gd_neigh" #include "neighbor/scan.h" #include #include "hci/hci_layer.h" #include "hci/hci_packets.h" #include "module.h" #include "os/handler.h" #include "os/log.h" namespace bluetooth { namespace neighbor { struct ScanModule::impl { impl(ScanModule& module); void SetInquiryScan(bool enabled); bool IsInquiryEnabled() const; void SetPageScan(bool enabled); bool IsPageEnabled() const; void Start(); void Stop(); private: ScanModule& module_; bool inquiry_scan_enabled_; bool page_scan_enabled_; void WriteScanEnable(); void ReadScanEnable(hci::ScanEnable); void OnCommandComplete(hci::CommandCompleteView status); hci::HciLayer* hci_layer_; os::Handler* handler_; }; const ModuleFactory neighbor::ScanModule::Factory = ModuleFactory([]() { return new neighbor::ScanModule(); }); neighbor::ScanModule::impl::impl(neighbor::ScanModule& module) : module_(module), inquiry_scan_enabled_(false), page_scan_enabled_(false) {} void neighbor::ScanModule::impl::OnCommandComplete(hci::CommandCompleteView view) { switch (view.GetCommandOpCode()) { case hci::OpCode::READ_SCAN_ENABLE: { auto packet = hci::ReadScanEnableCompleteView::Create(view); ASSERT(packet.IsValid()); ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS); ReadScanEnable(packet.GetScanEnable()); } break; case hci::OpCode::WRITE_SCAN_ENABLE: { auto packet = hci::WriteScanEnableCompleteView::Create(view); ASSERT(packet.IsValid()); ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS); } break; default: LOG_ERROR("Unhandled command %s", hci::OpCodeText(view.GetCommandOpCode()).c_str()); break; } } void neighbor::ScanModule::impl::WriteScanEnable() { hci::ScanEnable scan_enable; if (inquiry_scan_enabled_ && !page_scan_enabled_) { scan_enable = hci::ScanEnable::INQUIRY_SCAN_ONLY; } else if (!inquiry_scan_enabled_ && page_scan_enabled_) { scan_enable = hci::ScanEnable::PAGE_SCAN_ONLY; } else if (inquiry_scan_enabled_ && page_scan_enabled_) { scan_enable = hci::ScanEnable::INQUIRY_AND_PAGE_SCAN; } else { scan_enable = hci::ScanEnable::NO_SCANS; } { std::unique_ptr packet = hci::WriteScanEnableBuilder::Create(scan_enable); hci_layer_->EnqueueCommand(std::move(packet), common::BindOnce(&impl::OnCommandComplete, common::Unretained(this)), handler_); } { std::unique_ptr packet = hci::ReadScanEnableBuilder::Create(); hci_layer_->EnqueueCommand(std::move(packet), common::BindOnce(&impl::OnCommandComplete, common::Unretained(this)), handler_); } } void neighbor::ScanModule::impl::ReadScanEnable(hci::ScanEnable scan_enable) { switch (scan_enable) { case hci::ScanEnable::INQUIRY_SCAN_ONLY: inquiry_scan_enabled_ = true; page_scan_enabled_ = false; break; case hci::ScanEnable::PAGE_SCAN_ONLY: inquiry_scan_enabled_ = false; page_scan_enabled_ = true; break; case hci::ScanEnable::INQUIRY_AND_PAGE_SCAN: inquiry_scan_enabled_ = true; page_scan_enabled_ = true; break; default: inquiry_scan_enabled_ = false; page_scan_enabled_ = false; break; } } void neighbor::ScanModule::impl::SetInquiryScan(bool enabled) { inquiry_scan_enabled_ = enabled; WriteScanEnable(); } void neighbor::ScanModule::impl::SetPageScan(bool enabled) { page_scan_enabled_ = enabled; WriteScanEnable(); } bool neighbor::ScanModule::impl::IsInquiryEnabled() const { return inquiry_scan_enabled_; } bool neighbor::ScanModule::impl::IsPageEnabled() const { return page_scan_enabled_; } void neighbor::ScanModule::impl::Start() { hci_layer_ = module_.GetDependency(); handler_ = module_.GetHandler(); std::unique_ptr packet = hci::ReadScanEnableBuilder::Create(); hci_layer_->EnqueueCommand(std::move(packet), common::BindOnce(&impl::OnCommandComplete, common::Unretained(this)), handler_); } void neighbor::ScanModule::impl::Stop() { LOG_DEBUG("inquiry scan enabled:%d page scan enabled:%d", inquiry_scan_enabled_, page_scan_enabled_); } neighbor::ScanModule::ScanModule() : pimpl_(std::make_unique(*this)) {} neighbor::ScanModule::~ScanModule() { pimpl_.reset(); } void neighbor::ScanModule::SetInquiryScan() { pimpl_->SetInquiryScan(true); } void neighbor::ScanModule::ClearInquiryScan() { pimpl_->SetInquiryScan(false); } void neighbor::ScanModule::SetPageScan() { pimpl_->SetPageScan(true); } void neighbor::ScanModule::ClearPageScan() { pimpl_->SetPageScan(false); } bool neighbor::ScanModule::IsInquiryEnabled() const { return pimpl_->IsInquiryEnabled(); } bool neighbor::ScanModule::IsPageEnabled() const { return pimpl_->IsPageEnabled(); } void neighbor::ScanModule::ListDependencies(ModuleList* list) { list->add(); } void neighbor::ScanModule::Start() { pimpl_->Start(); } void neighbor::ScanModule::Stop() { pimpl_->Stop(); } } // namespace neighbor } // namespace bluetooth