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 92 const ModuleFactory neighbor::InquiryModule::Factory = ModuleFactory([]() { return new neighbor::InquiryModule(); }); 93 94 neighbor::InquiryModule::impl::impl(neighbor::InquiryModule& module) : module_(module) {} 95 96 void neighbor::InquiryModule::impl::OnCommandCompleteSync(hci::CommandCompleteView view) { 97 OnCommandComplete(view); 98 ASSERT(command_sync_ != nullptr); 99 command_sync_->set_value(); 100 } 101 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 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 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 */ 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 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 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 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 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 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 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 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 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 326 bool neighbor::InquiryModule::impl::IsInquiryActive() const { 327 return active_general_one_shot_ || active_limited_one_shot_ || active_limited_periodic_ || active_general_periodic_; 328 } 329 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 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 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 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 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 368 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 */ 376 neighbor::InquiryModule::InquiryModule() : pimpl_(std::make_unique<impl>(*this)) {} 377 378 neighbor::InquiryModule::~InquiryModule() { 379 pimpl_.reset(); 380 } 381 382 void neighbor::InquiryModule::RegisterCallbacks(InquiryCallbacks callbacks) { 383 pimpl_->RegisterCallbacks(callbacks); 384 } 385 386 void neighbor::InquiryModule::UnregisterCallbacks() { 387 pimpl_->UnregisterCallbacks(); 388 } 389 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 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 400 void neighbor::InquiryModule::StopInquiry() { 401 GetHandler()->Post( 402 common::BindOnce(&neighbor::InquiryModule::impl::StopOneShotInquiry, common::Unretained(pimpl_.get()))); 403 } 404 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 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 419 void neighbor::InquiryModule::StopPeriodicInquiry() { 420 GetHandler()->Post( 421 common::BindOnce(&neighbor::InquiryModule::impl::StopPeriodicInquiry, common::Unretained(pimpl_.get()))); 422 } 423 424 void neighbor::InquiryModule::SetScanActivity(ScanParameters params) { 425 GetHandler()->Post( 426 common::BindOnce(&neighbor::InquiryModule::impl::SetScanActivity, common::Unretained(pimpl_.get()), params)); 427 } 428 429 void neighbor::InquiryModule::SetInterlacedScan() { 430 GetHandler()->Post(common::BindOnce(&neighbor::InquiryModule::impl::SetScanType, common::Unretained(pimpl_.get()), 431 hci::InquiryScanType::INTERLACED)); 432 } 433 434 void neighbor::InquiryModule::SetStandardScan() { 435 GetHandler()->Post(common::BindOnce(&neighbor::InquiryModule::impl::SetScanType, common::Unretained(pimpl_.get()), 436 hci::InquiryScanType::STANDARD)); 437 } 438 439 void neighbor::InquiryModule::SetStandardInquiryResultMode() { 440 GetHandler()->Post(common::BindOnce(&neighbor::InquiryModule::impl::SetInquiryMode, common::Unretained(pimpl_.get()), 441 hci::InquiryMode::STANDARD)); 442 } 443 444 void neighbor::InquiryModule::SetInquiryWithRssiResultMode() { 445 GetHandler()->Post(common::BindOnce(&neighbor::InquiryModule::impl::SetInquiryMode, common::Unretained(pimpl_.get()), 446 hci::InquiryMode::RSSI)); 447 } 448 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 */ 457 void neighbor::InquiryModule::ListDependencies(ModuleList* list) { 458 list->add<hci::HciLayer>(); 459 } 460 461 void neighbor::InquiryModule::Start() { 462 pimpl_->Start(); 463 } 464 465 void neighbor::InquiryModule::Stop() { 466 pimpl_->Stop(); 467 } 468 469 } // namespace neighbor 470 } // namespace bluetooth 471