/* * 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 #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(request->mode())); } return ::grpc::Status::OK; } ::grpc::Status SetInquiryMode( ::grpc::ServerContext* context, const ::bluetooth::neighbor::InquiryMsg* request, ::grpc::ServerWriter* 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(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(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(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* 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::EventPacketView 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 name) { RemoteNameResponseMsg response; response.set_status(static_cast(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 pending_events_{"InquiryResponses"}; ::bluetooth::grpc::GrpcEventQueue pending_remote_names_{"RemoteNameResponses"}; }; void NeighborFacadeModule::ListDependencies(ModuleList* list) { ::bluetooth::grpc::GrpcFacadeModule::ListDependencies(list); list->add(); list->add(); list->add(); list->add(); list->add(); list->add(); } void NeighborFacadeModule::Start() { ::bluetooth::grpc::GrpcFacadeModule::Start(); service_ = new NeighborFacadeService( GetDependency(), GetDependency(), GetDependency(), GetDependency(), GetDependency(), GetDependency(), 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