323 lines
11 KiB
Python
Executable File
323 lines
11 KiB
Python
Executable File
# Copyright 2014 The Chromium OS Authors. All rights reserved.
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
|
|
import logging
|
|
import time
|
|
from collections import namedtuple
|
|
from contextlib import contextmanager
|
|
|
|
from autotest_lib.client.bin import utils
|
|
from autotest_lib.client.common_lib import error
|
|
from autotest_lib.client.cros.chameleon import chameleon
|
|
|
|
ChameleonPorts = namedtuple('ChameleonPorts', 'connected failed')
|
|
|
|
|
|
class ChameleonPortFinder(object):
|
|
"""
|
|
Responsible for finding all ports connected to the chameleon board.
|
|
|
|
It does not verify if these ports are connected to DUT.
|
|
|
|
"""
|
|
|
|
def __init__(self, chameleon_board):
|
|
"""
|
|
@param chameleon_board: a ChameleonBoard object representing the
|
|
Chameleon board whose ports we are interested
|
|
in finding.
|
|
|
|
"""
|
|
self.chameleon_board = chameleon_board
|
|
self.connected = None
|
|
self.failed = None
|
|
|
|
|
|
def find_all_ports(self):
|
|
"""
|
|
@returns a named tuple ChameleonPorts() containing a list of connected
|
|
ports as the first element and failed ports as second element.
|
|
|
|
"""
|
|
self.connected = self.chameleon_board.get_all_ports()
|
|
self.failed = []
|
|
|
|
return ChameleonPorts(self.connected, self.failed)
|
|
|
|
|
|
def find_port(self, interface):
|
|
"""
|
|
@param interface: string, the interface. e.g: HDMI, DP, VGA
|
|
@returns a ChameleonPort object if port is found, else None.
|
|
|
|
"""
|
|
connected_ports = self.find_all_ports().connected
|
|
|
|
for port in connected_ports:
|
|
if port.get_connector_type().lower() == interface.lower():
|
|
return port
|
|
|
|
return None
|
|
|
|
|
|
def __str__(self):
|
|
ports_to_str = lambda ports: ', '.join(
|
|
'%s(%d)' % (p.get_connector_type(), p.get_connector_id())
|
|
for p in ports)
|
|
|
|
if self.connected is None:
|
|
text = 'No port information. Did you run find_all_ports()?'
|
|
elif self.connected == []:
|
|
text = 'No port detected on the Chameleon board.'
|
|
else:
|
|
text = ('Detected %d connected port(s): %s. \t'
|
|
% (len(self.connected), ports_to_str(self.connected)))
|
|
|
|
if self.failed:
|
|
text += ('DUT failed to detect Chameleon ports: %s'
|
|
% ports_to_str(self.failed))
|
|
|
|
return text
|
|
|
|
|
|
class ChameleonInputFinder(ChameleonPortFinder):
|
|
"""
|
|
Responsible for finding all input ports connected to the chameleon board.
|
|
|
|
"""
|
|
|
|
def find_all_ports(self):
|
|
"""
|
|
@returns a named tuple ChameleonPorts() containing a list of connected
|
|
input ports as the first element and failed ports as second
|
|
element.
|
|
|
|
"""
|
|
self.connected = self.chameleon_board.get_all_inputs()
|
|
self.failed = []
|
|
|
|
return ChameleonPorts(self.connected, self.failed)
|
|
|
|
|
|
class ChameleonOutputFinder(ChameleonPortFinder):
|
|
"""
|
|
Responsible for finding all output ports connected to the chameleon board.
|
|
|
|
"""
|
|
|
|
def find_all_ports(self):
|
|
"""
|
|
@returns a named tuple ChameleonPorts() containing a list of connected
|
|
output ports as the first element and failed ports as the
|
|
second element.
|
|
|
|
"""
|
|
self.connected = self.chameleon_board.get_all_outputs()
|
|
self.failed = []
|
|
|
|
return ChameleonPorts(self.connected, self.failed)
|
|
|
|
|
|
class ChameleonVideoInputFinder(ChameleonInputFinder):
|
|
"""
|
|
Responsible for finding all video inputs connected to the chameleon board.
|
|
|
|
It also verifies if these ports are connected to DUT.
|
|
|
|
"""
|
|
|
|
REPLUG_DELAY_SEC = 1
|
|
|
|
def __init__(self, chameleon_board, display_facade):
|
|
"""
|
|
@param chameleon_board: a ChameleonBoard object representing the
|
|
Chameleon board whose ports we are interested
|
|
in finding.
|
|
@param display_facade: a display facade object, to access the DUT
|
|
display functionality, either locally or
|
|
remotely.
|
|
|
|
"""
|
|
super(ChameleonVideoInputFinder, self).__init__(chameleon_board)
|
|
self.display_facade = display_facade
|
|
self._TIMEOUT_VIDEO_STABLE_PROBE = 10
|
|
|
|
|
|
def _yield_all_ports(self, failed_ports=None, raise_error=False):
|
|
"""
|
|
Yields all connected video ports and ensures every of them plugged.
|
|
|
|
@param failed_ports: A list to append the failed port or None.
|
|
@param raise_error: True to raise TestFail if no connected video port.
|
|
@yields every connected ChameleonVideoInput which is ensured plugged
|
|
before yielding.
|
|
|
|
@raises TestFail if raise_error is True and no connected video port.
|
|
|
|
"""
|
|
yielded = False
|
|
all_ports = super(ChameleonVideoInputFinder, self).find_all_ports()
|
|
|
|
# unplug all ports
|
|
for port in all_ports.connected:
|
|
if port.has_video_support():
|
|
chameleon.ChameleonVideoInput(port).unplug()
|
|
self.display_facade.reset_connector_if_applicable(
|
|
port.get_connector_type())
|
|
|
|
for port in all_ports.connected:
|
|
# Skip the non-video port.
|
|
if not port.has_video_support():
|
|
continue
|
|
|
|
video_port = chameleon.ChameleonVideoInput(port)
|
|
# Plug the port to make it visible.
|
|
video_port.plug()
|
|
try:
|
|
# DUT takes some time to respond. Wait until the video signal
|
|
# to stabilize and wait for the connector change.
|
|
video_stable = video_port.wait_video_input_stable(
|
|
self._TIMEOUT_VIDEO_STABLE_PROBE)
|
|
output = utils.wait_for_value_changed(
|
|
self.display_facade.get_external_connector_name,
|
|
old_value=False)
|
|
|
|
if not output:
|
|
logging.warn('Maybe flaky that no display detected. Retry.')
|
|
video_port.unplug()
|
|
time.sleep(self.REPLUG_DELAY_SEC)
|
|
video_port.plug()
|
|
video_stable = video_port.wait_video_input_stable(
|
|
self._TIMEOUT_VIDEO_STABLE_PROBE)
|
|
output = utils.wait_for_value_changed(
|
|
self.display_facade.get_external_connector_name,
|
|
old_value=False)
|
|
|
|
logging.info('CrOS detected external connector: %r', output)
|
|
|
|
if output:
|
|
yield video_port
|
|
yielded = True
|
|
else:
|
|
if failed_ports is not None:
|
|
failed_ports.append(video_port)
|
|
logging.error('CrOS failed to see any external display')
|
|
if not video_stable:
|
|
logging.warn('Chameleon timed out waiting CrOS video')
|
|
finally:
|
|
# Unplug the port not to interfere with other tests.
|
|
video_port.unplug()
|
|
|
|
if raise_error and not yielded:
|
|
raise error.TestFail('No connected video port found between CrOS '
|
|
'and Chameleon.')
|
|
|
|
|
|
def iterate_all_ports(self):
|
|
"""
|
|
Iterates all connected video ports and ensures every of them plugged.
|
|
|
|
It is used via a for statement, like the following:
|
|
|
|
finder = ChameleonVideoInputFinder(chameleon_board, display_facade)
|
|
for chameleon_port in finder.iterate_all_ports()
|
|
# chameleon_port is automatically plugged before this line.
|
|
do_some_test_on(chameleon_port)
|
|
# chameleon_port is automatically unplugged after this line.
|
|
|
|
@yields every connected ChameleonVideoInput which is ensured plugged
|
|
before yeilding.
|
|
|
|
@raises TestFail if no connected video port.
|
|
|
|
"""
|
|
return self._yield_all_ports(raise_error=True)
|
|
|
|
|
|
@contextmanager
|
|
def use_first_port(self):
|
|
"""
|
|
Use the first connected video port and ensures it plugged.
|
|
|
|
It is used via a with statement, like the following:
|
|
|
|
finder = ChameleonVideoInputFinder(chameleon_board, display_facade)
|
|
with finder.use_first_port() as chameleon_port:
|
|
# chameleon_port is automatically plugged before this line.
|
|
do_some_test_on(chameleon_port)
|
|
# chameleon_port is automatically unplugged after this line.
|
|
|
|
@yields the first connected ChameleonVideoInput which is ensured plugged
|
|
before yeilding.
|
|
|
|
@raises TestFail if no connected video port.
|
|
|
|
"""
|
|
for port in self._yield_all_ports(raise_error=True):
|
|
yield port
|
|
break
|
|
|
|
|
|
def find_all_ports(self):
|
|
"""
|
|
@returns a named tuple ChameleonPorts() containing a list of connected
|
|
video inputs as the first element and failed ports as second
|
|
element.
|
|
|
|
"""
|
|
dut_failed_ports = []
|
|
connected_ports = list(self._yield_all_ports(dut_failed_ports))
|
|
self.connected = connected_ports
|
|
self.failed = dut_failed_ports
|
|
|
|
return ChameleonPorts(connected_ports, dut_failed_ports)
|
|
|
|
|
|
class ChameleonAudioInputFinder(ChameleonInputFinder):
|
|
"""
|
|
Responsible for finding all audio inputs connected to the chameleon board.
|
|
|
|
It does not verify if these ports are connected to DUT.
|
|
|
|
"""
|
|
|
|
def find_all_ports(self):
|
|
"""
|
|
@returns a named tuple ChameleonPorts() containing a list of connected
|
|
audio inputs as the first element and failed ports as second
|
|
element.
|
|
|
|
"""
|
|
all_ports = super(ChameleonAudioInputFinder, self).find_all_ports()
|
|
self.connected = [chameleon.ChameleonAudioInput(port)
|
|
for port in all_ports.connected
|
|
if port.has_audio_support()]
|
|
self.failed = []
|
|
|
|
return ChameleonPorts(self.connected, self.failed)
|
|
|
|
|
|
class ChameleonAudioOutputFinder(ChameleonOutputFinder):
|
|
"""
|
|
Responsible for finding all audio outputs connected to the chameleon board.
|
|
|
|
It does not verify if these ports are connected to DUT.
|
|
|
|
"""
|
|
|
|
def find_all_ports(self):
|
|
"""
|
|
@returns a named tuple ChameleonPorts() containing a list of connected
|
|
audio outputs as the first element and failed ports as second
|
|
element.
|
|
|
|
"""
|
|
all_ports = super(ChameleonAudioOutputFinder, self).find_all_ports()
|
|
self.connected = [chameleon.ChameleonAudioOutput(port)
|
|
for port in all_ports.connected
|
|
if port.has_audio_support()]
|
|
self.failed = []
|
|
|
|
return ChameleonPorts(self.connected, self.failed)
|