aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharlie Boutier <charliebout@google.com>2021-10-30 08:47:02 +0000
committerCharlie Boutier <charliebout@google.com>2021-10-30 10:04:22 +0000
commit478531d15ea1c4a8a3b50647221538e2074fd0dd (patch)
tree7463b2849a89bb9a0e56da9eef1489eb3d672230
parent2e4202b9f163798e2b85c177e39853b80388568d (diff)
downloadmmi2grpc-478531d15ea1c4a8a3b50647221538e2074fd0dd.tar.gz
a2dp: Delete GD facade. Add a2dp and host facade. Add a2dp mmi interact.
Change-Id: Ic2c3b5ea75cfd6562728357e115de33f5a4f562c
-rw-r--r--.gitignore5
-rw-r--r--blueberry/__init__.py (renamed from facade/__init__.py)0
-rw-r--r--interact/__init__.py18
-rw-r--r--interact/a2dp.py51
-rw-r--r--interact/l2cap.py48
-rw-r--r--proto/blueberry/a2dp.proto78
-rw-r--r--proto/blueberry/host.proto43
-rw-r--r--proto/facade/common.proto37
-rw-r--r--proto/facade/l2cap.proto129
-rw-r--r--proto/facade/neighbor.proto61
-rw-r--r--proto/facade/rootservice.proto32
-rwxr-xr-xprotoc-gen-custom_grpc9
-rwxr-xr-xsetup.py6
13 files changed, 197 insertions, 320 deletions
diff --git a/.gitignore b/.gitignore
index 3b6e253..f781d3d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
virtualenv
out/
__pycache__
-facade/*
-!facade/__init__.py
+blueberry/*
+!blueberry/__init__.py
+.eggs/ \ No newline at end of file
diff --git a/facade/__init__.py b/blueberry/__init__.py
index e69de29..e69de29 100644
--- a/facade/__init__.py
+++ b/blueberry/__init__.py
diff --git a/interact/__init__.py b/interact/__init__.py
index 0f08de1..faa92b2 100644
--- a/interact/__init__.py
+++ b/interact/__init__.py
@@ -1,9 +1,19 @@
import grpc
-from . import l2cap
+from . import a2dp
+
+from blueberry.host_grpc import Host
GRPC_PORT = 8999
-def run(profile: str, interaction_id: str, pts_addr: bytes):
+def run(profile: str, interaction_id: str, test: str, pts_addr: bytes):
+ channel = grpc.insecure_channel(f'localhost:{GRPC_PORT}')
+ print(f'{profile} mmi: {interaction_id}')
+ if profile == "A2DP":
+ a2dp.interact(channel, interaction_id, test, pts_addr)
+ channel.close()
+
+def read_local_address() -> bytes:
channel = grpc.insecure_channel(f'localhost:{GRPC_PORT}')
- if profile == "L2CAP":
- l2cap.interact(channel, interaction_id, pts_addr)
+ bluetooth_address = Host(channel).ReadLocalAddress(wait_for_ready=True)
+ channel.close()
+ return bluetooth_address.address
diff --git a/interact/a2dp.py b/interact/a2dp.py
new file mode 100644
index 0000000..66d46de
--- /dev/null
+++ b/interact/a2dp.py
@@ -0,0 +1,51 @@
+from grpc import Channel
+
+from blueberry.a2dp_grpc import A2DP
+from blueberry.host_grpc import Host
+
+from blueberry.a2dp_pb2 import Sink, Source
+from blueberry.host_pb2 import Connection
+
+_connection: Connection = None;
+_sink: Sink = None;
+_source: Source = None;
+
+def interact(channel: Channel, interaction_id: str, test: str, pts_addr: bytes):
+ global _connection, _sink, _source;
+ a2dp = A2DP(channel)
+ host = Host(channel)
+ if interaction_id == "TSC_AVDTP_mmi_iut_accept_connect":
+ host.SetConnectable(connectable=True)
+ elif interaction_id == "TSC_AVDTP_mmi_iut_initiate_start":
+ _connection = host.Connect(address=pts_addr).connection
+ if "SNK" in test:
+ _sink = a2dp.OpenSink(connection=_connection).sink
+ elif interaction_id == "TSC_AVDTP_mmi_iut_initiate_out_of_range":
+ if not _connection:
+ _connection = Connection(cookie=pts_addr)
+ host.Disconnect(connection=_connection)
+ _connection = None
+ _sink = None
+ _source = None
+ elif interaction_id == "TSC_AVDTP_mmi_iut_accept_discover":
+ pass
+ elif interaction_id == "TSC_AVDTP_mmi_iut_initiate_set_configuration":
+ _connection = host.Connect(address=pts_addr).connection
+ if "SRC" in test:
+ _source = a2dp.OpenSource(connection=_connection).source
+ elif interaction_id == "TSC_AVDTP_mmi_iut_accept_close_stream":
+ pass
+ elif interaction_id == "TSC_AVDTP_mmi_iut_accept_get_capabilities":
+ pass
+ elif interaction_id == "TSC_AVDTP_mmi_iut_accept_set_configuration":
+ pass
+ elif interaction_id == "TSC_AVDTP_mmi_iut_accept_open_stream":
+ pass
+ elif interaction_id == "TSC_AVDTP_mmi_iut_accept_start":
+ pass
+ elif interaction_id == "TSC_AVDTP_mmi_iut_confirm_streaming":
+ pass
+ elif interaction_id == "TSC_AVDTP_mmi_iut_accept_reconnect":
+ pass
+ else:
+ print(f'MMI NOT IMPLEMENTED: {interaction_id}') \ No newline at end of file
diff --git a/interact/l2cap.py b/interact/l2cap.py
deleted file mode 100644
index 4ee8e7d..0000000
--- a/interact/l2cap.py
+++ /dev/null
@@ -1,48 +0,0 @@
-import os
-
-from grpc import Channel
-
-from facade import l2cap_grpc, neighbor_grpc
-from facade.common_pb2 import BluetoothAddress
-from facade.l2cap_pb2 import RetransmissionFlowControlMode
-
-PSM = 1 # TODO: Add it to either utils.py or config file
-
-def interact(channel: Channel, interaction_id: str, pts_addr: bytes):
- print(f'mmi_id: {interaction_id}')
- addr = BluetoothAddress(address=pts_addr)
- l2cap = l2cap_grpc.L2capClassicModuleFacade(channel)
- neighbor = neighbor_grpc.NeighborFacade(channel)
- if interaction_id == "MMI_TESTER_ENABLE_CONNECTION":
- neighbor.EnablePageScan(enabled=True)
- l2cap.SetDynamicChannel(
- psm=PSM,
- enable=True,
- retransmission_mode=RetransmissionFlowControlMode.BASIC
- )
- if interaction_id == "MMI_IUT_SEND_CONFIG_REQ":
- pass
- if interaction_id == "MMI_IUT_SEND_L2CAP_DATA":
- payload = b'\x00' + os.urandom(40) + b'\x00'
- l2cap.SendDynamicChannelPacket(
- remote=addr,
- psm=PSM,
- payload=payload
- )
- if interaction_id == "MMI_IUT_INITIATE_ACL_CONNECTION":
- l2cap.SetDynamicChannel(
- psm=PSM,
- enable=True,
- retransmission_mode=RetransmissionFlowControlMode.BASIC
- )
- l2cap.OpenChannel(
- remote=addr,
- psm=PSM,
- mode=RetransmissionFlowControlMode.BASIC
- )
- if interaction_id == ("MMI_IUT_DISABLE_CONNECTION" or "MMI_IUT_SEND_DISCONNECT_RSP"):
- l2cap.CloseChannel(psm=PSM)
- if interaction_id == "MMI_IUT_SEND_ACL_DISCONNECTON":
- pass
- if interaction_id == "MMI_IUT_SEND_CONFIG_RSP":
- pass
diff --git a/proto/blueberry/a2dp.proto b/proto/blueberry/a2dp.proto
new file mode 100644
index 0000000..803ab0a
--- /dev/null
+++ b/proto/blueberry/a2dp.proto
@@ -0,0 +1,78 @@
+syntax = "proto3";
+
+package blueberry;
+
+import "blueberry/host.proto";
+
+service A2DP {
+ rpc OpenSource(OpenSourceRequest) returns (OpenSourceResponse);
+ rpc OpenSink(OpenSinkRequest) returns (OpenSinkResponse);
+ rpc Start(StartRequest) returns (StartResponse);
+ rpc Suspend(SuspendRequest) returns (SuspendResponse);
+ rpc Close(CloseRequest) returns (CloseResponse);
+ rpc Abort(AbortRequest) returns (AbortResponse);
+}
+
+message Source {
+ bytes cookie = 1;
+}
+
+message Sink {
+ bytes cookie = 1;
+}
+
+message OpenSourceRequest {
+ Connection connection = 1;
+}
+
+message OpenSourceResponse {
+ oneof response {
+ Source source = 1;
+ }
+}
+
+message OpenSinkRequest {
+ Connection connection = 1;
+}
+
+message OpenSinkResponse {
+ oneof response {
+ Sink sink = 1;
+ }
+}
+
+message StartRequest {
+ oneof response {
+ Sink sink = 1;
+ Source source = 2;
+ }
+}
+
+message StartResponse {}
+
+message SuspendRequest {
+ oneof response {
+ Sink sink = 1;
+ Source source = 2;
+ }
+}
+
+message SuspendResponse {}
+
+message CloseRequest {
+ oneof response {
+ Sink sink = 1;
+ Source source = 2;
+ }
+}
+
+message CloseResponse {}
+
+message AbortRequest {
+ oneof response {
+ Sink sink = 1;
+ Source source = 2;
+ }
+}
+
+message AbortResponse {} \ No newline at end of file
diff --git a/proto/blueberry/host.proto b/proto/blueberry/host.proto
new file mode 100644
index 0000000..85697e5
--- /dev/null
+++ b/proto/blueberry/host.proto
@@ -0,0 +1,43 @@
+syntax = "proto3";
+
+package blueberry;
+
+import "google/protobuf/empty.proto";
+
+service Host {
+ rpc Reset(google.protobuf.Empty) returns (google.protobuf.Empty);
+ rpc Connect(ConnectRequest) returns (ConnectResponse);
+ rpc Disconnect(DisconnectRequest) returns (DisconnectResponse);
+ rpc ReadLocalAddress(google.protobuf.Empty) returns (ReadLocalAddressResponse);
+ rpc SetConnectable(SetConnectableRequest) returns (SetConnectableResponse);
+}
+
+message Connection {
+ bytes cookie = 1;
+}
+
+message ConnectRequest {
+ bytes address = 1;
+}
+
+message ConnectResponse {
+ oneof response {
+ Connection connection = 1;
+ }
+}
+
+message DisconnectRequest {
+ Connection connection = 1;
+}
+
+message DisconnectResponse {}
+
+message ReadLocalAddressResponse {
+ bytes address = 1;
+}
+
+message SetConnectableRequest {
+ bool connectable = 1;
+}
+
+message SetConnectableResponse {} \ No newline at end of file
diff --git a/proto/facade/common.proto b/proto/facade/common.proto
deleted file mode 100644
index 222caca..0000000
--- a/proto/facade/common.proto
+++ /dev/null
@@ -1,37 +0,0 @@
-syntax = "proto3";
-
-package bluetooth.facade;
-
-message Empty {}
-
-message Data {
- bytes payload = 1;
-}
-
-message BluetoothAddress {
- bytes address = 1;
-}
-
-enum BluetoothAddressTypeEnum {
- PUBLIC_DEVICE_ADDRESS = 0x0;
- RANDOM_DEVICE_ADDRESS = 0x1;
- PUBLIC_IDENTITY_ADDRESS = 0x2;
- RANDOM_IDENTITY_ADDRESS = 0x3;
-}
-
-enum BluetoothOwnAddressTypeEnum {
- USE_PUBLIC_DEVICE_ADDRESS = 0x0;
- USE_RANDOM_DEVICE_ADDRESS = 0x1;
- RESOLVABLE_OR_PUBLIC_ADDRESS = 0x2;
- RESOLVABLE_OR_RANDOM_ADDRESS = 0x3;
-}
-
-message BluetoothAddressWithType {
- BluetoothAddress address = 1;
- BluetoothAddressTypeEnum type = 2;
-}
-
-enum BluetoothPeerAddressTypeEnum {
- PUBLIC_DEVICE_OR_IDENTITY_ADDRESS = 0x0;
- RANDOM_DEVICE_OR_IDENTITY_ADDRESS = 0x1;
-}
diff --git a/proto/facade/l2cap.proto b/proto/facade/l2cap.proto
deleted file mode 100644
index 7951ec4..0000000
--- a/proto/facade/l2cap.proto
+++ /dev/null
@@ -1,129 +0,0 @@
-syntax = "proto3";
-
-package bluetooth.l2cap.classic;
-
-import "facade/common.proto";
-
-service L2capClassicModuleFacade {
- rpc FetchConnectionComplete(facade.Empty) returns (stream ConnectionCompleteEvent) {
- // Testing Android Bluetooth stack only. Optional for other stack.
- }
- rpc FetchConnectionClose(facade.Empty) returns (stream ConnectionCloseEvent) {
- // Testing Android Bluetooth stack only. Optional for other stack.
- }
- rpc OpenChannel(OpenChannelRequest) returns (facade.Empty) {}
- rpc CloseChannel(CloseChannelRequest) returns (facade.Empty) {}
- rpc FetchL2capData(facade.Empty) returns (stream L2capPacket) {}
- rpc SetDynamicChannel(SetEnableDynamicChannelRequest) returns (facade.Empty) {}
- rpc SendDynamicChannelPacket(DynamicChannelPacket) returns (facade.Empty) {}
- rpc SetTrafficPaused(SetTrafficPausedRequest) returns (facade.Empty) {}
- rpc GetChannelQueueDepth(facade.Empty) returns (GetChannelQueueDepthResponse) {
- // Get the buffer size of channel queue end for L2CAP user (how many packets we can buffer
- // before L2CAP user dequeues.
- }
- rpc InitiateConnectionForSecurity(facade.BluetoothAddress) returns (facade.Empty) {}
- rpc FetchSecurityConnectionEvents(facade.Empty) returns (stream LinkSecurityInterfaceCallbackEvent) {}
- rpc SecurityLinkEnsureAuthenticated(facade.BluetoothAddress) returns (facade.Empty) {}
- rpc SecurityLinkHold(facade.BluetoothAddress) returns (facade.Empty) {}
- rpc SecurityLinkDisconnect(facade.BluetoothAddress) returns (facade.Empty) {}
- rpc SecurityLinkRelease(facade.BluetoothAddress) returns (facade.Empty) {}
-}
-
-enum LinkSecurityInterfaceCallbackEventType {
- ON_CONNECTED = 0;
- ON_DISCONNECTED = 1;
- ON_AUTHENTICATION_COMPLETE = 2;
- ON_ENCRYPTION_CHANGE = 3;
- ON_READ_REMOTE_VERSION_INFO = 4;
- ON_READ_REMOTE_EXTENDED_FEATURES = 5;
-}
-
-message LinkSecurityInterfaceCallbackEvent {
- facade.BluetoothAddress address = 1;
- LinkSecurityInterfaceCallbackEventType event_type = 2;
-}
-
-message RegisterChannelRequest {
- uint32 channel = 1;
-}
-
-message ConnectionCompleteEvent {
- facade.BluetoothAddress remote = 1;
-}
-
-message ConnectionCloseEvent {
- facade.BluetoothAddress remote = 1;
- uint32 reason = 2;
-}
-
-enum RetransmissionFlowControlMode {
- BASIC = 0;
- ERTM = 1;
- ERTM_OPTIONAL = 2;
-}
-
-message OpenChannelRequest {
- facade.BluetoothAddress remote = 1;
- uint32 psm = 2;
- RetransmissionFlowControlMode mode = 3;
-}
-
-message CloseChannelRequest {
- uint32 psm = 1;
-}
-
-enum ChannelSignalEventType {
- OPEN = 0;
- CLOSE = 1;
- CONFIGURE = 2;
-}
-
-message ChannelSignalEvent {
- uint32 cid = 1;
- ChannelSignalEventType type = 2;
-}
-
-enum SendL2capPacketResultType {
- OK = 0;
- BAD_CID = 1;
-}
-
-message SendL2capPacketResult {
- SendL2capPacketResultType result_type = 1;
-}
-
-message L2capPacket {
- oneof channel_type {
- uint32 psm = 1;
- uint32 fixed_cid = 2;
- }
- bytes payload = 3;
-}
-
-message SetEnableDynamicChannelRequest {
- uint32 psm = 1;
- bool enable = 2;
- RetransmissionFlowControlMode retransmission_mode = 3;
-}
-
-message DynamicChannelPacket {
- facade.BluetoothAddress remote = 1;
- uint32 psm = 2;
- bytes payload = 3;
-}
-
-message SetTrafficPausedRequest {
- bool paused = 1;
- uint32 psm = 2;
-}
-
-message GetChannelQueueDepthResponse {
- uint32 size = 1;
-}
-
-enum ClassicSecurityPolicy {
- ENCRYPTED_TRANSPORT = 0;
- AUTHENTICATED_ENCRYPTED_TRANSPORT = 1;
- BEST = 2;
- _SDP_ONLY_NO_SECURITY_WHATSOEVER_PLAINTEXT_TRANSPORT_OK = 3;
-}
diff --git a/proto/facade/neighbor.proto b/proto/facade/neighbor.proto
deleted file mode 100644
index 03defe1..0000000
--- a/proto/facade/neighbor.proto
+++ /dev/null
@@ -1,61 +0,0 @@
-syntax = "proto3";
-
-package bluetooth.neighbor;
-
-import "facade/common.proto";
-
-service NeighborFacade {
- rpc SetConnectability(EnableMsg) returns (facade.Empty) {}
- rpc SetDiscoverability(DiscoverabilitiyMsg) returns (facade.Empty) {}
- rpc SetInquiryMode(InquiryMsg) returns (stream InquiryResultMsg) {
- // Sets inquiry mode and fetches inquiry result HCI packet
- }
- rpc ReadRemoteName(RemoteNameRequestMsg) returns (facade.Empty) {}
- rpc GetRemoteNameEvents(facade.Empty) returns (stream RemoteNameResponseMsg) {}
- // TODO: Should we use a blocking call for ReadRemoteName instead? (Note: blocking model may not work for GD stack)
- rpc EnableInquiryScan(EnableMsg) returns (facade.Empty) {}
- rpc EnablePageScan(EnableMsg) returns (facade.Empty) {}
-}
-
-message EnableMsg {
- bool enabled = 1;
-}
-
-enum DiscoverabilityMode {
- OFF = 0;
- LIMITED = 1;
- GENERAL = 2;
-}
-
-message DiscoverabilitiyMsg {
- DiscoverabilityMode mode = 1;
-}
-
-enum ResultMode {
- STANDARD = 0;
- RSSI = 1;
- EXTENDED = 2;
-}
-
-message InquiryMsg {
- DiscoverabilityMode inquiry_mode = 1;
- ResultMode result_mode = 2;
- uint32 length_1_28s = 3;
- uint32 max_results = 4; // 0 is unlimited
-}
-
-message InquiryResultMsg {
- bytes packet = 1;
-}
-
-message RemoteNameRequestMsg {
- bytes address = 1;
- uint32 page_scan_repetition_mode = 2; // r0, r1, r2
- uint32 clock_offset = 3;
-}
-
-message RemoteNameResponseMsg {
- uint32 status = 1;
- bytes address = 2;
- bytes name = 3;
-}
diff --git a/proto/facade/rootservice.proto b/proto/facade/rootservice.proto
deleted file mode 100644
index 63ec41a..0000000
--- a/proto/facade/rootservice.proto
+++ /dev/null
@@ -1,32 +0,0 @@
-syntax = "proto3";
-package bluetooth.facade;
-
-import "facade/common.proto";
-
-service RootFacade {
- rpc StartStack(StartStackRequest) returns (StartStackResponse) {}
- rpc StopStack(StopStackRequest) returns (StopStackResponse) {}
-}
-
-enum BluetoothModule {
- HAL = 0;
- HCI = 1;
- HCI_INTERFACES = 2;
- L2CAP = 3;
- SECURITY = 4;
- SHIM = 5;
-}
-
-message StartStackRequest {
- BluetoothModule module_under_test = 1;
-}
-
-message StartStackResponse {}
-
-message StopStackRequest {}
-
-message StopStackResponse {}
-
-service ReadOnlyProperty {
- rpc ReadLocalAddress(Empty) returns (BluetoothAddress) {}
-}
diff --git a/protoc-gen-custom_grpc b/protoc-gen-custom_grpc
index a45dc19..3a0c8be 100755
--- a/protoc-gen-custom_grpc
+++ b/protoc-gen-custom_grpc
@@ -10,11 +10,14 @@ def eprint(*args, **kwargs):
request = CodeGeneratorRequest.FromString(sys.stdin.buffer.read())
+def has_type(proto_file, type_name):
+ return any(filter(lambda x: x.name == type_name, proto_file.message_type))
def import_type(imports, type):
+ # eprint(f'type: {type} request: {request.proto_file}')
package = type[1:type.rindex('.')]
type_name = type[type.rindex('.')+1:]
- file = next(filter(lambda x: x.package == package, request.proto_file))
+ file = next(filter(lambda x: x.package == package and has_type(x, type_name), request.proto_file))
python_path = file.name.replace('.proto', '').replace('/', '.')
as_name = python_path.replace('.', '_dot_') + '__pb2'
module_path = python_path[:python_path.rindex('.')]
@@ -34,12 +37,12 @@ def generate_method(imports, file, service, method):
raise Error("TODO: stream as input type")
return (
- f'def {method.name}(self, **kwargs):\n'
+ f'def {method.name}(self, wait_for_ready=None, **kwargs):\n'
f' return self.channel.{input_mode}_{output_mode}(\n'
f" '/{file.package}.{service.name}/{method.name}',\n"
f' request_serializer={input_type}.SerializeToString,\n'
f' response_deserializer={output_type}.FromString\n'
- f' )({input_type}(**kwargs))'
+ f' )({input_type}(**kwargs), wait_for_ready=wait_for_ready)'
).split('\n')
diff --git a/setup.py b/setup.py
index 20fd953..1af2b9e 100755
--- a/setup.py
+++ b/setup.py
@@ -27,10 +27,8 @@ class BuildGrpc(Command):
'-I=proto',
'--python_out=.',
'--custom_grpc_out=.',
- 'facade/l2cap.proto',
- 'facade/neighbor.proto',
- 'facade/common.proto',
- 'facade/rootservice.proto',
+ 'blueberry/host.proto',
+ 'blueberry/a2dp.proto'
])