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/inquiry.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 "os/handler.h"
27 #include "os/log.h"
28
29 namespace bluetooth {
30 namespace neighbor {
31
32 static constexpr uint8_t kGeneralInquiryAccessCode = 0x33;
33 static constexpr uint8_t kLimitedInquiryAccessCode = 0x00;
34
35 struct InquiryModule::impl {
36 void RegisterCallbacks(InquiryCallbacks inquiry_callbacks);
37 void UnregisterCallbacks();
38
39 void StartOneShotInquiry(bool limited, InquiryLength inquiry_length, NumResponses num_responses);
40 void StopOneShotInquiry();
41
42 void StartPeriodicInquiry(bool limited, InquiryLength inquiry_length, NumResponses num_responses,
43 PeriodLength max_delay, PeriodLength min_delay);
44 void StopPeriodicInquiry();
45
46 void SetScanActivity(ScanParameters params);
47
48 void SetScanType(hci::InquiryScanType scan_type);
49
50 void SetInquiryMode(hci::InquiryMode mode);
51
52 void Start();
53 void Stop();
54
55 bool HasCallbacks() const;
56
57 impl(InquiryModule& inquiry_module);
58
59 private:
60 InquiryCallbacks inquiry_callbacks_;
61
62 InquiryModule& module_;
63
64 bool active_general_one_shot_{false};
65 bool active_limited_one_shot_{false};
66 bool active_general_periodic_{false};
67 bool active_limited_periodic_{false};
68
69 ScanParameters inquiry_scan_;
70 hci::InquiryMode inquiry_mode_;
71 hci::InquiryScanType inquiry_scan_type_;
72 int8_t inquiry_response_tx_power_;
73
74 bool IsInquiryActive() const;
75
76 void EnqueueCommandComplete(std::unique_ptr<hci::CommandPacketBuilder> command);
77 void EnqueueCommandStatus(std::unique_ptr<hci::CommandPacketBuilder> command);
78 void OnCommandComplete(hci::CommandCompleteView view);
79 void OnCommandStatus(hci::CommandStatusView status);
80
81 void EnqueueCommandCompleteSync(std::unique_ptr<hci::CommandPacketBuilder> command);
82 void OnCommandCompleteSync(hci::CommandCompleteView view);
83
84 void OnEvent(hci::EventPacketView view);
85
86 std::promise<void>* command_sync_{nullptr};
87
88 hci::HciLayer* hci_layer_;
89 os::Handler* handler_;
90 };
91
__anonde04eb3f0102() 92 const ModuleFactory neighbor::InquiryModule::Factory = ModuleFactory([]() { return new neighbor::InquiryModule(); });
93
impl(neighbor::InquiryModule & module)94 neighbor::InquiryModule::impl::impl(neighbor::InquiryModule& module) : module_(module) {}
95
OnCommandCompleteSync(hci::CommandCompleteView view)96 void neighbor::InquiryModule::impl::OnCommandCompleteSync(hci::CommandCompleteView view) {
97 OnCommandComplete(view);
98 ASSERT(command_sync_ != nullptr);
99 command_sync_->set_value();
100 }
101
OnCommandComplete(hci::CommandCompleteView view)102 void neighbor::InquiryModule::impl::OnCommandComplete(hci::CommandCompleteView view) {
103 switch (view.GetCommandOpCode()) {
104 case hci::OpCode::INQUIRY_CANCEL: {
105 auto packet = hci::InquiryCancelCompleteView::Create(view);
106 ASSERT(packet.IsValid());
107 ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
108 } break;
109
110 case hci::OpCode::PERIODIC_INQUIRY_MODE: {
111 auto packet = hci::PeriodicInquiryModeCompleteView::Create(view);
112 ASSERT(packet.IsValid());
113 ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
114 } break;
115
116 case hci::OpCode::EXIT_PERIODIC_INQUIRY_MODE: {
117 auto packet = hci::ExitPeriodicInquiryModeCompleteView::Create(view);
118 ASSERT(packet.IsValid());
119 ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
120 } break;
121
122 case hci::OpCode::WRITE_INQUIRY_MODE: {
123 auto packet = hci::WriteInquiryModeCompleteView::Create(view);
124 ASSERT(packet.IsValid());
125 ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
126 } break;
127
128 case hci::OpCode::READ_INQUIRY_MODE: {
129 auto packet = hci::ReadInquiryModeCompleteView::Create(view);
130 ASSERT(packet.IsValid());
131 ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
132 inquiry_mode_ = packet.GetInquiryMode();
133 } break;
134
135 case hci::OpCode::READ_INQUIRY_RESPONSE_TRANSMIT_POWER_LEVEL: {
136 auto packet = hci::ReadInquiryResponseTransmitPowerLevelCompleteView::Create(view);
137 ASSERT(packet.IsValid());
138 ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
139 inquiry_response_tx_power_ = packet.GetTxPower();
140 } break;
141
142 case hci::OpCode::WRITE_INQUIRY_SCAN_ACTIVITY: {
143 auto packet = hci::WriteInquiryScanActivityCompleteView::Create(view);
144 ASSERT(packet.IsValid());
145 ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
146 } break;
147
148 case hci::OpCode::READ_INQUIRY_SCAN_ACTIVITY: {
149 auto packet = hci::ReadInquiryScanActivityCompleteView::Create(view);
150 ASSERT(packet.IsValid());
151 ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
152 inquiry_scan_.interval = packet.GetInquiryScanInterval();
153 inquiry_scan_.window = packet.GetInquiryScanWindow();
154 } break;
155
156 case hci::OpCode::WRITE_INQUIRY_SCAN_TYPE: {
157 auto packet = hci::WriteInquiryScanTypeCompleteView::Create(view);
158 ASSERT(packet.IsValid());
159 ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
160 } break;
161
162 case hci::OpCode::READ_INQUIRY_SCAN_TYPE: {
163 auto packet = hci::ReadInquiryScanTypeCompleteView::Create(view);
164 ASSERT(packet.IsValid());
165 ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
166 inquiry_scan_type_ = packet.GetInquiryScanType();
167 } break;
168
169 default:
170 LOG_WARN("Unhandled command:%s", hci::OpCodeText(view.GetCommandOpCode()).c_str());
171 break;
172 }
173 }
174
OnCommandStatus(hci::CommandStatusView status)175 void neighbor::InquiryModule::impl::OnCommandStatus(hci::CommandStatusView status) {
176 ASSERT(status.GetStatus() == hci::ErrorCode::SUCCESS);
177
178 switch (status.GetCommandOpCode()) {
179 case hci::OpCode::INQUIRY: {
180 auto packet = hci::InquiryStatusView::Create(status);
181 ASSERT(packet.IsValid());
182 if (active_limited_one_shot_ || active_general_one_shot_) {
183 LOG_DEBUG("Inquiry started lap: %s", active_limited_one_shot_ ? "Limited" : "General");
184 }
185 } break;
186
187 default:
188 LOG_WARN("Unhandled command:%s", hci::OpCodeText(status.GetCommandOpCode()).c_str());
189 break;
190 }
191 }
192
OnEvent(hci::EventPacketView view)193 void neighbor::InquiryModule::impl::OnEvent(hci::EventPacketView view) {
194 switch (view.GetEventCode()) {
195 case hci::EventCode::INQUIRY_COMPLETE: {
196 auto packet = hci::InquiryCompleteView::Create(view);
197 ASSERT(packet.IsValid());
198 LOG_DEBUG("inquiry complete");
199 active_limited_one_shot_ = false;
200 active_general_one_shot_ = false;
201 inquiry_callbacks_.complete(packet.GetStatus());
202 } break;
203
204 case hci::EventCode::INQUIRY_RESULT: {
205 auto packet = hci::InquiryResultView::Create(view);
206 ASSERT(packet.IsValid());
207 LOG_DEBUG("Inquiry result size:%zd num_responses:%zu", packet.size(), packet.GetInquiryResults().size());
208 inquiry_callbacks_.result(packet);
209 } break;
210
211 case hci::EventCode::INQUIRY_RESULT_WITH_RSSI: {
212 auto packet = hci::InquiryResultWithRssiView::Create(view);
213 ASSERT(packet.IsValid());
214 LOG_DEBUG("Inquiry result with rssi num_responses:%zu", packet.GetInquiryResults().size());
215 inquiry_callbacks_.result_with_rssi(packet);
216 } break;
217
218 case hci::EventCode::EXTENDED_INQUIRY_RESULT: {
219 auto packet = hci::ExtendedInquiryResultView::Create(view);
220 ASSERT(packet.IsValid());
221 LOG_DEBUG("Extended inquiry result addr:%s repetition_mode:%s cod:%s clock_offset:%d rssi:%hhd",
222 packet.GetAddress().ToString().c_str(),
223 hci::PageScanRepetitionModeText(packet.GetPageScanRepetitionMode()).c_str(),
224 packet.GetClassOfDevice().ToString().c_str(), packet.GetClockOffset(), packet.GetRssi());
225 inquiry_callbacks_.extended_result(packet);
226 } break;
227
228 default:
229 LOG_ERROR("Unhandled event:%s", hci::EventCodeText(view.GetEventCode()).c_str());
230 break;
231 }
232 }
233
234 /**
235 * impl
236 */
RegisterCallbacks(InquiryCallbacks callbacks)237 void neighbor::InquiryModule::impl::RegisterCallbacks(InquiryCallbacks callbacks) {
238 inquiry_callbacks_ = callbacks;
239
240 hci_layer_->RegisterEventHandler(hci::EventCode::INQUIRY_RESULT,
241 common::Bind(&InquiryModule::impl::OnEvent, common::Unretained(this)), handler_);
242 hci_layer_->RegisterEventHandler(hci::EventCode::INQUIRY_RESULT_WITH_RSSI,
243 common::Bind(&InquiryModule::impl::OnEvent, common::Unretained(this)), handler_);
244 hci_layer_->RegisterEventHandler(hci::EventCode::EXTENDED_INQUIRY_RESULT,
245 common::Bind(&InquiryModule::impl::OnEvent, common::Unretained(this)), handler_);
246 hci_layer_->RegisterEventHandler(hci::EventCode::INQUIRY_COMPLETE,
247 common::Bind(&InquiryModule::impl::OnEvent, common::Unretained(this)), handler_);
248 }
249
UnregisterCallbacks()250 void neighbor::InquiryModule::impl::UnregisterCallbacks() {
251 hci_layer_->UnregisterEventHandler(hci::EventCode::INQUIRY_COMPLETE);
252 hci_layer_->UnregisterEventHandler(hci::EventCode::EXTENDED_INQUIRY_RESULT);
253 hci_layer_->UnregisterEventHandler(hci::EventCode::INQUIRY_RESULT_WITH_RSSI);
254 hci_layer_->UnregisterEventHandler(hci::EventCode::INQUIRY_RESULT);
255
256 inquiry_callbacks_ = {nullptr, nullptr, nullptr, nullptr};
257 }
258
EnqueueCommandComplete(std::unique_ptr<hci::CommandPacketBuilder> command)259 void neighbor::InquiryModule::impl::EnqueueCommandComplete(std::unique_ptr<hci::CommandPacketBuilder> command) {
260 hci_layer_->EnqueueCommand(std::move(command), common::BindOnce(&impl::OnCommandComplete, common::Unretained(this)),
261 handler_);
262 }
263
EnqueueCommandStatus(std::unique_ptr<hci::CommandPacketBuilder> command)264 void neighbor::InquiryModule::impl::EnqueueCommandStatus(std::unique_ptr<hci::CommandPacketBuilder> command) {
265 hci_layer_->EnqueueCommand(std::move(command), common::BindOnce(&impl::OnCommandStatus, common::Unretained(this)),
266 handler_);
267 }
268
EnqueueCommandCompleteSync(std::unique_ptr<hci::CommandPacketBuilder> command)269 void neighbor::InquiryModule::impl::EnqueueCommandCompleteSync(std::unique_ptr<hci::CommandPacketBuilder> command) {
270 ASSERT(command_sync_ == nullptr);
271 command_sync_ = new std::promise<void>();
272 auto command_received = command_sync_->get_future();
273 hci_layer_->EnqueueCommand(std::move(command),
274 common::BindOnce(&impl::OnCommandCompleteSync, common::Unretained(this)), handler_);
275 command_received.wait();
276 delete command_sync_;
277 command_sync_ = nullptr;
278 }
279
StartOneShotInquiry(bool limited,InquiryLength inquiry_length,NumResponses num_responses)280 void neighbor::InquiryModule::impl::StartOneShotInquiry(bool limited, InquiryLength inquiry_length,
281 NumResponses num_responses) {
282 ASSERT(HasCallbacks());
283 ASSERT(!IsInquiryActive());
284 hci::Lap lap;
285 if (limited) {
286 active_limited_one_shot_ = true;
287 lap.lap_ = kLimitedInquiryAccessCode;
288 } else {
289 active_general_one_shot_ = true;
290 lap.lap_ = kGeneralInquiryAccessCode;
291 }
292 EnqueueCommandStatus(hci::InquiryBuilder::Create(lap, inquiry_length, num_responses));
293 }
294
StopOneShotInquiry()295 void neighbor::InquiryModule::impl::StopOneShotInquiry() {
296 ASSERT(active_general_one_shot_ || active_limited_one_shot_);
297 active_general_one_shot_ = false;
298 active_limited_one_shot_ = false;
299 EnqueueCommandComplete(hci::InquiryCancelBuilder::Create());
300 }
301
StartPeriodicInquiry(bool limited,InquiryLength inquiry_length,NumResponses num_responses,PeriodLength max_delay,PeriodLength min_delay)302 void neighbor::InquiryModule::impl::StartPeriodicInquiry(bool limited, InquiryLength inquiry_length,
303 NumResponses num_responses, PeriodLength max_delay,
304 PeriodLength min_delay) {
305 ASSERT(HasCallbacks());
306 ASSERT(!IsInquiryActive());
307 hci::Lap lap;
308 if (limited) {
309 active_limited_periodic_ = true;
310 lap.lap_ = kLimitedInquiryAccessCode;
311 } else {
312 active_general_periodic_ = true;
313 lap.lap_ = kGeneralInquiryAccessCode;
314 }
315 EnqueueCommandComplete(
316 hci::PeriodicInquiryModeBuilder::Create(max_delay, min_delay, lap, inquiry_length, num_responses));
317 }
318
StopPeriodicInquiry()319 void neighbor::InquiryModule::impl::StopPeriodicInquiry() {
320 ASSERT(active_general_periodic_ || active_limited_periodic_);
321 active_general_periodic_ = false;
322 active_limited_periodic_ = false;
323 EnqueueCommandComplete(hci::ExitPeriodicInquiryModeBuilder::Create());
324 }
325
IsInquiryActive() const326 bool neighbor::InquiryModule::impl::IsInquiryActive() const {
327 return active_general_one_shot_ || active_limited_one_shot_ || active_limited_periodic_ || active_general_periodic_;
328 }
329
Start()330 void neighbor::InquiryModule::impl::Start() {
331 hci_layer_ = module_.GetDependency<hci::HciLayer>();
332 handler_ = module_.GetHandler();
333
334 EnqueueCommandComplete(hci::ReadInquiryResponseTransmitPowerLevelBuilder::Create());
335 EnqueueCommandComplete(hci::ReadInquiryScanActivityBuilder::Create());
336 EnqueueCommandComplete(hci::ReadInquiryScanTypeBuilder::Create());
337 EnqueueCommandCompleteSync(hci::ReadInquiryModeBuilder::Create());
338
339 LOG_DEBUG("Started inquiry module");
340 }
341
Stop()342 void neighbor::InquiryModule::impl::Stop() {
343 LOG_INFO("Inquiry scan interval:%hu window:%hu", inquiry_scan_.interval, inquiry_scan_.window);
344 LOG_INFO("Inquiry mode:%s scan_type:%s", hci::InquiryModeText(inquiry_mode_).c_str(),
345 hci::InquiryScanTypeText(inquiry_scan_type_).c_str());
346 LOG_INFO("Inquiry response tx power:%hhd", inquiry_response_tx_power_);
347 LOG_DEBUG("Stopped inquiry module");
348 }
349
SetInquiryMode(hci::InquiryMode mode)350 void neighbor::InquiryModule::impl::SetInquiryMode(hci::InquiryMode mode) {
351 EnqueueCommandComplete(hci::WriteInquiryModeBuilder::Create(mode));
352 inquiry_mode_ = mode;
353 LOG_DEBUG("Set inquiry mode:%s", hci::InquiryModeText(mode).c_str());
354 }
355
SetScanActivity(ScanParameters params)356 void neighbor::InquiryModule::impl::SetScanActivity(ScanParameters params) {
357 EnqueueCommandComplete(hci::WriteInquiryScanActivityBuilder::Create(params.interval, params.window));
358 inquiry_scan_ = params;
359 LOG_DEBUG("Set scan activity interval:0x%x/%.02fms window:0x%x/%.02fms", params.interval,
360 ScanIntervalTimeMs(params.interval), params.window, ScanWindowTimeMs(params.window));
361 }
362
SetScanType(hci::InquiryScanType scan_type)363 void neighbor::InquiryModule::impl::SetScanType(hci::InquiryScanType scan_type) {
364 EnqueueCommandComplete(hci::WriteInquiryScanTypeBuilder::Create(scan_type));
365 LOG_DEBUG("Set scan type:%s", hci::InquiryScanTypeText(scan_type).c_str());
366 }
367
HasCallbacks() const368 bool neighbor::InquiryModule::impl::HasCallbacks() const {
369 return inquiry_callbacks_.result != nullptr && inquiry_callbacks_.result_with_rssi != nullptr &&
370 inquiry_callbacks_.extended_result != nullptr && inquiry_callbacks_.complete != nullptr;
371 }
372
373 /**
374 * General API here
375 */
InquiryModule()376 neighbor::InquiryModule::InquiryModule() : pimpl_(std::make_unique<impl>(*this)) {}
377
~InquiryModule()378 neighbor::InquiryModule::~InquiryModule() {
379 pimpl_.reset();
380 }
381
RegisterCallbacks(InquiryCallbacks callbacks)382 void neighbor::InquiryModule::RegisterCallbacks(InquiryCallbacks callbacks) {
383 pimpl_->RegisterCallbacks(callbacks);
384 }
385
UnregisterCallbacks()386 void neighbor::InquiryModule::UnregisterCallbacks() {
387 pimpl_->UnregisterCallbacks();
388 }
389
StartGeneralInquiry(InquiryLength inquiry_length,NumResponses num_responses)390 void neighbor::InquiryModule::StartGeneralInquiry(InquiryLength inquiry_length, NumResponses num_responses) {
391 GetHandler()->Post(common::BindOnce(&neighbor::InquiryModule::impl::StartOneShotInquiry,
392 common::Unretained(pimpl_.get()), false, inquiry_length, num_responses));
393 }
394
StartLimitedInquiry(InquiryLength inquiry_length,NumResponses num_responses)395 void neighbor::InquiryModule::StartLimitedInquiry(InquiryLength inquiry_length, NumResponses num_responses) {
396 GetHandler()->Post(common::BindOnce(&neighbor::InquiryModule::impl::StartOneShotInquiry,
397 common::Unretained(pimpl_.get()), true, inquiry_length, num_responses));
398 }
399
StopInquiry()400 void neighbor::InquiryModule::StopInquiry() {
401 GetHandler()->Post(
402 common::BindOnce(&neighbor::InquiryModule::impl::StopOneShotInquiry, common::Unretained(pimpl_.get())));
403 }
404
StartGeneralPeriodicInquiry(InquiryLength inquiry_length,NumResponses num_responses,PeriodLength max_delay,PeriodLength min_delay)405 void neighbor::InquiryModule::StartGeneralPeriodicInquiry(InquiryLength inquiry_length, NumResponses num_responses,
406 PeriodLength max_delay, PeriodLength min_delay) {
407 GetHandler()->Post(common::BindOnce(&neighbor::InquiryModule::impl::StartPeriodicInquiry,
408 common::Unretained(pimpl_.get()), false, inquiry_length, num_responses, max_delay,
409 min_delay));
410 }
411
StartLimitedPeriodicInquiry(InquiryLength inquiry_length,NumResponses num_responses,PeriodLength max_delay,PeriodLength min_delay)412 void neighbor::InquiryModule::StartLimitedPeriodicInquiry(InquiryLength inquiry_length, NumResponses num_responses,
413 PeriodLength max_delay, PeriodLength min_delay) {
414 GetHandler()->Post(common::BindOnce(&neighbor::InquiryModule::impl::StartPeriodicInquiry,
415 common::Unretained(pimpl_.get()), true, inquiry_length, num_responses, max_delay,
416 min_delay));
417 }
418
StopPeriodicInquiry()419 void neighbor::InquiryModule::StopPeriodicInquiry() {
420 GetHandler()->Post(
421 common::BindOnce(&neighbor::InquiryModule::impl::StopPeriodicInquiry, common::Unretained(pimpl_.get())));
422 }
423
SetScanActivity(ScanParameters params)424 void neighbor::InquiryModule::SetScanActivity(ScanParameters params) {
425 GetHandler()->Post(
426 common::BindOnce(&neighbor::InquiryModule::impl::SetScanActivity, common::Unretained(pimpl_.get()), params));
427 }
428
SetInterlacedScan()429 void neighbor::InquiryModule::SetInterlacedScan() {
430 GetHandler()->Post(common::BindOnce(&neighbor::InquiryModule::impl::SetScanType, common::Unretained(pimpl_.get()),
431 hci::InquiryScanType::INTERLACED));
432 }
433
SetStandardScan()434 void neighbor::InquiryModule::SetStandardScan() {
435 GetHandler()->Post(common::BindOnce(&neighbor::InquiryModule::impl::SetScanType, common::Unretained(pimpl_.get()),
436 hci::InquiryScanType::STANDARD));
437 }
438
SetStandardInquiryResultMode()439 void neighbor::InquiryModule::SetStandardInquiryResultMode() {
440 GetHandler()->Post(common::BindOnce(&neighbor::InquiryModule::impl::SetInquiryMode, common::Unretained(pimpl_.get()),
441 hci::InquiryMode::STANDARD));
442 }
443
SetInquiryWithRssiResultMode()444 void neighbor::InquiryModule::SetInquiryWithRssiResultMode() {
445 GetHandler()->Post(common::BindOnce(&neighbor::InquiryModule::impl::SetInquiryMode, common::Unretained(pimpl_.get()),
446 hci::InquiryMode::RSSI));
447 }
448
SetExtendedInquiryResultMode()449 void neighbor::InquiryModule::SetExtendedInquiryResultMode() {
450 GetHandler()->Post(common::BindOnce(&neighbor::InquiryModule::impl::SetInquiryMode, common::Unretained(pimpl_.get()),
451 hci::InquiryMode::RSSI_OR_EXTENDED));
452 }
453
454 /**
455 * Module methods here
456 */
ListDependencies(ModuleList * list)457 void neighbor::InquiryModule::ListDependencies(ModuleList* list) {
458 list->add<hci::HciLayer>();
459 }
460
Start()461 void neighbor::InquiryModule::Start() {
462 pimpl_->Start();
463 }
464
Stop()465 void neighbor::InquiryModule::Stop() {
466 pimpl_->Stop();
467 }
468
469 } // namespace neighbor
470 } // namespace bluetooth
471