You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
181 lines
7.4 KiB
181 lines
7.4 KiB
#!/usr/bin/env python3
|
|
#
|
|
# Copyright 2021 - 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.
|
|
|
|
import logging
|
|
|
|
from bluetooth_packets_python3 import hci_packets
|
|
from cert.capture import Capture
|
|
from cert.captures import SecurityCaptures
|
|
from cert.closable import Closable
|
|
from cert.closable import safeClose
|
|
from cert.event_stream import EventStream, IEventStream
|
|
from cert.event_stream import FilteringEventStream
|
|
from cert.matchers import IsoMatchers
|
|
from cert.truth import assertThat
|
|
from datetime import timedelta
|
|
from facade import common_pb2 as common
|
|
from google.protobuf import empty_pb2 as empty_proto
|
|
from iso import facade_pb2 as iso_facade_pb2
|
|
|
|
|
|
class CisTestParameters():
|
|
|
|
def __init__(self, cis_id, nse, max_sdu_m_to_s, max_sdu_s_to_m, max_pdu_m_to_s, max_pdu_s_to_m, phy_m_to_s,
|
|
phy_s_to_m, bn_m_to_s, bn_s_to_m):
|
|
self.cis_id = cis_id
|
|
self.nse = nse
|
|
self.max_sdu_m_to_s = max_sdu_m_to_s
|
|
self.max_sdu_s_to_m = max_sdu_s_to_m
|
|
self.max_pdu_m_to_s = max_pdu_m_to_s
|
|
self.max_pdu_s_to_m = max_pdu_s_to_m
|
|
self.phy_m_to_s = phy_m_to_s
|
|
self.phy_s_to_m = phy_s_to_m
|
|
self.bn_m_to_s = bn_m_to_s
|
|
self.bn_s_to_m = bn_s_to_m
|
|
|
|
|
|
class PyLeIsoStream(IEventStream):
|
|
|
|
def __init__(self, device, cis_handle, iso_data_stream):
|
|
self._device = device
|
|
self._cis_handle = cis_handle
|
|
self._le_iso_data_stream = iso_data_stream
|
|
self._our_le_iso_cis_view = FilteringEventStream(
|
|
self._le_iso_data_stream, IsoMatchers.PacketPayloadWithMatchingCisHandle(self._cis_handle))
|
|
|
|
def get_event_queue(self):
|
|
return self._our_le_iso_cis_view.get_event_queue()
|
|
|
|
def send(self, payload):
|
|
self._device.iso.SendIsoPacket(iso_facade_pb2.IsoPacket(handle=self._cis_handle, payload=payload))
|
|
|
|
|
|
class PyLeIso(Closable):
|
|
"""
|
|
Abstraction for iso tasks and GRPC calls
|
|
"""
|
|
|
|
_iso_event_stream = None
|
|
|
|
def __init__(self, device):
|
|
logging.info("DUT: Init")
|
|
self._device = device
|
|
self._device.wait_channel_ready()
|
|
self._iso_event_stream = EventStream(self._device.iso.FetchIsoEvents(empty_proto.Empty()))
|
|
self._iso_data_stream = EventStream(self._device.iso.FetchIsoData(empty_proto.Empty()))
|
|
|
|
def close(self):
|
|
if self._iso_event_stream is not None:
|
|
safeClose(self._iso_event_stream)
|
|
else:
|
|
logging.info("DUT: ISO Event Stream is None!")
|
|
if self._iso_data_stream is not None:
|
|
safeClose(self._iso_data_stream)
|
|
else:
|
|
logging.info("DUT: ISO Data Stream is None!")
|
|
|
|
logging.info("DUT: close")
|
|
|
|
def le_set_cig_parameters(self, cig_id, sdu_interval_m_to_s, sdu_interval_s_to_m, peripherals_clock_accuracy,
|
|
packing, framing, max_transport_latency_m_to_s, max_transport_latency_s_to_m, cis_id,
|
|
max_sdu_m_to_s, max_sdu_s_to_m, phy_m_to_s, phy_s_to_m, rtn_m_to_s, rtn_s_to_m):
|
|
|
|
resp = self._device.iso.LeSetCigParameters(
|
|
iso_facade_pb2.LeSetCigParametersRequest(
|
|
cig_id=cig_id,
|
|
sdu_interval_m_to_s=sdu_interval_m_to_s,
|
|
sdu_interval_s_to_m=sdu_interval_s_to_m,
|
|
peripherals_clock_accuracy=peripherals_clock_accuracy,
|
|
packing=packing,
|
|
framing=framing,
|
|
max_transport_latency_m_to_s=max_transport_latency_m_to_s,
|
|
max_transport_latency_s_to_m=max_transport_latency_s_to_m,
|
|
cis_id=cis_id,
|
|
max_sdu_m_to_s=max_sdu_m_to_s,
|
|
max_sdu_s_to_m=max_sdu_s_to_m,
|
|
phy_m_to_s=phy_m_to_s,
|
|
phy_s_to_m=phy_s_to_m,
|
|
rtn_m_to_s=rtn_m_to_s,
|
|
rtn_s_to_m=rtn_s_to_m))
|
|
|
|
def le_set_cig_parameters_test(self, cig_id, sdu_interval_m_to_s, sdu_interval_s_to_m, ft_m_to_s, ft_s_to_m,
|
|
iso_interval, peripherals_clock_accuracy, packing, framing,
|
|
max_transport_latency_m_to_s, max_transport_latency_s_to_m, cis_configs):
|
|
configs = []
|
|
for cc in cis_configs:
|
|
configs.append(
|
|
iso_facade_pb2.LeSetCigParametersTestRequest.LeCisParametersTestConfig(
|
|
cis_id=cc.cis_id,
|
|
nse=cc.nse,
|
|
max_sdu_m_to_s=cc.max_sdu_m_to_s,
|
|
max_sdu_s_to_m=cc.max_sdu_s_to_m,
|
|
max_pdu_m_to_s=cc.max_pdu_m_to_s,
|
|
max_pdu_s_to_m=cc.max_pdu_s_to_m,
|
|
phy_m_to_s=cc.phy_m_to_s,
|
|
phy_s_to_m=cc.phy_s_to_m,
|
|
bn_m_to_s=cc.bn_m_to_s,
|
|
bn_s_to_m=cc.bn_s_to_m,
|
|
))
|
|
|
|
resp = self._device.iso.LeSetCigParameters(
|
|
iso_facade_pb2.LeSetCigParametersTestRequest(
|
|
cig_id=cig_id,
|
|
sdu_interval_m_to_s=sdu_interval_m_to_s,
|
|
sdu_interval_s_to_m=sdu_interval_s_to_m,
|
|
ft_m_to_s=ft_m_to_s,
|
|
ft_s_to_m=ft_s_to_m,
|
|
iso_interval=iso_interval,
|
|
peripherals_clock_accuracy=peripherals_clock_accuracy,
|
|
packing=packing,
|
|
framing=framing,
|
|
max_transport_latency_m_to_s=max_transport_latency_m_to_s,
|
|
max_transport_latency_s_to_m=max_transport_latency_s_to_m,
|
|
cis_configs=configs))
|
|
|
|
def wait_le_set_cig_parameters_complete(self):
|
|
set_cig_params_complete_capture = PyLeIso.IsoCigComplete(iso_facade_pb2.IsoMsgType.ISO_PARAMETERS_SET_COMPLETE)
|
|
|
|
assertThat(self._iso_event_stream).emits(set_cig_params_complete_capture, timeout=timedelta(seconds=5))
|
|
return set_cig_params_complete_capture.get()
|
|
|
|
@staticmethod
|
|
def IsoCigComplete(type=None):
|
|
return Capture(lambda event: True if event.message_type == type else False, PyLeIso._extract_cis_handles)
|
|
|
|
@staticmethod
|
|
def _extract_cis_handles(event):
|
|
if event is None:
|
|
return None
|
|
return event.cis_handle
|
|
|
|
def le_create_cis(self, cis_and_acl_handle_array):
|
|
handles_pairs = []
|
|
for hp_tmp in cis_and_acl_handle_array:
|
|
handles_pairs.append(
|
|
iso_facade_pb2.LeCreateCisRequest.HandlePair(cis_handle=hp_tmp[0], acl_handle=hp_tmp[1]))
|
|
|
|
self._device.iso.LeCreateCis(iso_facade_pb2.LeCreateCisRequest(handle_pair=handles_pairs))
|
|
|
|
def wait_le_cis_established(self):
|
|
cis_establshed_capture = PyLeIso.IsoCigEstablished(iso_facade_pb2.IsoMsgType.ISO_CIS_ESTABLISHED)
|
|
assertThat(self._iso_event_stream).emits(cis_establshed_capture, timeout=timedelta(seconds=5))
|
|
cis_handle = cis_establshed_capture.get()[0]
|
|
return PyLeIsoStream(self._device, cis_handle, self._iso_data_stream)
|
|
|
|
@staticmethod
|
|
def IsoCigEstablished(type):
|
|
return Capture(lambda event: True if event.message_type == type else False, PyLeIso._extract_cis_handles)
|