blob: 31f7761b8a298bc028c6d7fda17e15186b72e208 [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.
*/
#include "neighbor/facade/facade.h"
#include <memory>
#include "common/bind.h"
#include "grpc/grpc_event_queue.h"
#include "hci/hci_packets.h"
#include "neighbor/facade/facade.grpc.pb.h"
using ::grpc::ServerAsyncResponseWriter;
using ::grpc::ServerAsyncWriter;
using ::grpc::ServerContext;
namespace bluetooth {
namespace neighbor {
namespace facade {
class NeighborFacadeService : public NeighborFacade::Service {
public:
NeighborFacadeService(
ConnectabilityModule* connectability_module,
DiscoverabilityModule* discoverability_module,
InquiryModule* inquiry_module,
NameModule* name_module,
PageModule*,
ScanModule* scan_module,
::bluetooth::os::Handler* facade_handler)
: connectability_module_(connectability_module),
discoverability_module_(discoverability_module),
inquiry_module_(inquiry_module),
name_module_(name_module),
scan_module_(scan_module),
facade_handler_(facade_handler) {}
::grpc::Status SetConnectability(
::grpc::ServerContext* context,
const ::bluetooth::neighbor::EnableMsg* request,
::google::protobuf::Empty* response) override {
if (request->enabled()) {
connectability_module_->StartConnectability();
} else {
connectability_module_->StopConnectability();
}
return ::grpc::Status::OK;
}
::grpc::Status SetDiscoverability(
::grpc::ServerContext* context,
const ::bluetooth::neighbor::DiscoverabilitiyMsg* request,
::google::protobuf::Empty* response) override {
switch (request->mode()) {
case DiscoverabilityMode::OFF:
discoverability_module_->StopDiscoverability();
break;
case DiscoverabilityMode::LIMITED:
discoverability_module_->StartLimitedDiscoverability();
break;
case DiscoverabilityMode::GENERAL:
discoverability_module_->StartGeneralDiscoverability();
break;
default:
LOG_ALWAYS_FATAL("Unknown discoverability mode %d", static_cast<int>(request->mode()));
}
return ::grpc::Status::OK;
}
::grpc::Status SetInquiryMode(
::grpc::ServerContext* context,
const ::bluetooth::neighbor::InquiryMsg* request,
::grpc::ServerWriter<InquiryResultMsg>* writer) override {
inquiry_module_->RegisterCallbacks(inquiry_callbacks_);
switch (request->result_mode()) {
case ResultMode::STANDARD:
inquiry_module_->SetStandardInquiryResultMode();
break;
case ResultMode::RSSI:
inquiry_module_->SetInquiryWithRssiResultMode();
break;
case ResultMode::EXTENDED:
inquiry_module_->SetExtendedInquiryResultMode();
break;
default:
LOG_ALWAYS_FATAL("Unknown result mode %d", static_cast<int>(request->result_mode()));
}
switch (request->inquiry_mode()) {
case DiscoverabilityMode::OFF:
inquiry_module_->StopInquiry();
break;
case DiscoverabilityMode::LIMITED:
inquiry_module_->StartLimitedInquiry(request->length_1_28s(), request->max_results());
break;
case DiscoverabilityMode::GENERAL:
inquiry_module_->StartGeneralInquiry(request->length_1_28s(), request->max_results());
break;
default:
LOG_ALWAYS_FATAL("Unknown discoverability mode %d", static_cast<int>(request->inquiry_mode()));
}
return pending_events_.RunLoop(context, writer);
}
::grpc::Status ReadRemoteName(
::grpc::ServerContext* context,
const ::bluetooth::neighbor::RemoteNameRequestMsg* request,
::google::protobuf::Empty* response) override {
hci::Address remote;
ASSERT(hci::Address::FromString(request->address(), remote));
hci::PageScanRepetitionMode mode;
switch (request->page_scan_repetition_mode()) {
case 0:
mode = hci::PageScanRepetitionMode::R0;
break;
case 1:
mode = hci::PageScanRepetitionMode::R1;
break;
case 2:
mode = hci::PageScanRepetitionMode::R2;
break;
default:
LOG_ALWAYS_FATAL("Unknown PageScanRepetition mode %d", static_cast<int>(request->page_scan_repetition_mode()));
}
name_module_->ReadRemoteNameRequest(
remote,
mode,
request->clock_offset(),
(request->clock_offset() != 0 ? hci::ClockOffsetValid::VALID : hci::ClockOffsetValid::INVALID),
common::Bind(&NeighborFacadeService::on_remote_name, common::Unretained(this)),
facade_handler_);
return ::grpc::Status::OK;
}
::grpc::Status GetRemoteNameEvents(
::grpc::ServerContext* context,
const ::google::protobuf::Empty* request,
::grpc::ServerWriter<RemoteNameResponseMsg>* writer) override {
return pending_remote_names_.RunLoop(context, writer);
}
::grpc::Status EnableInquiryScan(
::grpc::ServerContext* context,
const ::bluetooth::neighbor::EnableMsg* request,
::google::protobuf::Empty* response) override {
if (request->enabled()) {
scan_module_->SetInquiryScan();
} else {
scan_module_->ClearInquiryScan();
}
return ::grpc::Status::OK;
}
::grpc::Status EnablePageScan(
::grpc::ServerContext* context,
const ::bluetooth::neighbor::EnableMsg* request,
::google::protobuf::Empty* response) override {
if (request->enabled()) {
scan_module_->SetPageScan();
} else {
scan_module_->ClearPageScan();
}
return ::grpc::Status::OK;
}
private:
void on_incoming_inquiry_result(hci::EventView view) {
InquiryResultMsg inquiry_result_msg;
inquiry_result_msg.set_packet(std::string(view.begin(), view.end()));
pending_events_.OnIncomingEvent(std::move(inquiry_result_msg));
}
void on_incoming_inquiry_complete(hci::ErrorCode status) {
InquiryResultMsg inquiry_result_msg;
inquiry_result_msg.set_packet(hci::ErrorCodeText(status));
pending_events_.OnIncomingEvent(std::move(inquiry_result_msg));
}
InquiryCallbacks inquiry_callbacks_{
.result = [this](hci::InquiryResultView view) { on_incoming_inquiry_result(view); },
.result_with_rssi = [this](hci::InquiryResultWithRssiView view) { on_incoming_inquiry_result(view); },
.extended_result = [this](hci::ExtendedInquiryResultView view) { on_incoming_inquiry_result(view); },
.complete = [this](hci::ErrorCode status) { on_incoming_inquiry_complete(status); }};
void on_remote_name(hci::ErrorCode status, hci::Address address, std::array<uint8_t, 248> name) {
RemoteNameResponseMsg response;
response.set_status(static_cast<int>(status));
response.set_address(address.ToString());
response.set_name(name.begin(), name.size());
pending_remote_names_.OnIncomingEvent(response);
}
ConnectabilityModule* connectability_module_;
DiscoverabilityModule* discoverability_module_;
InquiryModule* inquiry_module_;
NameModule* name_module_;
ScanModule* scan_module_;
::bluetooth::os::Handler* facade_handler_;
::bluetooth::grpc::GrpcEventQueue<InquiryResultMsg> pending_events_{"InquiryResponses"};
::bluetooth::grpc::GrpcEventQueue<RemoteNameResponseMsg> pending_remote_names_{"RemoteNameResponses"};
};
void NeighborFacadeModule::ListDependencies(ModuleList* list) const {
::bluetooth::grpc::GrpcFacadeModule::ListDependencies(list);
list->add<ConnectabilityModule>();
list->add<DiscoverabilityModule>();
list->add<InquiryModule>();
list->add<NameModule>();
list->add<PageModule>();
list->add<ScanModule>();
}
void NeighborFacadeModule::Start() {
::bluetooth::grpc::GrpcFacadeModule::Start();
service_ = new NeighborFacadeService(
GetDependency<ConnectabilityModule>(),
GetDependency<DiscoverabilityModule>(),
GetDependency<InquiryModule>(),
GetDependency<NameModule>(),
GetDependency<PageModule>(),
GetDependency<ScanModule>(),
GetHandler());
}
void NeighborFacadeModule::Stop() {
delete service_;
::bluetooth::grpc::GrpcFacadeModule::Stop();
}
::grpc::Service* NeighborFacadeModule::GetService() const {
return service_;
}
const ModuleFactory NeighborFacadeModule::Factory =
::bluetooth::ModuleFactory([]() { return new NeighborFacadeModule(); });
} // namespace facade
} // namespace neighbor
} // namespace bluetooth