}
cc_test {
- name: "bluetooth_cert_test",
- defaults: [
- "gd_defaults",
- ],
- host_supported: true,
- srcs: [
- ":BluetoothCertCppClient_hci_hal",
- ],
- static_libs : [
- "libbluetooth_gd",
- ],
- shared_libs: [
- "libgrpc++_unsecure",
- "libprotobuf-cpp-full",
- ],
- generated_headers: [
- "BluetoothGeneratedPackets_h",
- "BluetoothCertFacadeGeneratedStub_h",
- ],
- generated_sources: [
- "BluetoothCertFacadeGeneratedStub_cc",
- ],
- sanitize: {
- address: true,
- },
-}
-
-cc_test {
name: "bluetooth_test_gd",
test_suites: ["device-tests"],
defaults: [
filegroup {
name: "BluetoothCertFacadeProto",
srcs: [
+ "facade/common.proto",
"hal/facade/api.proto",
],
}
":BluetoothCertFacadeProto",
],
out: [
+ "facade/common.grpc.pb.h",
+ "facade/common.pb.h",
"hal/facade/api.grpc.pb.h",
"hal/facade/api.pb.h",
],
":BluetoothCertFacadeProto",
],
out: [
+ "facade/common.grpc.pb.cc",
+ "facade/common.pb.cc",
"hal/facade/api.grpc.pb.cc",
"hal/facade/api.pb.cc",
],
],
cmd: "$(location aprotoc) -Isystem/bt/gd -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-python-plugin) $(in) --grpc_out=$(genDir) --python_out=$(genDir); " +
"touch $(genDir)/__init__.py; " +
+ "touch $(genDir)/facade/__init__.py; " +
"touch $(genDir)/hal/__init__.py; " +
"touch $(genDir)/hal/facade/__init__.py; ",
srcs: [
],
out: [
"__init__.py",
+ "facade/__init__.py",
+ "facade/common_pb2_grpc.py",
+ "facade/common_pb2.py",
"hal/__init__.py",
"hal/facade/__init__.py",
"hal/facade/api_pb2_grpc.py",
--- /dev/null
+syntax = "proto3";
+
+package bluetooth.facade;
+
+enum EventSubscriptionMode {
+ UNCHANGED = 0;
+ SUBSCRIBE = 1;
+ UNSUBSCRIBE = 2;
+}
+
+enum EventFetchMode {
+ NONE = 0;
+ ALL_CURRENT = 1;
+ AT_LEAST_ONE = 2;
+}
+
+message EventStreamRequest {
+ EventSubscriptionMode subscription_mode = 1;
+ EventFetchMode fetch_mode = 2;
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <grpc++/grpc++.h>
+
+#include "common/blocking_queue.h"
+#include "facade/common.pb.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace grpc {
+
+template <typename RES, typename EVENT>
+class GrpcEventStreamCallback {
+ public:
+ virtual ~GrpcEventStreamCallback() = default;
+ virtual void OnSubscribe() {}
+ virtual void OnUnsubscribe() {}
+ virtual void OnWriteResponse(RES* response, const EVENT& event) = 0;
+};
+
+template <typename RES, typename EVENT>
+class GrpcEventStream {
+ public:
+ explicit GrpcEventStream(GrpcEventStreamCallback<RES, EVENT>* callback) : callback_(callback) {}
+
+ void OnIncomingEvent(const EVENT& event) {
+ if (subscribed_) {
+ event_queue_.push(event);
+ }
+ }
+
+ ::grpc::Status HandleRequest(::grpc::ServerContext* context, const ::bluetooth::facade::EventStreamRequest* request,
+ ::grpc::ServerWriter<RES>* writer) {
+ ::bluetooth::facade::EventSubscriptionMode subscription_mode = request->subscription_mode();
+ ::bluetooth::facade::EventFetchMode fetch_mode = request->fetch_mode();
+
+ if (subscription_mode == ::bluetooth::facade::SUBSCRIBE) {
+ callback_->OnSubscribe();
+ subscribed_ = true;
+ }
+
+ if (fetch_mode == ::bluetooth::facade::AT_LEAST_ONE) {
+ RES response;
+ EVENT event = event_queue_.take();
+ callback_->OnWriteResponse(&response, event);
+ writer->Write(response);
+ }
+
+ // fetch all current remaining items and append to AT_LEAST_ONE query if present
+ if (fetch_mode == ::bluetooth::facade::ALL_CURRENT || fetch_mode == ::bluetooth::facade::AT_LEAST_ONE) {
+ while (!event_queue_.empty()) {
+ RES response;
+ EVENT event = event_queue_.take();
+ callback_->OnWriteResponse(&response, event);
+ writer->Write(response);
+ }
+ }
+
+ if (subscription_mode == ::bluetooth::facade::UNSUBSCRIBE) {
+ subscribed_ = false;
+ event_queue_.clear();
+ callback_->OnUnsubscribe();
+ }
+
+ return ::grpc::Status::OK;
+ }
+
+ private:
+ common::BlockingQueue<EVENT> event_queue_;
+ GrpcEventStreamCallback<RES, EVENT>* callback_;
+ bool subscribed_ = false;
+};
+
+} // namespace grpc
+} // namespace bluetooth
"facade/facade.cc",
],
}
-
-filegroup {
- name: "BluetoothCertCppClient_hci_hal",
- srcs: [
- "cert/simple_hal_test.cc",
- ],
-}
+++ /dev/null
-/*
- * 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 <grpc++/grpc++.h>
-#include <gtest/gtest.h>
-
-#include <chrono>
-#include <string>
-#include <thread>
-
-#include "hal/facade/api.grpc.pb.h"
-#include "hci/hci_packets.h"
-#include "os/log.h"
-
-using grpc::ClientContext;
-
-namespace bluetooth {
-namespace hal {
-namespace cert {
-
-using ::bluetooth::hal::facade::HciCmdPacket;
-using ::bluetooth::hal::facade::HciEvtPacket;
-using ::bluetooth::hal::facade::HciTransportation;
-using ::bluetooth::hal::facade::LoopbackModeSettings;
-
-class HalAdapterCertTest : public ::testing::Test {
- protected:
- void SetUp() override {
- int port = 8899;
- std::string channel = "localhost:" + std::to_string(port);
- stub_ = HciTransportation::NewStub(grpc::CreateChannel(channel, grpc::InsecureChannelCredentials()));
- }
- void TearDown() override {
- stub_.reset();
- }
-
- std::unique_ptr<HciTransportation::Stub> stub_;
-};
-
-TEST_F(HalAdapterCertTest, enable_loopback_mode) {
- ClientContext set_loopback_mode_context;
- LoopbackModeSettings settings;
- settings.set_enable(true);
- ::google::protobuf::Empty empty;
- ::grpc::Status status = stub_->SetLoopbackMode(&set_loopback_mode_context, settings, &empty);
- EXPECT_EQ(status.ok(), true);
-
- ClientContext register_hci_evt_context;
-
- auto reader = stub_->RegisterHciEvt(®ister_hci_evt_context, empty);
-
- auto packet = hci::DisconnectBuilder::Create(2, hci::DisconnectReason::PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED);
- std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
- hci::BitInserter it(*packet_bytes);
- packet->Serialize(it);
-
- std::string payload(packet_bytes->begin(), packet_bytes->end());
-
- ClientContext send_hci_cmd_context;
- HciCmdPacket cmd;
- cmd.set_payload(payload);
- status = stub_->SendHciCmd(&send_hci_cmd_context, cmd, &empty);
- EXPECT_EQ(status.ok(), true);
-
- HciEvtPacket received_packet;
- reader->Read(&received_packet);
-
- ClientContext unregister_hci_evt_context;
-
- status = stub_->UnregisterHciEvt(&unregister_hci_evt_context, empty, &empty);
- EXPECT_EQ(status.ok(), true);
-
- // EXPECT_EQ(reader->Read(&received_packet), false);
-}
-
-} // namespace cert
-} // namespace hal
-} // namespace bluetooth
from cert.gd_base_test import GdBaseTestClass
+from facade import common_pb2
from hal.facade import api_pb2
class SimpleHalTest(GdBaseTestClass):
response = self.gd_devices[0].hal.SetLoopbackMode(api_pb2.LoopbackModeSettings(enable=True))
print("Response " + str(response))
+ def test_fetch_hci_event(self):
+ response = self.gd_devices[0].hal.SetLoopbackMode(api_pb2.LoopbackModeSettings(enable=True))
+
+ request = common_pb2.EventStreamRequest(subscription_mode=common_pb2.SUBSCRIBE,
+ fetch_mode=common_pb2.NONE)
+ response = self.gd_devices[0].hal.FetchHciEvent(request)
+
+ inquiry_string = b'\x01\x04\x05\x33\x8b\x9e\x30\x01'
+ response = self.gd_devices[0].hal.SendHciCommand(api_pb2.HciCmdPacket(payload=inquiry_string))
+
+ request = common_pb2.EventStreamRequest(subscription_mode=common_pb2.UNCHANGED,
+ fetch_mode=common_pb2.AT_LEAST_ONE)
+ response = self.gd_devices[0].hal.FetchHciEvent(request)
+
+ for event in response:
+ print(event.payload)
+
+ request = common_pb2.EventStreamRequest(subscription_mode=common_pb2.UNSUBSCRIBE,
+ fetch_mode=common_pb2.NONE)
+ response = self.gd_devices[0].hal.FetchHciEvent(request)
package bluetooth.hal.facade;
import "google/protobuf/empty.proto";
+import "facade/common.proto";
// The HCI HAL transportation layer certification API surface definition
service HciTransportation {
rpc SetLoopbackMode(LoopbackModeSettings) returns (google.protobuf.Empty) {}
- rpc SendHciCmd(HciCmdPacket) returns (google.protobuf.Empty) {}
+ rpc SendHciCommand(HciCmdPacket) returns (google.protobuf.Empty) {}
rpc SendHciAcl(HciAclPacket) returns (google.protobuf.Empty) {}
rpc SendHciSco(HciScoPacket) returns (google.protobuf.Empty) {}
- rpc RegisterHciEvt(google.protobuf.Empty) returns (stream HciEvtPacket) {}
- rpc RegisterHciAcl(google.protobuf.Empty) returns (stream HciAclPacket) {}
- rpc RegisterHciSco(google.protobuf.Empty) returns (stream HciScoPacket) {}
- rpc UnregisterHciEvt(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc UnregisterHciAcl(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc UnregisterHciSco(google.protobuf.Empty) returns (google.protobuf.Empty) {}
+
+ rpc FetchHciEvent(bluetooth.facade.EventStreamRequest) returns (stream HciEvtPacket) {}
+ rpc FetchHciAcl(bluetooth.facade.EventStreamRequest) returns (stream HciAclPacket) {}
+ rpc FetchHciSco(bluetooth.facade.EventStreamRequest) returns (stream HciScoPacket) {}
}
message LoopbackModeSettings {
#include <memory>
#include <mutex>
-#include <thread>
-#include "grpc/async_grpc.h"
+#include "common/blocking_queue.h"
+#include "grpc/grpc_event_stream.h"
#include "hal/facade/api.grpc.pb.h"
#include "hal/hci_hal.h"
#include "hci/hci_packets.h"
: public HciTransportation::Service,
public ::bluetooth::hal::HciHalCallbacks {
public:
- HciTransportationService(HciHal* hal) : hal_(hal) {
- }
+ HciTransportationService(HciHal* hal)
+ : hal_(hal), hci_event_stream_(&hci_event_stream_callback_), hci_acl_stream_(&hci_acl_stream_callback_),
+ hci_sco_stream_(&hci_sco_stream_callback_) {}
::grpc::Status SetLoopbackMode(::grpc::ServerContext* context,
const ::bluetooth::hal::facade::LoopbackModeSettings* request,
return ::grpc::Status::OK;
}
- ::grpc::Status SendHciCmd(::grpc::ServerContext* context, const ::bluetooth::hal::facade::HciCmdPacket* request,
- ::google::protobuf::Empty* response) override {
+ ::grpc::Status SendHciCommand(::grpc::ServerContext* context, const ::bluetooth::hal::facade::HciCmdPacket* request,
+ ::google::protobuf::Empty* response) override {
std::string req_string = request->payload();
hal_->sendHciCommand(std::vector<uint8_t>(req_string.begin(), req_string.end()));
return ::grpc::Status::OK;
return ::grpc::Status::OK;
}
+ ::grpc::Status FetchHciEvent(::grpc::ServerContext* context, const ::bluetooth::facade::EventStreamRequest* request,
+ ::grpc::ServerWriter<HciEvtPacket>* writer) override {
+ return hci_event_stream_.HandleRequest(context, request, writer);
+ };
+
+ ::grpc::Status FetchHciAcl(::grpc::ServerContext* context, const ::bluetooth::facade::EventStreamRequest* request,
+ ::grpc::ServerWriter<HciAclPacket>* writer) override {
+ return hci_acl_stream_.HandleRequest(context, request, writer);
+ };
+
+ ::grpc::Status FetchHciSco(::grpc::ServerContext* context, const ::bluetooth::facade::EventStreamRequest* request,
+ ::grpc::ServerWriter<HciScoPacket>* writer) override {
+ return hci_sco_stream_.HandleRequest(context, request, writer);
+ };
+
void hciEventReceived(bluetooth::hal::HciPacket event) override {
- // TODO
+ std::string response_str = std::string(event.begin(), event.end());
+ hci_event_stream_.OnIncomingEvent(event);
}
void aclDataReceived(bluetooth::hal::HciPacket data) override {
- // TODO
+ hci_acl_stream_.OnIncomingEvent(data);
}
void scoDataReceived(bluetooth::hal::HciPacket data) override {
- // TODO
+ hci_sco_stream_.OnIncomingEvent(data);
}
+
private:
HciHal* hal_;
+
+ class HciEventStreamCallback : public ::bluetooth::grpc::GrpcEventStreamCallback<HciEvtPacket, HciPacket> {
+ public:
+ void OnWriteResponse(HciEvtPacket* response, const HciPacket& event) override {
+ std::string response_str = std::string(event.begin(), event.end());
+ response->set_payload(std::string(event.begin(), event.end()));
+ }
+ } hci_event_stream_callback_;
+ ::bluetooth::grpc::GrpcEventStream<HciEvtPacket, HciPacket> hci_event_stream_;
+
+ class HciAclStreamCallback : public ::bluetooth::grpc::GrpcEventStreamCallback<HciAclPacket, HciPacket> {
+ public:
+ void OnWriteResponse(HciAclPacket* response, const HciPacket& event) override {
+ response->set_payload(std::string(event.begin(), event.end()));
+ }
+ } hci_acl_stream_callback_;
+ ::bluetooth::grpc::GrpcEventStream<HciAclPacket, HciPacket> hci_acl_stream_;
+
+ class HciScoStreamCallback : public ::bluetooth::grpc::GrpcEventStreamCallback<HciScoPacket, HciPacket> {
+ public:
+ void OnWriteResponse(HciScoPacket* response, const HciPacket& event) override {
+ response->set_payload(std::string(event.begin(), event.end()));
+ }
+ } hci_sco_stream_callback_;
+ ::bluetooth::grpc::GrpcEventStream<HciScoPacket, HciPacket> hci_sco_stream_;
};
void HalFacadeModule::ListDependencies(ModuleList* list) {