chameleon.py revision 24a9b64a364a434167ceff8544bf188aa0c897e0
13ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch# Copyright (c) 2014 The Chromium OS Authors. All rights reserved. 2b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# Use of this source code is governed by a BSD-style license that can be 3b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# found in the LICENSE file. 4b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 5014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochimport httplib 6014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochimport logging 7b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochimport socket 8014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochimport time 9014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochimport xmlrpclib 10014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochfrom contextlib import contextmanager 11b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 12b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfrom PIL import Image 13b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 14b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochfrom autotest_lib.client.bin import utils 15b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochfrom autotest_lib.client.common_lib import error 16b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochfrom autotest_lib.client.cros.chameleon import audio_board 17b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfrom autotest_lib.client.cros.chameleon import edid as edid_lib 18b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 19b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 20b8a8cc1952d61a2f3a2568848933943a543b5d3eBen MurdochCHAMELEON_PORT = 9992 21b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 22b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 23b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochclass ChameleonConnectionError(error.TestError): 24b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch """Indicates that connecting to Chameleon failed. 25b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 26b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch It is fatal to the test unless caught. 27b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch """ 28b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch pass 29b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 30b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 31b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochclass ChameleonConnection(object): 32b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch """ChameleonConnection abstracts the network connection to the board. 33b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 34b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch ChameleonBoard and ChameleonPort use it for accessing Chameleon RPC. 35b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 36b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch """ 37b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 38b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch def __init__(self, hostname, port=CHAMELEON_PORT): 39014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch """Constructs a ChameleonConnection. 40b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 41b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch @param hostname: Hostname the chameleond process is running. 42b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch @param port: Port number the chameleond process is listening on. 43b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 44b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch @raise ChameleonConnectionError if connection failed. 45b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch """ 46b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch self.chameleond_proxy = ChameleonConnection._create_server_proxy( 47b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch hostname, port) 48b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 49b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 50b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch @staticmethod 51b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch def _create_server_proxy(hostname, port): 52b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch """Creates the chameleond server proxy. 53b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 54b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch @param hostname: Hostname the chameleond process is running. 55b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch @param port: Port number the chameleond process is listening on. 56b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 57b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch @return ServerProxy object to chameleond. 58b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 59b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch @raise ChameleonConnectionError if connection failed. 60b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch """ 61b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch remote = 'http://%s:%s' % (hostname, port) 62b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch chameleond_proxy = xmlrpclib.ServerProxy(remote, allow_none=True) 63b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch # Call a RPC to test. 64b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch try: 65b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch chameleond_proxy.GetSupportedPorts() 66b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch except (socket.error, 67b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch xmlrpclib.ProtocolError, 68b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch httplib.BadStatusLine) as e: 69b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch raise ChameleonConnectionError(e) 70b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return chameleond_proxy 71b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 72b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 73537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdochclass ChameleonBoard(object): 74b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch """ChameleonBoard is an abstraction of a Chameleon board. 75b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 76b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch A Chameleond RPC proxy is passed to the construction such that it can 77b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch use this proxy to control the Chameleon board. 78b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 79b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch User can use host to access utilities that are not provided by 80b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Chameleond XMLRPC server, e.g. send_file and get_file, which are provided by 81b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch ssh_host.SSHHost, which is the base class of ChameleonHost. 82014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 83b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch """ 84b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 85b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch def __init__(self, chameleon_connection, chameleon_host=None): 86b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch """Construct a ChameleonBoard. 87b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 88b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch @param chameleon_connection: ChameleonConnection object. 89b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch @param chameleon_host: ChameleonHost object. None if this ChameleonBoard 90b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch is not created by a ChameleonHost. 91b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch """ 92b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch self.host = chameleon_host 93b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch self._chameleond_proxy = chameleon_connection.chameleond_proxy 94b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if self._chameleond_proxy.HasAudioBoard(): 95b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch self._audio_board = audio_board.AudioBoard(chameleon_connection) 96b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch else: 97b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch self._audio_board = None 98b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch logging.info('There is no audio board on this Chameleon.') 99b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 100b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch def reset(self): 101b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch """Resets Chameleon board.""" 102b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch self._chameleond_proxy.Reset() 103b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 10421efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch 105b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch def get_all_ports(self): 1061b268ca467c924004286c97bac133db489cf43d0Ben Murdoch """Gets all the ports on Chameleon board which are connected. 1071b268ca467c924004286c97bac133db489cf43d0Ben Murdoch 108b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch @return: A list of ChameleonPort objects. 109b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch """ 110b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch ports = self._chameleond_proxy.ProbePorts() 111b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return [ChameleonPort(self._chameleond_proxy, port) for port in ports] 1121b268ca467c924004286c97bac133db489cf43d0Ben Murdoch 1131b268ca467c924004286c97bac133db489cf43d0Ben Murdoch 11421efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch def get_all_inputs(self): 115b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch """Gets all the input ports on Chameleon board which are connected. 116014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 117b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch @return: A list of ChameleonPort objects. 118b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch """ 119b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch ports = self._chameleond_proxy.ProbeInputs() 120b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return [ChameleonPort(self._chameleond_proxy, port) for port in ports] 121b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 122b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 123b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch def get_all_outputs(self): 124b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch """Gets all the output ports on Chameleon board which are connected. 125b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 126b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch @return: A list of ChameleonPort objects. 127b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch """ 128014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch ports = self._chameleond_proxy.ProbeOutputs() 129b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return [ChameleonPort(self._chameleond_proxy, port) for port in ports] 130b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 131b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 132b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch def get_label(self): 133b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch """Gets the label which indicates the display connection. 134b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 135b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch @return: A string of the label, like 'hdmi', 'dp_hdmi', etc. 136b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch """ 137b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch connectors = [] 138b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch for port in self._chameleond_proxy.ProbeInputs(): 139b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if self._chameleond_proxy.HasVideoSupport(port): 140b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch connector = self._chameleond_proxy.GetConnectorType(port).lower() 141b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch connectors.append(connector) 142b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch # Eliminate duplicated ports. It simplifies the labels of dual-port 143b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch # devices, i.e. dp_dp categorized into dp. 144b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return '_'.join(sorted(set(connectors))) 145b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 146b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 147b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch def get_audio_board(self): 148b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch """Gets the audio board on Chameleon. 149b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 150b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch @return: An AudioBoard object. 151b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch """ 152b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return self._audio_board 153b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 154b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 155b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochclass ChameleonPort(object): 1563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch """ChameleonPort is an abstraction of a general port of a Chameleon board. 157b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 158958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier It only contains some common methods shared with audio and video ports. 159014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 160014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch A Chameleond RPC proxy and an port_id are passed to the construction. 161014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch The port_id is the unique identity to the port. 162958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier """ 163958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier 164958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier def __init__(self, chameleond_proxy, port_id): 165b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch """Construct a ChameleonPort. 166b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 167b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch @param chameleond_proxy: Chameleond RPC proxy object. 168b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch @param port_id: The ID of the input port. 169b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch """ 170b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch self.chameleond_proxy = chameleond_proxy 171b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch self.port_id = port_id 172b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 173b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 174b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch def get_connector_id(self): 175b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch """Returns the connector ID. 176b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1771e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block @return: A number of connector ID. 1781e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block """ 179b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return self.port_id 180b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 181b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 182b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch def get_connector_type(self): 183b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch """Returns the human readable string for the connector type. 184b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 185b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch @return: A string, like "VGA", "DVI", "HDMI", or "DP". 186b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch """ 1873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch return self.chameleond_proxy.GetConnectorType(self.port_id) 1883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 189b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 190257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch def has_audio_support(self): 191257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch """Returns if the input has audio support. 192257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 193b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch @return: True if the input has audio support; otherwise, False. 194257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch """ 195257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch return self.chameleond_proxy.HasAudioSupport(self.port_id) 196257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 197257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 198257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch def has_video_support(self): 199257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch """Returns if the input has video support. 200257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 201257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch @return: True if the input has video support; otherwise, False. 202257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch """ 203257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch return self.chameleond_proxy.HasVideoSupport(self.port_id) 204257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 205257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 206257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch def plug(self): 207257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch """Asserts HPD line to high, emulating plug.""" 208257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch logging.info('Plug Chameleon port %d', self.port_id) 209b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch self.chameleond_proxy.Plug(self.port_id) 210b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 211b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 212b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch def unplug(self): 213b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch """Deasserts HPD line to low, emulating unplug.""" 214b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch logging.info('Unplug Chameleon port %d', self.port_id) 2151e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block self.chameleond_proxy.Unplug(self.port_id) 2161e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 2171e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 218b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch def set_plug(self, plug_status): 219b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch """Sets plug/unplug by plug_status. 220b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 221b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch @param plug_status: True to plug; False to unplug. 222b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch """ 223b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if plug_status: 224b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch self.plug() 225b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch else: 226b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch self.unplug() 227b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 2281e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 2291b268ca467c924004286c97bac133db489cf43d0Ben Murdoch @property 2301b268ca467c924004286c97bac133db489cf43d0Ben Murdoch def plugged(self): 2311b268ca467c924004286c97bac133db489cf43d0Ben Murdoch """ 2321b268ca467c924004286c97bac133db489cf43d0Ben Murdoch @returns True if this port is plugged to Chameleon, False otherwise. 2331b268ca467c924004286c97bac133db489cf43d0Ben Murdoch 2341b268ca467c924004286c97bac133db489cf43d0Ben Murdoch """ 2351b268ca467c924004286c97bac133db489cf43d0Ben Murdoch return self.chameleond_proxy.IsPlugged(self.port_id) 2361e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 237b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 238b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochclass ChameleonVideoInput(ChameleonPort): 239b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch """ChameleonVideoInput is an abstraction of a video input port. 240b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 241b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch It contains some special methods to control a video input. 2421e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block """ 2431e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 244b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch _DURATION_UNPLUG_FOR_EDID = 5 2451e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block _TIMEOUT_VIDEO_STABLE_PROBE = 10 246b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch _EDID_ID_DISABLE = -1 247b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 2481e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block def __init__(self, chameleon_port): 2491e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block """Construct a ChameleonVideoInput. 2501e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 2511e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block @param chameleon_port: A general ChameleonPort object. 252b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch """ 253b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch self.chameleond_proxy = chameleon_port.chameleond_proxy 2541e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block self.port_id = chameleon_port.port_id 2551e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 2561e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 2571e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block def wait_video_input_stable(self, timeout=None): 258b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch """Waits the video input stable or timeout. 259b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 260b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch @param timeout: The time period to wait for. 261b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 262b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch @return: True if the video input becomes stable within the timeout 263b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch period; otherwise, False. 264b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch """ 265b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return self.chameleond_proxy.WaitVideoInputStable(self.port_id, 266b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch timeout) 267b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 268b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 269b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch def read_edid(self): 2701b268ca467c924004286c97bac133db489cf43d0Ben Murdoch """Reads the EDID. 2711b268ca467c924004286c97bac133db489cf43d0Ben Murdoch 272b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch @return: An Edid object or NO_EDID. 2731e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block """ 274b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch edid_binary = self.chameleond_proxy.ReadEdid(self.port_id) 275b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if edid_binary is None: 276b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return edid_lib.NO_EDID 277b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch # Read EDID without verify. It may be made corrupted as intended 278b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch # for the test purpose. 279b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch return edid_lib.Edid(edid_binary.data, skip_verify=True) 2801e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 281b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 282b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch def apply_edid(self, edid): 283b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch """Applies the given EDID. 284b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch 285b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch @param edid: An Edid object or NO_EDID. 286014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch """ 287b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch if edid is edid_lib.NO_EDID: 288014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch self.chameleond_proxy.ApplyEdid(self.port_id, self._EDID_ID_DISABLE) 289b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch else: 290b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch edid_binary = xmlrpclib.Binary(edid.data) 291b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch edid_id = self.chameleond_proxy.CreateEdid(edid_binary) 292b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch self.chameleond_proxy.ApplyEdid(self.port_id, edid_id) 293b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch self.chameleond_proxy.DestroyEdid(edid_id) 294b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch 295b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 296b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch @contextmanager 297b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch def use_edid(self, edid): 298b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch """Uses the given EDID in a with statement. 299b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 300b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch It sets the EDID up in the beginning and restores to the original 3013fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch EDID in the end. This function is expected to be used in a with 3023fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch statement, like the following: 303b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 304b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch with chameleon_port.use_edid(edid): 305b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch do_some_test_on(chameleon_port) 306014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 307014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch @param edid: An EDID object. 308b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch """ 309014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch # Set the EDID up in the beginning. 310014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch plugged = self.plugged 311b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if plugged: 312b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch self.unplug() 313b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 314b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch original_edid = self.read_edid() 315b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch logging.info('Apply EDID on port %d', self.port_id) 316257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch self.apply_edid(edid) 317b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 318b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if plugged: 319b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch time.sleep(self._DURATION_UNPLUG_FOR_EDID) 320b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch self.plug() 321b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch self.wait_video_input_stable(self._TIMEOUT_VIDEO_STABLE_PROBE) 322b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 323257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch try: 324014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch # Yeild to execute the with statement. 325014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch yield 326257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch finally: 327b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch # Restore the original EDID in the end. 328257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch current_edid = self.read_edid() 329257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if original_edid.data != current_edid.data: 330b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch logging.info('Restore the original EDID.') 331b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch self.apply_edid(original_edid) 332b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 333b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 334b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch def use_edid_file(self, filename): 335b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch """Uses the given EDID file in a with statement. 336b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 337b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch It sets the EDID up in the beginning and restores to the original 338b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch EDID in the end. This function is expected to be used in a with 339b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch statement, like the following: 340b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 341b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch with chameleon_port.use_edid_file(filename): 342b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch do_some_test_on(chameleon_port) 343b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 344b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch @param filename: A path to the EDID file. 345b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch """ 346b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return self.use_edid(edid_lib.Edid.from_file(filename)) 347b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 348b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 349b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch def fire_hpd_pulse(self, deassert_interval_usec, assert_interval_usec=None, 350b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch repeat_count=1, end_level=1): 351b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 352b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch """Fires one or more HPD pulse (low -> high -> low -> ...). 353b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 354b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch @param deassert_interval_usec: The time in microsecond of the 355b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch deassert pulse. 356b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch @param assert_interval_usec: The time in microsecond of the 357b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch assert pulse. If None, then use the same value as 358b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch deassert_interval_usec. 359b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch @param repeat_count: The count of HPD pulses to fire. 360b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch @param end_level: HPD ends with 0 for LOW (unplugged) or 1 for 361014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch HIGH (plugged). 362257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch """ 363257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch self.chameleond_proxy.FireHpdPulse( 364257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch self.port_id, deassert_interval_usec, 365014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch assert_interval_usec, repeat_count, int(bool(end_level))) 366b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 367b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 368b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch def fire_mixed_hpd_pulses(self, widths): 369257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch """Fires one or more HPD pulses, starting at low, of mixed widths. 370257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 371257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch One must specify a list of segment widths in the widths argument where 372257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch widths[0] is the width of the first low segment, widths[1] is that of 373014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch the first high segment, widths[2] is that of the second low segment... 374b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch etc. The HPD line stops at low if even number of segment widths are 375b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch specified; otherwise, it stops at high. 376b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 377014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch @param widths: list of pulse segment widths in usec. 378b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch """ 379014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch self.chameleond_proxy.FireMixedHpdPulses(self.port_id, widths) 380014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 381b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 382b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch def capture_screen(self): 383014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch """Captures Chameleon framebuffer. 384b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 385b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch @return An Image object. 386b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch """ 387b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return Image.fromstring( 388b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 'RGB', 389b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch self.get_resolution(), 390b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch self.chameleond_proxy.DumpPixels(self.port_id).data) 391b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 392b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 393b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch def get_resolution(self): 394014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch """Gets the source resolution. 395014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 396014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch @return: A (width, height) tuple. 397014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch """ 398014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch # The return value of RPC is converted to a list. Convert it back to 399014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch # a tuple. 400014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch return tuple(self.chameleond_proxy.DetectResolution(self.port_id)) 401b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 402b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 403b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch def set_content_protection(self, enable): 404b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch """Sets the content protection state on the port. 405b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 406014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch @param enable: True to enable; False to disable. 407b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch """ 408b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch self.chameleond_proxy.SetContentProtection(self.port_id, enable) 409b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 410b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 411b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch def is_content_protection_enabled(self): 412b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch """Returns True if the content protection is enabled on the port. 413014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 414b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch @return: True if the content protection is enabled; otherwise, False. 415b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch """ 416b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return self.chameleond_proxy.IsContentProtectionEnabled(self.port_id) 417b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 418b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 419b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch def is_video_input_encrypted(self): 420b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch """Returns True if the video input on the port is encrypted. 421b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 422014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch @return: True if the video input is encrypted; otherwise, False. 423b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch """ 424014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch return self.chameleond_proxy.IsVideoInputEncrypted(self.port_id) 425b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 426b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 427b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch def start_capturing_video(self, box=None): 428b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch """ 429b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Captures video frames. Asynchronous, returns immediately. 430014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 431b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch @param box: int tuple, left, upper, right, lower pixel coordinates. 432b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Defines the rectangular boundary within which to capture. 433b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch """ 434b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 435014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch if box is None: 436b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch self.chameleond_proxy.StartCapturingVideo(self.port_id) 437b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch else: 438014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch self.chameleond_proxy.StartCapturingVideo(self.port_id, *box) 439b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 440b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 441b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch def stop_capturing_video(self): 442b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch """ 443b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Stops the ongoing video frame capturing. 444b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 445b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch """ 446b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch self.chameleond_proxy.StopCapturingVideo(self.port_id) 447b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 448b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 449b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch def get_captured_frame_count(self): 450b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch """ 451b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch @return: int, the number of frames that have been captured. 452b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 453b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch """ 454014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch return self.chameleond_proxy.GetCapturedFrameCount() 455b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 456014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 457b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch def read_captured_frame(self, index): 458b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch """ 459b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch @param index: int, index of the desired captured frame. 460b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch @return: xmlrpclib.Binary object containing a byte-array of the pixels. 461014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 462b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch """ 463014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 464b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch frame = self.chameleond_proxy.ReadCapturedFrame(index) 465b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch return Image.fromstring('RGB', 466b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch self.get_captured_resolution(), 467b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch frame.data) 4681e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 469b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch 470b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch def get_captured_checksums(self, start_index=0, stop_index=None): 471b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch """ 472b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch @param start_index: int, index of the frame to start with. 473014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch @param stop_index: int, index of the frame (excluded) to stop at. 474b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch @return: a list of checksums of frames captured. 4753fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 4763fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch """ 477b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return self.chameleond_proxy.GetCapturedChecksums(start_index, 478b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch stop_index) 479b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 480b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 481b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch def get_captured_resolution(self): 482b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch """ 483b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch @return: (width, height) tuple, the resolution of captured frames. 484b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 485b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch """ 486b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return self.chameleond_proxy.GetCapturedResolution() 487b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 488b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 489b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 490b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochclass ChameleonAudioInput(ChameleonPort): 491b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch """ChameleonAudioInput is an abstraction of an audio input port. 492b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 493b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch It contains some special methods to control an audio input. 494b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch """ 495b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 496b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch def __init__(self, chameleon_port): 497b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch """Construct a ChameleonAudioInput. 498b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 499b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch @param chameleon_port: A general ChameleonPort object. 500b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch """ 501b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch self.chameleond_proxy = chameleon_port.chameleond_proxy 502b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch self.port_id = chameleon_port.port_id 5033fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 5043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 5053fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch def start_capturing_audio(self): 506b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch """Starts capturing audio.""" 507b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return self.chameleond_proxy.StartCapturingAudio(self.port_id) 508b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 509b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 510b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch def stop_capturing_audio(self): 511b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch """Stops capturing audio. 512014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 5133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Returns: 5143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch A tuple (data, format). 5153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch data: The captured binary data. 5163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch format: A dict containing: 5173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch file_type: 'raw' or 'wav'. 5183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch sample_format: 'S32_LE' for 32-bit signed integer in little-endian. 5193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Refer to aplay manpage for other formats. 5203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch channel: channel number. 5213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch rate: sampling rate. 5223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch """ 5233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch rpc_data, data_format = self.chameleond_proxy.StopCapturingAudio( 524b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch self.port_id) 525b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return rpc_data.data, data_format 526b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 527b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 5283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochclass ChameleonAudioOutput(ChameleonPort): 5293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch """ChameleonAudioOutput is an abstraction of an audio output port. 5303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 531014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch It contains some special methods to control an audio output. 532b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch """ 533b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 534b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch def __init__(self, chameleon_port): 535b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch """Construct a ChameleonAudioOutput. 5363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 537b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch @param chameleon_port: A general ChameleonPort object. 538b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch """ 539b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch self.chameleond_proxy = chameleon_port.chameleond_proxy 540b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch self.port_id = chameleon_port.port_id 541b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch 542b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 543b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch def start_playing_audio(self, path, data_format): 544b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch """Starts playing audio. 545b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch 546b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch @param path: The path to the file to play on Chameleon. 547b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch @param data_format: A dict containing data format. Currently Chameleon 548b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch only accepts data format: 5491b268ca467c924004286c97bac133db489cf43d0Ben Murdoch dict(file_type='raw', sample_format='S32_LE', 550b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch channel=8, rate=48000). 551b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 552b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch """ 553014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch self.chameleond_proxy.StartPlayingAudio(self.port_id, path, data_format) 554b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 555b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch 556b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch def stop_playing_audio(self): 557b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch """Stops capturing audio.""" 558b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch self.chameleond_proxy.StopPlayingAudio(self.port_id) 559b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch 560b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 561b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdochdef make_chameleon_hostname(dut_hostname): 562b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch """Given a DUT's hostname, returns the hostname of its Chameleon. 563b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch 564b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch @param dut_hostname: Hostname of a DUT. 565b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 566b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch @return Hostname of the DUT's Chameleon. 567014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch """ 568b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch host_parts = dut_hostname.split('.') 569b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch host_parts[0] = host_parts[0] + '-chameleon' 570b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch return '.'.join(host_parts) 571014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 572b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 573b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdochdef create_chameleon_board(dut_hostname, args): 574b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch """Given either DUT's hostname or argments, creates a ChameleonBoard object. 575b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch 576b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch If the DUT's hostname is in the lab zone, it connects to the Chameleon by 577b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch append the hostname with '-chameleon' suffix. If not, checks if the args 578b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch contains the key-value pair 'chameleon_host=IP'. 579b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 580b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch @param dut_hostname: Hostname of a DUT. 581b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch @param args: A string of arguments passed from the command line. 582b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 583014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch @return A ChameleonBoard object. 584b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 585b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch @raise ChameleonConnectionError if unknown hostname. 586b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch """ 587b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch connection = None 588b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch hostname = make_chameleon_hostname(dut_hostname) 589b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if utils.host_is_in_lab_zone(hostname): 590014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch connection = ChameleonConnection(hostname) 591b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch else: 592b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch args_dict = utils.args_to_dict(args) 593b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch hostname = args_dict.get('chameleon_host', None) 594b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch port = args_dict.get('chameleon_port', CHAMELEON_PORT) 595b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if hostname: 596014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch connection = ChameleonConnection(hostname, port) 597b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch else: 598b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch raise ChameleonConnectionError('No chameleon_host is given in args') 599b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 600b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return ChameleonBoard(connection) 601b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch