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/page.h"
19 
20 #include <memory>
21 
22 #include "common/bind.h"
23 #include "hci/hci_layer.h"
24 #include "hci/hci_packets.h"
25 #include "module.h"
26 #include "neighbor/scan_parameters.h"
27 #include "os/handler.h"
28 #include "os/log.h"
29 
30 namespace bluetooth {
31 namespace neighbor {
32 
33 struct PageModule::impl {
34   void SetScanActivity(ScanParameters params);
35   ScanParameters GetScanActivity() const;
36 
37   void SetScanType(hci::PageScanType type);
38 
39   void SetTimeout(PageTimeout timeout);
40 
41   void Start();
42   void Stop();
43 
44   impl(PageModule& page_module);
45 
46  private:
47   PageModule& module_;
48 
49   ScanParameters scan_parameters_;
50   hci::PageScanType scan_type_;
51   PageTimeout timeout_;
52 
53   void OnCommandComplete(hci::CommandCompleteView status);
54 
55   hci::HciLayer* hci_layer_;
56   os::Handler* handler_;
57 };
58 
__anonf733b2e00102() 59 const ModuleFactory neighbor::PageModule::Factory = ModuleFactory([]() { return new neighbor::PageModule(); });
60 
impl(neighbor::PageModule & module)61 neighbor::PageModule::impl::impl(neighbor::PageModule& module) : module_(module) {}
62 
OnCommandComplete(hci::CommandCompleteView view)63 void neighbor::PageModule::impl::OnCommandComplete(hci::CommandCompleteView view) {
64   switch (view.GetCommandOpCode()) {
65     case hci::OpCode::WRITE_PAGE_SCAN_ACTIVITY: {
66       auto packet = hci::WritePageScanActivityCompleteView::Create(view);
67       ASSERT(packet.IsValid());
68       ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
69     } break;
70 
71     case hci::OpCode::READ_PAGE_SCAN_ACTIVITY: {
72       auto packet = hci::ReadPageScanActivityCompleteView::Create(view);
73       ASSERT(packet.IsValid());
74       ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
75       scan_parameters_.interval = packet.GetPageScanInterval();
76       scan_parameters_.window = packet.GetPageScanWindow();
77     } break;
78 
79     case hci::OpCode::WRITE_PAGE_SCAN_TYPE: {
80       auto packet = hci::WritePageScanTypeCompleteView::Create(view);
81       ASSERT(packet.IsValid());
82       ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
83     } break;
84 
85     case hci::OpCode::READ_PAGE_SCAN_TYPE: {
86       auto packet = hci::ReadPageScanTypeCompleteView::Create(view);
87       ASSERT(packet.IsValid());
88       ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
89       scan_type_ = packet.GetPageScanType();
90     } break;
91 
92     case hci::OpCode::WRITE_PAGE_TIMEOUT: {
93       auto packet = hci::WritePageTimeoutCompleteView::Create(view);
94       ASSERT(packet.IsValid());
95       ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
96     } break;
97 
98     case hci::OpCode::READ_PAGE_TIMEOUT: {
99       auto packet = hci::ReadPageTimeoutCompleteView::Create(view);
100       ASSERT(packet.IsValid());
101       ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
102       timeout_ = packet.GetPageTimeout();
103     } break;
104 
105     default:
106       LOG_ERROR("Unhandled command %s", hci::OpCodeText(view.GetCommandOpCode()).c_str());
107       break;
108   }
109 }
110 
Start()111 void neighbor::PageModule::impl::Start() {
112   hci_layer_ = module_.GetDependency<hci::HciLayer>();
113   handler_ = module_.GetHandler();
114 
115   hci_layer_->EnqueueCommand(
116       hci::ReadPageScanActivityBuilder::Create(), handler_->BindOnceOn(this, &impl::OnCommandComplete));
117 
118   hci_layer_->EnqueueCommand(
119       hci::ReadPageScanTypeBuilder::Create(), handler_->BindOnceOn(this, &impl::OnCommandComplete));
120 
121   hci_layer_->EnqueueCommand(
122       hci::ReadPageTimeoutBuilder::Create(), handler_->BindOnceOn(this, &impl::OnCommandComplete));
123 }
124 
Stop()125 void neighbor::PageModule::impl::Stop() {
126   LOG_INFO("Page scan interval:%hd window:%hd", scan_parameters_.interval, scan_parameters_.window);
127   LOG_INFO("Page scan_type:%s", hci::PageScanTypeText(scan_type_).c_str());
128 }
129 
SetScanActivity(ScanParameters params)130 void neighbor::PageModule::impl::SetScanActivity(ScanParameters params) {
131   hci_layer_->EnqueueCommand(
132       hci::WritePageScanActivityBuilder::Create(params.interval, params.window),
133       handler_->BindOnceOn(this, &impl::OnCommandComplete));
134 
135   hci_layer_->EnqueueCommand(
136       hci::ReadPageScanActivityBuilder::Create(), handler_->BindOnceOn(this, &impl::OnCommandComplete));
137   LOG_INFO(
138       "Set page scan activity interval:0x%x/%.02fms window:0x%x/%.02fms",
139       params.interval,
140       ScanIntervalTimeMs(params.interval),
141       params.window,
142       ScanWindowTimeMs(params.window));
143 }
144 
GetScanActivity() const145 ScanParameters neighbor::PageModule::impl::GetScanActivity() const {
146   return scan_parameters_;
147 }
148 
SetScanType(hci::PageScanType scan_type)149 void neighbor::PageModule::impl::SetScanType(hci::PageScanType scan_type) {
150   hci_layer_->EnqueueCommand(
151       hci::WritePageScanTypeBuilder::Create(scan_type), handler_->BindOnceOn(this, &impl::OnCommandComplete));
152 
153   hci_layer_->EnqueueCommand(
154       hci::ReadPageScanTypeBuilder::Create(), handler_->BindOnceOn(this, &impl::OnCommandComplete));
155   LOG_INFO("Set page scan type:%s", hci::PageScanTypeText(scan_type).c_str());
156 }
157 
SetTimeout(PageTimeout timeout)158 void neighbor::PageModule::impl::SetTimeout(PageTimeout timeout) {
159   hci_layer_->EnqueueCommand(
160       hci::WritePageTimeoutBuilder::Create(timeout), handler_->BindOnceOn(this, &impl::OnCommandComplete));
161 
162   hci_layer_->EnqueueCommand(
163       hci::ReadPageTimeoutBuilder::Create(), handler_->BindOnceOn(this, &impl::OnCommandComplete));
164   LOG_INFO("Set page scan timeout:0x%x/%.02fms", timeout, PageTimeoutMs(timeout));
165 }
166 
167 /**
168  * General API here
169  */
PageModule()170 neighbor::PageModule::PageModule() : pimpl_(std::make_unique<impl>(*this)) {}
171 
~PageModule()172 neighbor::PageModule::~PageModule() {
173   pimpl_.reset();
174 }
175 
SetScanActivity(ScanParameters params)176 void neighbor::PageModule::SetScanActivity(ScanParameters params) {
177   pimpl_->SetScanActivity(params);
178 }
179 
GetScanActivity() const180 ScanParameters neighbor::PageModule::GetScanActivity() const {
181   return pimpl_->GetScanActivity();
182 }
183 
SetInterlacedScan()184 void neighbor::PageModule::SetInterlacedScan() {
185   pimpl_->SetScanType(hci::PageScanType::INTERLACED);
186 }
187 
SetStandardScan()188 void neighbor::PageModule::SetStandardScan() {
189   pimpl_->SetScanType(hci::PageScanType::STANDARD);
190 }
191 
SetTimeout(PageTimeout timeout)192 void neighbor::PageModule::SetTimeout(PageTimeout timeout) {
193   pimpl_->SetTimeout(timeout);
194 }
195 
196 /**
197  * Module methods here
198  */
ListDependencies(ModuleList * list)199 void neighbor::PageModule::ListDependencies(ModuleList* list) {
200   list->add<hci::HciLayer>();
201 }
202 
Start()203 void neighbor::PageModule::Start() {
204   pimpl_->Start();
205 }
206 
Stop()207 void neighbor::PageModule::Stop() {
208   pimpl_->Stop();
209 }
210 
211 }  // namespace neighbor
212 }  // namespace bluetooth
213