#!/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)