1 /*
2  * Copyright 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #define LOG_TAG "bt_gd_neigh"
17 
18 #include "neighbor/scan.h"
19 
20 #include <memory>
21 
22 #include "hci/hci_layer.h"
23 #include "hci/hci_packets.h"
24 #include "module.h"
25 #include "os/handler.h"
26 #include "os/log.h"
27 
28 namespace bluetooth {
29 namespace neighbor {
30 
31 struct ScanModule::impl {
32   impl(ScanModule& module);
33 
34   void SetInquiryScan(bool enabled);
35   bool IsInquiryEnabled() const;
36 
37   void SetPageScan(bool enabled);
38   bool IsPageEnabled() const;
39 
40   void Start();
41   void Stop();
42 
43  private:
44   ScanModule& module_;
45 
46   bool inquiry_scan_enabled_;
47   bool page_scan_enabled_;
48 
49   void WriteScanEnable();
50   void ReadScanEnable(hci::ScanEnable);
51 
52   void OnCommandComplete(hci::CommandCompleteView status);
53 
54   hci::HciLayer* hci_layer_;
55   os::Handler* handler_;
56 };
57 
__anone26516c80102() 58 const ModuleFactory neighbor::ScanModule::Factory = ModuleFactory([]() { return new neighbor::ScanModule(); });
59 
impl(neighbor::ScanModule & module)60 neighbor::ScanModule::impl::impl(neighbor::ScanModule& module)
61     : module_(module), inquiry_scan_enabled_(false), page_scan_enabled_(false) {}
62 
OnCommandComplete(hci::CommandCompleteView view)63 void neighbor::ScanModule::impl::OnCommandComplete(hci::CommandCompleteView view) {
64   switch (view.GetCommandOpCode()) {
65     case hci::OpCode::READ_SCAN_ENABLE: {
66       auto packet = hci::ReadScanEnableCompleteView::Create(view);
67       ASSERT(packet.IsValid());
68       ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
69       ReadScanEnable(packet.GetScanEnable());
70     } break;
71 
72     case hci::OpCode::WRITE_SCAN_ENABLE: {
73       auto packet = hci::WriteScanEnableCompleteView::Create(view);
74       ASSERT(packet.IsValid());
75       ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
76     } break;
77 
78     default:
79       LOG_ERROR("Unhandled command %s", hci::OpCodeText(view.GetCommandOpCode()).c_str());
80       break;
81   }
82 }
83 
WriteScanEnable()84 void neighbor::ScanModule::impl::WriteScanEnable() {
85   hci::ScanEnable scan_enable;
86 
87   if (inquiry_scan_enabled_ && !page_scan_enabled_) {
88     scan_enable = hci::ScanEnable::INQUIRY_SCAN_ONLY;
89   } else if (!inquiry_scan_enabled_ && page_scan_enabled_) {
90     scan_enable = hci::ScanEnable::PAGE_SCAN_ONLY;
91   } else if (inquiry_scan_enabled_ && page_scan_enabled_) {
92     scan_enable = hci::ScanEnable::INQUIRY_AND_PAGE_SCAN;
93   } else {
94     scan_enable = hci::ScanEnable::NO_SCANS;
95   }
96 
97   {
98     std::unique_ptr<hci::WriteScanEnableBuilder> packet = hci::WriteScanEnableBuilder::Create(scan_enable);
99     hci_layer_->EnqueueCommand(std::move(packet), handler_->BindOnceOn(this, &impl::OnCommandComplete));
100   }
101 
102   {
103     std::unique_ptr<hci::ReadScanEnableBuilder> packet = hci::ReadScanEnableBuilder::Create();
104     hci_layer_->EnqueueCommand(std::move(packet), handler_->BindOnceOn(this, &impl::OnCommandComplete));
105   }
106 }
107 
ReadScanEnable(hci::ScanEnable scan_enable)108 void neighbor::ScanModule::impl::ReadScanEnable(hci::ScanEnable scan_enable) {
109   switch (scan_enable) {
110     case hci::ScanEnable::INQUIRY_SCAN_ONLY:
111       inquiry_scan_enabled_ = true;
112       page_scan_enabled_ = false;
113       break;
114 
115     case hci::ScanEnable::PAGE_SCAN_ONLY:
116       inquiry_scan_enabled_ = false;
117       page_scan_enabled_ = true;
118       break;
119 
120     case hci::ScanEnable::INQUIRY_AND_PAGE_SCAN:
121       inquiry_scan_enabled_ = true;
122       page_scan_enabled_ = true;
123       break;
124 
125     default:
126       inquiry_scan_enabled_ = false;
127       page_scan_enabled_ = false;
128       break;
129   }
130 }
131 
SetInquiryScan(bool enabled)132 void neighbor::ScanModule::impl::SetInquiryScan(bool enabled) {
133   inquiry_scan_enabled_ = enabled;
134   WriteScanEnable();
135 }
136 
SetPageScan(bool enabled)137 void neighbor::ScanModule::impl::SetPageScan(bool enabled) {
138   page_scan_enabled_ = enabled;
139   WriteScanEnable();
140 }
141 
IsInquiryEnabled() const142 bool neighbor::ScanModule::impl::IsInquiryEnabled() const {
143   return inquiry_scan_enabled_;
144 }
145 
IsPageEnabled() const146 bool neighbor::ScanModule::impl::IsPageEnabled() const {
147   return page_scan_enabled_;
148 }
149 
Start()150 void neighbor::ScanModule::impl::Start() {
151   hci_layer_ = module_.GetDependency<hci::HciLayer>();
152   handler_ = module_.GetHandler();
153 
154   std::unique_ptr<hci::ReadScanEnableBuilder> packet = hci::ReadScanEnableBuilder::Create();
155   hci_layer_->EnqueueCommand(std::move(packet), handler_->BindOnceOn(this, &impl::OnCommandComplete));
156 }
157 
Stop()158 void neighbor::ScanModule::impl::Stop() {
159   LOG_DEBUG("inquiry scan enabled:%d page scan enabled:%d", inquiry_scan_enabled_, page_scan_enabled_);
160 }
161 
ScanModule()162 neighbor::ScanModule::ScanModule() : pimpl_(std::make_unique<impl>(*this)) {}
163 
~ScanModule()164 neighbor::ScanModule::~ScanModule() {
165   pimpl_.reset();
166 }
167 
SetInquiryScan()168 void neighbor::ScanModule::SetInquiryScan() {
169   pimpl_->SetInquiryScan(true);
170 }
171 
ClearInquiryScan()172 void neighbor::ScanModule::ClearInquiryScan() {
173   pimpl_->SetInquiryScan(false);
174 }
175 
SetPageScan()176 void neighbor::ScanModule::SetPageScan() {
177   pimpl_->SetPageScan(true);
178 }
179 
ClearPageScan()180 void neighbor::ScanModule::ClearPageScan() {
181   pimpl_->SetPageScan(false);
182 }
183 
IsInquiryEnabled() const184 bool neighbor::ScanModule::IsInquiryEnabled() const {
185   return pimpl_->IsInquiryEnabled();
186 }
187 
IsPageEnabled() const188 bool neighbor::ScanModule::IsPageEnabled() const {
189   return pimpl_->IsPageEnabled();
190 }
191 
ListDependencies(ModuleList * list)192 void neighbor::ScanModule::ListDependencies(ModuleList* list) {
193   list->add<hci::HciLayer>();
194 }
195 
Start()196 void neighbor::ScanModule::Start() {
197   pimpl_->Start();
198 }
199 
Stop()200 void neighbor::ScanModule::Stop() {
201   pimpl_->Stop();
202 }
203 
204 }  // namespace neighbor
205 }  // namespace bluetooth
206