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