blob: 3514cafb7a39e6e5a3d1bc00937023ae79e7e6a6 [file] [log] [blame]
/*
* Copyright 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "bt_gd_neigh"
#include <memory>
#include "common/bind.h"
#include "hci/hci_layer.h"
#include "hci/hci_packets.h"
#include "module.h"
#include "neighbor/discoverability.h"
#include "neighbor/scan.h"
#include "os/handler.h"
#include "os/log.h"
namespace bluetooth {
namespace neighbor {
static constexpr uint8_t kGeneralInquiryAccessCode = 0x33;
static constexpr uint8_t kLimitedInquiryAccessCode = 0x00;
struct DiscoverabilityModule::impl {
void StartDiscoverability(std::vector<hci::Lap>& laps);
void StopDiscoverability();
bool IsGeneralDiscoverabilityEnabled() const;
bool IsLimitedDiscoverabilityEnabled() const;
void Start();
impl(DiscoverabilityModule& discoverability_module);
private:
uint8_t num_supported_iac_;
std::vector<hci::Lap> laps_;
void OnCommandComplete(hci::CommandCompleteView status);
hci::HciLayer* hci_layer_;
neighbor::ScanModule* scan_module_;
os::Handler* handler_;
DiscoverabilityModule& module_;
void Dump() const;
};
const ModuleFactory neighbor::DiscoverabilityModule::Factory =
ModuleFactory([]() { return new neighbor::DiscoverabilityModule(); });
neighbor::DiscoverabilityModule::impl::impl(neighbor::DiscoverabilityModule& module) : module_(module) {}
void neighbor::DiscoverabilityModule::impl::OnCommandComplete(hci::CommandCompleteView status) {
switch (status.GetCommandOpCode()) {
case hci::OpCode::READ_CURRENT_IAC_LAP: {
auto packet = hci::ReadCurrentIacLapCompleteView::Create(status);
ASSERT(packet.IsValid());
ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
laps_ = packet.GetLapsToRead();
} break;
case hci::OpCode::WRITE_CURRENT_IAC_LAP: {
auto packet = hci::WriteCurrentIacLapCompleteView::Create(status);
ASSERT(packet.IsValid());
ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
} break;
case hci::OpCode::READ_NUMBER_OF_SUPPORTED_IAC: {
auto packet = hci::ReadNumberOfSupportedIacCompleteView::Create(status);
ASSERT(packet.IsValid());
ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
num_supported_iac_ = packet.GetNumSupportIac();
} break;
default:
LOG_WARN("Unhandled command:%s", hci::OpCodeText(status.GetCommandOpCode()).c_str());
break;
}
}
void neighbor::DiscoverabilityModule::impl::StartDiscoverability(std::vector<hci::Lap>& laps) {
ASSERT(laps.size() <= num_supported_iac_);
hci_layer_->EnqueueCommand(hci::WriteCurrentIacLapBuilder::Create(laps),
common::BindOnce(&impl::OnCommandComplete, common::Unretained(this)), handler_);
hci_layer_->EnqueueCommand(hci::ReadCurrentIacLapBuilder::Create(),
common::BindOnce(&impl::OnCommandComplete, common::Unretained(this)), handler_);
scan_module_->SetInquiryScan();
}
void neighbor::DiscoverabilityModule::impl::StopDiscoverability() {
scan_module_->ClearInquiryScan();
}
bool neighbor::DiscoverabilityModule::impl::IsGeneralDiscoverabilityEnabled() const {
return scan_module_->IsInquiryEnabled() && laps_.size() == 1;
}
bool neighbor::DiscoverabilityModule::impl::IsLimitedDiscoverabilityEnabled() const {
return scan_module_->IsInquiryEnabled() && laps_.size() == 2;
}
void neighbor::DiscoverabilityModule::impl::Start() {
hci_layer_ = module_.GetDependency<hci::HciLayer>();
scan_module_ = module_.GetDependency<neighbor::ScanModule>();
handler_ = module_.GetHandler();
hci_layer_->EnqueueCommand(hci::ReadCurrentIacLapBuilder::Create(),
common::BindOnce(&impl::OnCommandComplete, common::Unretained(this)), handler_);
hci_layer_->EnqueueCommand(hci::ReadNumberOfSupportedIacBuilder::Create(),
common::BindOnce(&impl::OnCommandComplete, common::Unretained(this)), handler_);
LOG_DEBUG("Started discoverability module");
}
void neighbor::DiscoverabilityModule::impl::Dump() const {
LOG_DEBUG("Number of supported iacs:%hhd", num_supported_iac_);
LOG_DEBUG("Number of current iacs:%zd", laps_.size());
for (auto it : laps_) {
LOG_DEBUG(" discoverability lap:%x", it.lap_);
}
}
neighbor::DiscoverabilityModule::DiscoverabilityModule() : pimpl_(std::make_unique<impl>(*this)) {}
neighbor::DiscoverabilityModule::~DiscoverabilityModule() {
pimpl_.reset();
}
void neighbor::DiscoverabilityModule::StartGeneralDiscoverability() {
std::vector<hci::Lap> laps;
{
hci::Lap lap;
lap.lap_ = kGeneralInquiryAccessCode;
laps.push_back(lap);
}
pimpl_->StartDiscoverability(laps);
}
void neighbor::DiscoverabilityModule::StartLimitedDiscoverability() {
std::vector<hci::Lap> laps;
{
hci::Lap lap;
lap.lap_ = kGeneralInquiryAccessCode;
laps.push_back(lap);
}
{
hci::Lap lap;
lap.lap_ = kLimitedInquiryAccessCode;
laps.push_back(lap);
}
pimpl_->StartDiscoverability(laps);
}
void neighbor::DiscoverabilityModule::StopDiscoverability() {
pimpl_->StopDiscoverability();
}
bool neighbor::DiscoverabilityModule::IsGeneralDiscoverabilityEnabled() const {
return pimpl_->IsGeneralDiscoverabilityEnabled();
}
bool neighbor::DiscoverabilityModule::IsLimitedDiscoverabilityEnabled() const {
return pimpl_->IsLimitedDiscoverabilityEnabled();
}
/**
* Module stuff
*/
void neighbor::DiscoverabilityModule::ListDependencies(ModuleList* list) {
list->add<hci::HciLayer>();
list->add<neighbor::ScanModule>();
}
void neighbor::DiscoverabilityModule::Start() {
pimpl_->Start();
}
void neighbor::DiscoverabilityModule::Stop() {}
} // namespace neighbor
} // namespace bluetooth