1eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam# Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
2eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam# Use of this source code is governed by a BSD-style license that can be
3eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam# found in the LICENSE file.
4eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam
5c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tamimport httplib
672e354c97eb4890f4ce770ea27caa62cf620b4c1Tom Wai-Hong Tamimport logging
7c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tamimport socket
8e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tamimport time
9eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tamimport xmlrpclib
10e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tamfrom contextlib import contextmanager
11eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam
12428b34464f1060129cbcda08d60ec44ed88a518dJ. Richard Barnettefrom PIL import Image
13428b34464f1060129cbcda08d60ec44ed88a518dJ. Richard Barnette
14c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tamfrom autotest_lib.client.bin import utils
15c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tamfrom autotest_lib.client.common_lib import error
162e9446a948550c9c504e60826b5118180a39a0c8Cheng-Yi Chiangfrom autotest_lib.client.cros.chameleon import audio_board
175b43d6ab4e30473d0935e7ffc3a59767cdfbd34eTom Wai-Hong Tamfrom autotest_lib.client.cros.chameleon import edid as edid_lib
18a320675d6aadeb74b17f708b31af2873f63a001eSelina Liufrom autotest_lib.client.cros.chameleon import usb_controller
197a4ba1cad16c47849d8dfabcfaf5aa9d64960977Tom Wai-Hong Tam
20eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam
21c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong TamCHAMELEON_PORT = 9992
22c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam
23c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam
24c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tamclass ChameleonConnectionError(error.TestError):
25c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam    """Indicates that connecting to Chameleon failed.
26c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam
27c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam    It is fatal to the test unless caught.
28c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam    """
29c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam    pass
30c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam
31c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam
32c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tamclass ChameleonConnection(object):
33c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam    """ChameleonConnection abstracts the network connection to the board.
34c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam
35c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam    ChameleonBoard and ChameleonPort use it for accessing Chameleon RPC.
36c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam
37c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam    """
38c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam
39c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam    def __init__(self, hostname, port=CHAMELEON_PORT):
40c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam        """Constructs a ChameleonConnection.
41c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam
42c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam        @param hostname: Hostname the chameleond process is running.
43c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam        @param port: Port number the chameleond process is listening on.
44c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam
45c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam        @raise ChameleonConnectionError if connection failed.
46c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam        """
47c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam        self.chameleond_proxy = ChameleonConnection._create_server_proxy(
48c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam                hostname, port)
49c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam
50c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam
51c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam    @staticmethod
52c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam    def _create_server_proxy(hostname, port):
53c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam        """Creates the chameleond server proxy.
54c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam
55c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam        @param hostname: Hostname the chameleond process is running.
56c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam        @param port: Port number the chameleond process is listening on.
57c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam
58c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam        @return ServerProxy object to chameleond.
59c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam
60c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam        @raise ChameleonConnectionError if connection failed.
61c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam        """
62c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam        remote = 'http://%s:%s' % (hostname, port)
63c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam        chameleond_proxy = xmlrpclib.ServerProxy(remote, allow_none=True)
64c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam        # Call a RPC to test.
65c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam        try:
66b4fd848987c6ac62a9e65ff4bb91ef281ab6894eTom Wai-Hong Tam            chameleond_proxy.GetSupportedPorts()
67c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam        except (socket.error,
68c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam                xmlrpclib.ProtocolError,
69c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam                httplib.BadStatusLine) as e:
70c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam            raise ChameleonConnectionError(e)
71c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam        return chameleond_proxy
72c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam
73c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam
74eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tamclass ChameleonBoard(object):
75eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam    """ChameleonBoard is an abstraction of a Chameleon board.
76eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam
77eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam    A Chameleond RPC proxy is passed to the construction such that it can
78eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam    use this proxy to control the Chameleon board.
79c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam
806517831bcd04801ae5ce8124d045e1c3365d8525Cheng-Yi Chiang    User can use host to access utilities that are not provided by
816517831bcd04801ae5ce8124d045e1c3365d8525Cheng-Yi Chiang    Chameleond XMLRPC server, e.g. send_file and get_file, which are provided by
826517831bcd04801ae5ce8124d045e1c3365d8525Cheng-Yi Chiang    ssh_host.SSHHost, which is the base class of ChameleonHost.
836517831bcd04801ae5ce8124d045e1c3365d8525Cheng-Yi Chiang
84eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam    """
85eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam
866517831bcd04801ae5ce8124d045e1c3365d8525Cheng-Yi Chiang    def __init__(self, chameleon_connection, chameleon_host=None):
87eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam        """Construct a ChameleonBoard.
88eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam
89c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam        @param chameleon_connection: ChameleonConnection object.
906517831bcd04801ae5ce8124d045e1c3365d8525Cheng-Yi Chiang        @param chameleon_host: ChameleonHost object. None if this ChameleonBoard
916517831bcd04801ae5ce8124d045e1c3365d8525Cheng-Yi Chiang                               is not created by a ChameleonHost.
92eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam        """
936517831bcd04801ae5ce8124d045e1c3365d8525Cheng-Yi Chiang        self.host = chameleon_host
94c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam        self._chameleond_proxy = chameleon_connection.chameleond_proxy
95a320675d6aadeb74b17f708b31af2873f63a001eSelina Liu        self._usb_ctrl = usb_controller.USBController(chameleon_connection)
9692cce6c062e48b1adf173a6fd0a519d9f920b5ddCheng-Yi Chiang        if self._chameleond_proxy.HasAudioBoard():
9792cce6c062e48b1adf173a6fd0a519d9f920b5ddCheng-Yi Chiang            self._audio_board = audio_board.AudioBoard(chameleon_connection)
9892cce6c062e48b1adf173a6fd0a519d9f920b5ddCheng-Yi Chiang        else:
9992cce6c062e48b1adf173a6fd0a519d9f920b5ddCheng-Yi Chiang            self._audio_board = None
10092cce6c062e48b1adf173a6fd0a519d9f920b5ddCheng-Yi Chiang            logging.info('There is no audio board on this Chameleon.')
101eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam
102eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam    def reset(self):
103eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam        """Resets Chameleon board."""
104eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam        self._chameleond_proxy.Reset()
105eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam
106eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam
107eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam    def get_all_ports(self):
108eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam        """Gets all the ports on Chameleon board which are connected.
109eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam
110eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam        @return: A list of ChameleonPort objects.
111eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam        """
11219c95d740e9b6194d94e30c4bfce9ce449b34da5Tom Wai-Hong Tam        ports = self._chameleond_proxy.ProbePorts()
11319c95d740e9b6194d94e30c4bfce9ce449b34da5Tom Wai-Hong Tam        return [ChameleonPort(self._chameleond_proxy, port) for port in ports]
11419c95d740e9b6194d94e30c4bfce9ce449b34da5Tom Wai-Hong Tam
11519c95d740e9b6194d94e30c4bfce9ce449b34da5Tom Wai-Hong Tam
11619c95d740e9b6194d94e30c4bfce9ce449b34da5Tom Wai-Hong Tam    def get_all_inputs(self):
11719c95d740e9b6194d94e30c4bfce9ce449b34da5Tom Wai-Hong Tam        """Gets all the input ports on Chameleon board which are connected.
11819c95d740e9b6194d94e30c4bfce9ce449b34da5Tom Wai-Hong Tam
11919c95d740e9b6194d94e30c4bfce9ce449b34da5Tom Wai-Hong Tam        @return: A list of ChameleonPort objects.
12019c95d740e9b6194d94e30c4bfce9ce449b34da5Tom Wai-Hong Tam        """
121eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam        ports = self._chameleond_proxy.ProbeInputs()
122eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam        return [ChameleonPort(self._chameleond_proxy, port) for port in ports]
123eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam
124eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam
12519c95d740e9b6194d94e30c4bfce9ce449b34da5Tom Wai-Hong Tam    def get_all_outputs(self):
12619c95d740e9b6194d94e30c4bfce9ce449b34da5Tom Wai-Hong Tam        """Gets all the output ports on Chameleon board which are connected.
12719c95d740e9b6194d94e30c4bfce9ce449b34da5Tom Wai-Hong Tam
12819c95d740e9b6194d94e30c4bfce9ce449b34da5Tom Wai-Hong Tam        @return: A list of ChameleonPort objects.
12919c95d740e9b6194d94e30c4bfce9ce449b34da5Tom Wai-Hong Tam        """
13019c95d740e9b6194d94e30c4bfce9ce449b34da5Tom Wai-Hong Tam        ports = self._chameleond_proxy.ProbeOutputs()
13119c95d740e9b6194d94e30c4bfce9ce449b34da5Tom Wai-Hong Tam        return [ChameleonPort(self._chameleond_proxy, port) for port in ports]
13219c95d740e9b6194d94e30c4bfce9ce449b34da5Tom Wai-Hong Tam
13319c95d740e9b6194d94e30c4bfce9ce449b34da5Tom Wai-Hong Tam
1343d75ebce0a965218db301852e3feb309b3d5b333Tom Wai-Hong Tam    def get_label(self):
1353d75ebce0a965218db301852e3feb309b3d5b333Tom Wai-Hong Tam        """Gets the label which indicates the display connection.
1363d75ebce0a965218db301852e3feb309b3d5b333Tom Wai-Hong Tam
1373d75ebce0a965218db301852e3feb309b3d5b333Tom Wai-Hong Tam        @return: A string of the label, like 'hdmi', 'dp_hdmi', etc.
1383d75ebce0a965218db301852e3feb309b3d5b333Tom Wai-Hong Tam        """
139d7a45223ad35e98496bf3d0f8eeefa7a1eb2d731Tom Wai-Hong Tam        connectors = []
140d7a45223ad35e98496bf3d0f8eeefa7a1eb2d731Tom Wai-Hong Tam        for port in self._chameleond_proxy.ProbeInputs():
141d7a45223ad35e98496bf3d0f8eeefa7a1eb2d731Tom Wai-Hong Tam            if self._chameleond_proxy.HasVideoSupport(port):
142d7a45223ad35e98496bf3d0f8eeefa7a1eb2d731Tom Wai-Hong Tam                connector = self._chameleond_proxy.GetConnectorType(port).lower()
143d7a45223ad35e98496bf3d0f8eeefa7a1eb2d731Tom Wai-Hong Tam                connectors.append(connector)
1443d75ebce0a965218db301852e3feb309b3d5b333Tom Wai-Hong Tam        # Eliminate duplicated ports. It simplifies the labels of dual-port
1453d75ebce0a965218db301852e3feb309b3d5b333Tom Wai-Hong Tam        # devices, i.e. dp_dp categorized into dp.
1463d75ebce0a965218db301852e3feb309b3d5b333Tom Wai-Hong Tam        return '_'.join(sorted(set(connectors)))
1473d75ebce0a965218db301852e3feb309b3d5b333Tom Wai-Hong Tam
1483d75ebce0a965218db301852e3feb309b3d5b333Tom Wai-Hong Tam
1492e9446a948550c9c504e60826b5118180a39a0c8Cheng-Yi Chiang    def get_audio_board(self):
1502e9446a948550c9c504e60826b5118180a39a0c8Cheng-Yi Chiang        """Gets the audio board on Chameleon.
1512e9446a948550c9c504e60826b5118180a39a0c8Cheng-Yi Chiang
1522e9446a948550c9c504e60826b5118180a39a0c8Cheng-Yi Chiang        @return: An AudioBoard object.
1532e9446a948550c9c504e60826b5118180a39a0c8Cheng-Yi Chiang        """
1542e9446a948550c9c504e60826b5118180a39a0c8Cheng-Yi Chiang        return self._audio_board
1552e9446a948550c9c504e60826b5118180a39a0c8Cheng-Yi Chiang
1562e9446a948550c9c504e60826b5118180a39a0c8Cheng-Yi Chiang
157a320675d6aadeb74b17f708b31af2873f63a001eSelina Liu    def get_usb_controller(self):
158a320675d6aadeb74b17f708b31af2873f63a001eSelina Liu        """Gets the USB controller on Chameleon.
159a320675d6aadeb74b17f708b31af2873f63a001eSelina Liu
160a320675d6aadeb74b17f708b31af2873f63a001eSelina Liu        @return: A USBController object.
161a320675d6aadeb74b17f708b31af2873f63a001eSelina Liu        """
162a320675d6aadeb74b17f708b31af2873f63a001eSelina Liu        return self._usb_ctrl
163a320675d6aadeb74b17f708b31af2873f63a001eSelina Liu
164a320675d6aadeb74b17f708b31af2873f63a001eSelina Liu
16508f2fc155347bffe84bf1e125fbcb82ec612e705Cheng-Yi Chiang    def get_mac_address(self):
16608f2fc155347bffe84bf1e125fbcb82ec612e705Cheng-Yi Chiang        """Gets the MAC address of Chameleon.
16708f2fc155347bffe84bf1e125fbcb82ec612e705Cheng-Yi Chiang
16808f2fc155347bffe84bf1e125fbcb82ec612e705Cheng-Yi Chiang        @return: A string for MAC address.
16908f2fc155347bffe84bf1e125fbcb82ec612e705Cheng-Yi Chiang        """
17008f2fc155347bffe84bf1e125fbcb82ec612e705Cheng-Yi Chiang        return self._chameleond_proxy.GetMacAddress()
17108f2fc155347bffe84bf1e125fbcb82ec612e705Cheng-Yi Chiang
17208f2fc155347bffe84bf1e125fbcb82ec612e705Cheng-Yi Chiang
173eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tamclass ChameleonPort(object):
1748578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam    """ChameleonPort is an abstraction of a general port of a Chameleon board.
1758578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam
1768578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam    It only contains some common methods shared with audio and video ports.
177eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam
17819c95d740e9b6194d94e30c4bfce9ce449b34da5Tom Wai-Hong Tam    A Chameleond RPC proxy and an port_id are passed to the construction.
17919c95d740e9b6194d94e30c4bfce9ce449b34da5Tom Wai-Hong Tam    The port_id is the unique identity to the port.
180eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam    """
181eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam
18219c95d740e9b6194d94e30c4bfce9ce449b34da5Tom Wai-Hong Tam    def __init__(self, chameleond_proxy, port_id):
183eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam        """Construct a ChameleonPort.
184eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam
185eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam        @param chameleond_proxy: Chameleond RPC proxy object.
18619c95d740e9b6194d94e30c4bfce9ce449b34da5Tom Wai-Hong Tam        @param port_id: The ID of the input port.
187eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam        """
1888578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam        self.chameleond_proxy = chameleond_proxy
1898578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam        self.port_id = port_id
190eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam
191eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam
192eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam    def get_connector_id(self):
193eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam        """Returns the connector ID.
194eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam
195eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam        @return: A number of connector ID.
196eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam        """
1978578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam        return self.port_id
198eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam
199eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam
200eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam    def get_connector_type(self):
201eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam        """Returns the human readable string for the connector type.
202eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam
203eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam        @return: A string, like "VGA", "DVI", "HDMI", or "DP".
204eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam        """
2058578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam        return self.chameleond_proxy.GetConnectorType(self.port_id)
206eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam
207eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam
2086bd2f1998baf5e9d53680f52511e2694ccc5d6d6Tom Wai-Hong Tam    def has_audio_support(self):
2096bd2f1998baf5e9d53680f52511e2694ccc5d6d6Tom Wai-Hong Tam        """Returns if the input has audio support.
2106bd2f1998baf5e9d53680f52511e2694ccc5d6d6Tom Wai-Hong Tam
2116bd2f1998baf5e9d53680f52511e2694ccc5d6d6Tom Wai-Hong Tam        @return: True if the input has audio support; otherwise, False.
2126bd2f1998baf5e9d53680f52511e2694ccc5d6d6Tom Wai-Hong Tam        """
2138578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam        return self.chameleond_proxy.HasAudioSupport(self.port_id)
2146bd2f1998baf5e9d53680f52511e2694ccc5d6d6Tom Wai-Hong Tam
2156bd2f1998baf5e9d53680f52511e2694ccc5d6d6Tom Wai-Hong Tam
2166bd2f1998baf5e9d53680f52511e2694ccc5d6d6Tom Wai-Hong Tam    def has_video_support(self):
2176bd2f1998baf5e9d53680f52511e2694ccc5d6d6Tom Wai-Hong Tam        """Returns if the input has video support.
2186bd2f1998baf5e9d53680f52511e2694ccc5d6d6Tom Wai-Hong Tam
2196bd2f1998baf5e9d53680f52511e2694ccc5d6d6Tom Wai-Hong Tam        @return: True if the input has video support; otherwise, False.
2206bd2f1998baf5e9d53680f52511e2694ccc5d6d6Tom Wai-Hong Tam        """
2218578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam        return self.chameleond_proxy.HasVideoSupport(self.port_id)
2228578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam
2238578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam
2248578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam    def plug(self):
2258578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam        """Asserts HPD line to high, emulating plug."""
22672e354c97eb4890f4ce770ea27caa62cf620b4c1Tom Wai-Hong Tam        logging.info('Plug Chameleon port %d', self.port_id)
2278578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam        self.chameleond_proxy.Plug(self.port_id)
2288578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam
2298578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam
2308578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam    def unplug(self):
2318578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam        """Deasserts HPD line to low, emulating unplug."""
23272e354c97eb4890f4ce770ea27caa62cf620b4c1Tom Wai-Hong Tam        logging.info('Unplug Chameleon port %d', self.port_id)
2338578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam        self.chameleond_proxy.Unplug(self.port_id)
2348578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam
2358578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam
23672e354c97eb4890f4ce770ea27caa62cf620b4c1Tom Wai-Hong Tam    def set_plug(self, plug_status):
23772e354c97eb4890f4ce770ea27caa62cf620b4c1Tom Wai-Hong Tam        """Sets plug/unplug by plug_status.
23872e354c97eb4890f4ce770ea27caa62cf620b4c1Tom Wai-Hong Tam
23972e354c97eb4890f4ce770ea27caa62cf620b4c1Tom Wai-Hong Tam        @param plug_status: True to plug; False to unplug.
24072e354c97eb4890f4ce770ea27caa62cf620b4c1Tom Wai-Hong Tam        """
24172e354c97eb4890f4ce770ea27caa62cf620b4c1Tom Wai-Hong Tam        if plug_status:
24272e354c97eb4890f4ce770ea27caa62cf620b4c1Tom Wai-Hong Tam            self.plug()
24372e354c97eb4890f4ce770ea27caa62cf620b4c1Tom Wai-Hong Tam        else:
24472e354c97eb4890f4ce770ea27caa62cf620b4c1Tom Wai-Hong Tam            self.unplug()
24572e354c97eb4890f4ce770ea27caa62cf620b4c1Tom Wai-Hong Tam
24672e354c97eb4890f4ce770ea27caa62cf620b4c1Tom Wai-Hong Tam
2478578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam    @property
2488578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam    def plugged(self):
2498578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam        """
2508578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam        @returns True if this port is plugged to Chameleon, False otherwise.
2518578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam
2528578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam        """
2538578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam        return self.chameleond_proxy.IsPlugged(self.port_id)
2548578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam
2558578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam
2568578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tamclass ChameleonVideoInput(ChameleonPort):
2578578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam    """ChameleonVideoInput is an abstraction of a video input port.
2588578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam
2598578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam    It contains some special methods to control a video input.
2608578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam    """
2618578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam
262c44fcd702aa712d0b8f3016930710973219e5af8Chin-Huang Lin    _DUT_STABILIZE_TIME = 3
263e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam    _DURATION_UNPLUG_FOR_EDID = 5
264e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam    _TIMEOUT_VIDEO_STABLE_PROBE = 10
2655b43d6ab4e30473d0935e7ffc3a59767cdfbd34eTom Wai-Hong Tam    _EDID_ID_DISABLE = -1
266e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam
2678578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam    def __init__(self, chameleon_port):
2688578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam        """Construct a ChameleonVideoInput.
2698578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam
2708578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam        @param chameleon_port: A general ChameleonPort object.
2718578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam        """
2728578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam        self.chameleond_proxy = chameleon_port.chameleond_proxy
2738578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam        self.port_id = chameleon_port.port_id
2746bd2f1998baf5e9d53680f52511e2694ccc5d6d6Tom Wai-Hong Tam
2756bd2f1998baf5e9d53680f52511e2694ccc5d6d6Tom Wai-Hong Tam
276e090aa536604063fcaa59955f74eefb07c80ca3aTom Wai-Hong Tam    def wait_video_input_stable(self, timeout=None):
277e090aa536604063fcaa59955f74eefb07c80ca3aTom Wai-Hong Tam        """Waits the video input stable or timeout.
278e090aa536604063fcaa59955f74eefb07c80ca3aTom Wai-Hong Tam
279e090aa536604063fcaa59955f74eefb07c80ca3aTom Wai-Hong Tam        @param timeout: The time period to wait for.
280e090aa536604063fcaa59955f74eefb07c80ca3aTom Wai-Hong Tam
281e090aa536604063fcaa59955f74eefb07c80ca3aTom Wai-Hong Tam        @return: True if the video input becomes stable within the timeout
282e090aa536604063fcaa59955f74eefb07c80ca3aTom Wai-Hong Tam                 period; otherwise, False.
283e090aa536604063fcaa59955f74eefb07c80ca3aTom Wai-Hong Tam        """
284c44fcd702aa712d0b8f3016930710973219e5af8Chin-Huang Lin        is_input_stable = self.chameleond_proxy.WaitVideoInputStable(
285c44fcd702aa712d0b8f3016930710973219e5af8Chin-Huang Lin                                self.port_id, timeout)
286c44fcd702aa712d0b8f3016930710973219e5af8Chin-Huang Lin
287c44fcd702aa712d0b8f3016930710973219e5af8Chin-Huang Lin        # If video input of Chameleon has been stable, wait for DUT software
288c44fcd702aa712d0b8f3016930710973219e5af8Chin-Huang Lin        # layer to be stable as well to make sure all the configurations have
289c44fcd702aa712d0b8f3016930710973219e5af8Chin-Huang Lin        # been propagated before proceeding.
290c44fcd702aa712d0b8f3016930710973219e5af8Chin-Huang Lin        if is_input_stable:
291c44fcd702aa712d0b8f3016930710973219e5af8Chin-Huang Lin            logging.info('Video input has been stable. Waiting for the DUT'
292c44fcd702aa712d0b8f3016930710973219e5af8Chin-Huang Lin                         ' to be stable...')
293c44fcd702aa712d0b8f3016930710973219e5af8Chin-Huang Lin            time.sleep(self._DUT_STABILIZE_TIME)
294c44fcd702aa712d0b8f3016930710973219e5af8Chin-Huang Lin        return is_input_stable
295e090aa536604063fcaa59955f74eefb07c80ca3aTom Wai-Hong Tam
296e090aa536604063fcaa59955f74eefb07c80ca3aTom Wai-Hong Tam
297eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam    def read_edid(self):
298eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam        """Reads the EDID.
299eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam
3005b43d6ab4e30473d0935e7ffc3a59767cdfbd34eTom Wai-Hong Tam        @return: An Edid object or NO_EDID.
301eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam        """
3025b43d6ab4e30473d0935e7ffc3a59767cdfbd34eTom Wai-Hong Tam        edid_binary = self.chameleond_proxy.ReadEdid(self.port_id)
3035b43d6ab4e30473d0935e7ffc3a59767cdfbd34eTom Wai-Hong Tam        if edid_binary is None:
3045b43d6ab4e30473d0935e7ffc3a59767cdfbd34eTom Wai-Hong Tam            return edid_lib.NO_EDID
3053737b1d3e9ce9e12341585d5431d947373dfc424Tom Wai-Hong Tam        # Read EDID without verify. It may be made corrupted as intended
3063737b1d3e9ce9e12341585d5431d947373dfc424Tom Wai-Hong Tam        # for the test purpose.
3075b43d6ab4e30473d0935e7ffc3a59767cdfbd34eTom Wai-Hong Tam        return edid_lib.Edid(edid_binary.data, skip_verify=True)
308eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam
309eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam
3107a4ba1cad16c47849d8dfabcfaf5aa9d64960977Tom Wai-Hong Tam    def apply_edid(self, edid):
311eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam        """Applies the given EDID.
312eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam
3135b43d6ab4e30473d0935e7ffc3a59767cdfbd34eTom Wai-Hong Tam        @param edid: An Edid object or NO_EDID.
314eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam        """
3155b43d6ab4e30473d0935e7ffc3a59767cdfbd34eTom Wai-Hong Tam        if edid is edid_lib.NO_EDID:
3165b43d6ab4e30473d0935e7ffc3a59767cdfbd34eTom Wai-Hong Tam          self.chameleond_proxy.ApplyEdid(self.port_id, self._EDID_ID_DISABLE)
3175b43d6ab4e30473d0935e7ffc3a59767cdfbd34eTom Wai-Hong Tam        else:
3185b43d6ab4e30473d0935e7ffc3a59767cdfbd34eTom Wai-Hong Tam          edid_binary = xmlrpclib.Binary(edid.data)
3195b43d6ab4e30473d0935e7ffc3a59767cdfbd34eTom Wai-Hong Tam          edid_id = self.chameleond_proxy.CreateEdid(edid_binary)
3205b43d6ab4e30473d0935e7ffc3a59767cdfbd34eTom Wai-Hong Tam          self.chameleond_proxy.ApplyEdid(self.port_id, edid_id)
3215b43d6ab4e30473d0935e7ffc3a59767cdfbd34eTom Wai-Hong Tam          self.chameleond_proxy.DestroyEdid(edid_id)
322c95277635c90ee616898d1f547440eff2dafc9cbMussa
323c95277635c90ee616898d1f547440eff2dafc9cbMussa
324e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam    @contextmanager
325e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam    def use_edid(self, edid):
326e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam        """Uses the given EDID in a with statement.
327e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam
328e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam        It sets the EDID up in the beginning and restores to the original
329e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam        EDID in the end. This function is expected to be used in a with
330e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam        statement, like the following:
331e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam
332e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam            with chameleon_port.use_edid(edid):
333e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam                do_some_test_on(chameleon_port)
334e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam
335e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam        @param edid: An EDID object.
336e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam        """
337e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam        # Set the EDID up in the beginning.
338e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam        plugged = self.plugged
339e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam        if plugged:
340e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam            self.unplug()
341e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam
342e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam        original_edid = self.read_edid()
343e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam        logging.info('Apply EDID on port %d', self.port_id)
344e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam        self.apply_edid(edid)
345e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam
346e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam        if plugged:
347e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam            time.sleep(self._DURATION_UNPLUG_FOR_EDID)
348e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam            self.plug()
349e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam            self.wait_video_input_stable(self._TIMEOUT_VIDEO_STABLE_PROBE)
350e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam
3512876774869edc2ca66476e471c409773ee0ab06dTom Wai-Hong Tam        try:
3522876774869edc2ca66476e471c409773ee0ab06dTom Wai-Hong Tam            # Yeild to execute the with statement.
3532876774869edc2ca66476e471c409773ee0ab06dTom Wai-Hong Tam            yield
3542876774869edc2ca66476e471c409773ee0ab06dTom Wai-Hong Tam        finally:
3552876774869edc2ca66476e471c409773ee0ab06dTom Wai-Hong Tam            # Restore the original EDID in the end.
3562876774869edc2ca66476e471c409773ee0ab06dTom Wai-Hong Tam            current_edid = self.read_edid()
3572876774869edc2ca66476e471c409773ee0ab06dTom Wai-Hong Tam            if original_edid.data != current_edid.data:
3582876774869edc2ca66476e471c409773ee0ab06dTom Wai-Hong Tam                logging.info('Restore the original EDID.')
3592876774869edc2ca66476e471c409773ee0ab06dTom Wai-Hong Tam                self.apply_edid(original_edid)
360e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam
361e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam
362e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam    def use_edid_file(self, filename):
363e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam        """Uses the given EDID file in a with statement.
364e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam
365e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam        It sets the EDID up in the beginning and restores to the original
366e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam        EDID in the end. This function is expected to be used in a with
367e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam        statement, like the following:
368e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam
369e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam            with chameleon_port.use_edid_file(filename):
370e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam                do_some_test_on(chameleon_port)
371e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam
372e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam        @param filename: A path to the EDID file.
373e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam        """
3745b43d6ab4e30473d0935e7ffc3a59767cdfbd34eTom Wai-Hong Tam        return self.use_edid(edid_lib.Edid.from_file(filename))
375e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam
376e6e901f00651bdd4796942b66d492b2de3d803f0Tom Wai-Hong Tam
377eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam    def fire_hpd_pulse(self, deassert_interval_usec, assert_interval_usec=None,
378e06f80fae6b4a54721bd0953f3383759791259f9Ting-Yuan Cheng                       repeat_count=1, end_level=1):
379eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam
380e06f80fae6b4a54721bd0953f3383759791259f9Ting-Yuan Cheng        """Fires one or more HPD pulse (low -> high -> low -> ...).
381e06f80fae6b4a54721bd0953f3383759791259f9Ting-Yuan Cheng
382e06f80fae6b4a54721bd0953f3383759791259f9Ting-Yuan Cheng        @param deassert_interval_usec: The time in microsecond of the
383e06f80fae6b4a54721bd0953f3383759791259f9Ting-Yuan Cheng                deassert pulse.
384e06f80fae6b4a54721bd0953f3383759791259f9Ting-Yuan Cheng        @param assert_interval_usec: The time in microsecond of the
385e06f80fae6b4a54721bd0953f3383759791259f9Ting-Yuan Cheng                assert pulse. If None, then use the same value as
386e06f80fae6b4a54721bd0953f3383759791259f9Ting-Yuan Cheng                deassert_interval_usec.
387e06f80fae6b4a54721bd0953f3383759791259f9Ting-Yuan Cheng        @param repeat_count: The count of HPD pulses to fire.
388e06f80fae6b4a54721bd0953f3383759791259f9Ting-Yuan Cheng        @param end_level: HPD ends with 0 for LOW (unplugged) or 1 for
389e06f80fae6b4a54721bd0953f3383759791259f9Ting-Yuan Cheng                HIGH (plugged).
390eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam        """
3918578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam        self.chameleond_proxy.FireHpdPulse(
3928578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam                self.port_id, deassert_interval_usec,
393e06f80fae6b4a54721bd0953f3383759791259f9Ting-Yuan Cheng                assert_interval_usec, repeat_count, int(bool(end_level)))
394eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam
395eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam
396dab3815cdcea63b68bb18318442fb759fc8cb6ebHung-ying Tyan    def fire_mixed_hpd_pulses(self, widths):
397dab3815cdcea63b68bb18318442fb759fc8cb6ebHung-ying Tyan        """Fires one or more HPD pulses, starting at low, of mixed widths.
398dab3815cdcea63b68bb18318442fb759fc8cb6ebHung-ying Tyan
399dab3815cdcea63b68bb18318442fb759fc8cb6ebHung-ying Tyan        One must specify a list of segment widths in the widths argument where
400dab3815cdcea63b68bb18318442fb759fc8cb6ebHung-ying Tyan        widths[0] is the width of the first low segment, widths[1] is that of
401dab3815cdcea63b68bb18318442fb759fc8cb6ebHung-ying Tyan        the first high segment, widths[2] is that of the second low segment...
402dab3815cdcea63b68bb18318442fb759fc8cb6ebHung-ying Tyan        etc. The HPD line stops at low if even number of segment widths are
403dab3815cdcea63b68bb18318442fb759fc8cb6ebHung-ying Tyan        specified; otherwise, it stops at high.
404dab3815cdcea63b68bb18318442fb759fc8cb6ebHung-ying Tyan
405dab3815cdcea63b68bb18318442fb759fc8cb6ebHung-ying Tyan        @param widths: list of pulse segment widths in usec.
406dab3815cdcea63b68bb18318442fb759fc8cb6ebHung-ying Tyan        """
4078578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam        self.chameleond_proxy.FireMixedHpdPulses(self.port_id, widths)
408dab3815cdcea63b68bb18318442fb759fc8cb6ebHung-ying Tyan
409dab3815cdcea63b68bb18318442fb759fc8cb6ebHung-ying Tyan
4104c8022f036732d1e12931a8f6743cfce92ab2fbaTom Wai-Hong Tam    def capture_screen(self):
411eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam        """Captures Chameleon framebuffer.
412eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam
4134c8022f036732d1e12931a8f6743cfce92ab2fbaTom Wai-Hong Tam        @return An Image object.
414eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam        """
415200a00c77422f92a28811c8174a364e1a716e9afTom Wai-Hong Tam        return Image.fromstring(
416200a00c77422f92a28811c8174a364e1a716e9afTom Wai-Hong Tam                'RGB',
4174c8022f036732d1e12931a8f6743cfce92ab2fbaTom Wai-Hong Tam                self.get_resolution(),
4188578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam                self.chameleond_proxy.DumpPixels(self.port_id).data)
419c95277635c90ee616898d1f547440eff2dafc9cbMussa
420eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam
421eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam    def get_resolution(self):
422eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam        """Gets the source resolution.
423eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam
424eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam        @return: A (width, height) tuple.
425eaee34082a63a957e6881ad779b825a774e3d7edTom Wai-Hong Tam        """
42684d759bd4be143e04f69a1def09ad5f36dadb12bTom Wai-Hong Tam        # The return value of RPC is converted to a list. Convert it back to
42784d759bd4be143e04f69a1def09ad5f36dadb12bTom Wai-Hong Tam        # a tuple.
4288578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam        return tuple(self.chameleond_proxy.DetectResolution(self.port_id))
4298578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam
4308578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam
4314e241012e91ba74f1e85d5e6a630290e18a15aa9Tom Wai-Hong Tam    def set_content_protection(self, enable):
4324e241012e91ba74f1e85d5e6a630290e18a15aa9Tom Wai-Hong Tam        """Sets the content protection state on the port.
4334e241012e91ba74f1e85d5e6a630290e18a15aa9Tom Wai-Hong Tam
4344e241012e91ba74f1e85d5e6a630290e18a15aa9Tom Wai-Hong Tam        @param enable: True to enable; False to disable.
4354e241012e91ba74f1e85d5e6a630290e18a15aa9Tom Wai-Hong Tam        """
4364e241012e91ba74f1e85d5e6a630290e18a15aa9Tom Wai-Hong Tam        self.chameleond_proxy.SetContentProtection(self.port_id, enable)
4374e241012e91ba74f1e85d5e6a630290e18a15aa9Tom Wai-Hong Tam
4384e241012e91ba74f1e85d5e6a630290e18a15aa9Tom Wai-Hong Tam
4394e241012e91ba74f1e85d5e6a630290e18a15aa9Tom Wai-Hong Tam    def is_content_protection_enabled(self):
4404e241012e91ba74f1e85d5e6a630290e18a15aa9Tom Wai-Hong Tam        """Returns True if the content protection is enabled on the port.
4414e241012e91ba74f1e85d5e6a630290e18a15aa9Tom Wai-Hong Tam
4424e241012e91ba74f1e85d5e6a630290e18a15aa9Tom Wai-Hong Tam        @return: True if the content protection is enabled; otherwise, False.
4434e241012e91ba74f1e85d5e6a630290e18a15aa9Tom Wai-Hong Tam        """
4444e241012e91ba74f1e85d5e6a630290e18a15aa9Tom Wai-Hong Tam        return self.chameleond_proxy.IsContentProtectionEnabled(self.port_id)
4454e241012e91ba74f1e85d5e6a630290e18a15aa9Tom Wai-Hong Tam
4464e241012e91ba74f1e85d5e6a630290e18a15aa9Tom Wai-Hong Tam
4474e241012e91ba74f1e85d5e6a630290e18a15aa9Tom Wai-Hong Tam    def is_video_input_encrypted(self):
4484e241012e91ba74f1e85d5e6a630290e18a15aa9Tom Wai-Hong Tam        """Returns True if the video input on the port is encrypted.
4494e241012e91ba74f1e85d5e6a630290e18a15aa9Tom Wai-Hong Tam
4504e241012e91ba74f1e85d5e6a630290e18a15aa9Tom Wai-Hong Tam        @return: True if the video input is encrypted; otherwise, False.
4514e241012e91ba74f1e85d5e6a630290e18a15aa9Tom Wai-Hong Tam        """
4524e241012e91ba74f1e85d5e6a630290e18a15aa9Tom Wai-Hong Tam        return self.chameleond_proxy.IsVideoInputEncrypted(self.port_id)
4534e241012e91ba74f1e85d5e6a630290e18a15aa9Tom Wai-Hong Tam
4544e241012e91ba74f1e85d5e6a630290e18a15aa9Tom Wai-Hong Tam
45532a15dd607c55ed227b47591facd637b86fcb801Mussa    def start_capturing_video(self, box=None):
45632a15dd607c55ed227b47591facd637b86fcb801Mussa        """
45732a15dd607c55ed227b47591facd637b86fcb801Mussa        Captures video frames. Asynchronous, returns immediately.
45832a15dd607c55ed227b47591facd637b86fcb801Mussa
45932a15dd607c55ed227b47591facd637b86fcb801Mussa        @param box: int tuple, left, upper, right, lower pixel coordinates.
46032a15dd607c55ed227b47591facd637b86fcb801Mussa                    Defines the rectangular boundary within which to capture.
46132a15dd607c55ed227b47591facd637b86fcb801Mussa        """
46232a15dd607c55ed227b47591facd637b86fcb801Mussa
46332a15dd607c55ed227b47591facd637b86fcb801Mussa        if box is None:
46432a15dd607c55ed227b47591facd637b86fcb801Mussa            self.chameleond_proxy.StartCapturingVideo(self.port_id)
46532a15dd607c55ed227b47591facd637b86fcb801Mussa        else:
46632a15dd607c55ed227b47591facd637b86fcb801Mussa            self.chameleond_proxy.StartCapturingVideo(self.port_id, *box)
46732a15dd607c55ed227b47591facd637b86fcb801Mussa
46832a15dd607c55ed227b47591facd637b86fcb801Mussa
46932a15dd607c55ed227b47591facd637b86fcb801Mussa    def stop_capturing_video(self):
47032a15dd607c55ed227b47591facd637b86fcb801Mussa        """
47132a15dd607c55ed227b47591facd637b86fcb801Mussa        Stops the ongoing video frame capturing.
47232a15dd607c55ed227b47591facd637b86fcb801Mussa
47332a15dd607c55ed227b47591facd637b86fcb801Mussa        """
47432a15dd607c55ed227b47591facd637b86fcb801Mussa        self.chameleond_proxy.StopCapturingVideo(self.port_id)
47532a15dd607c55ed227b47591facd637b86fcb801Mussa
47632a15dd607c55ed227b47591facd637b86fcb801Mussa
47732a15dd607c55ed227b47591facd637b86fcb801Mussa    def get_captured_frame_count(self):
47832a15dd607c55ed227b47591facd637b86fcb801Mussa        """
47932a15dd607c55ed227b47591facd637b86fcb801Mussa        @return: int, the number of frames that have been captured.
48032a15dd607c55ed227b47591facd637b86fcb801Mussa
48132a15dd607c55ed227b47591facd637b86fcb801Mussa        """
48232a15dd607c55ed227b47591facd637b86fcb801Mussa        return self.chameleond_proxy.GetCapturedFrameCount()
48332a15dd607c55ed227b47591facd637b86fcb801Mussa
48432a15dd607c55ed227b47591facd637b86fcb801Mussa
48532a15dd607c55ed227b47591facd637b86fcb801Mussa    def read_captured_frame(self, index):
48632a15dd607c55ed227b47591facd637b86fcb801Mussa        """
48732a15dd607c55ed227b47591facd637b86fcb801Mussa        @param index: int, index of the desired captured frame.
48832a15dd607c55ed227b47591facd637b86fcb801Mussa        @return: xmlrpclib.Binary object containing a byte-array of the pixels.
48932a15dd607c55ed227b47591facd637b86fcb801Mussa
49032a15dd607c55ed227b47591facd637b86fcb801Mussa        """
49132a15dd607c55ed227b47591facd637b86fcb801Mussa
49232a15dd607c55ed227b47591facd637b86fcb801Mussa        frame = self.chameleond_proxy.ReadCapturedFrame(index)
49332a15dd607c55ed227b47591facd637b86fcb801Mussa        return Image.fromstring('RGB',
49432a15dd607c55ed227b47591facd637b86fcb801Mussa                                self.get_captured_resolution(),
49532a15dd607c55ed227b47591facd637b86fcb801Mussa                                frame.data)
49632a15dd607c55ed227b47591facd637b86fcb801Mussa
49732a15dd607c55ed227b47591facd637b86fcb801Mussa
49832a15dd607c55ed227b47591facd637b86fcb801Mussa    def get_captured_checksums(self, start_index=0, stop_index=None):
49932a15dd607c55ed227b47591facd637b86fcb801Mussa        """
50032a15dd607c55ed227b47591facd637b86fcb801Mussa        @param start_index: int, index of the frame to start with.
50132a15dd607c55ed227b47591facd637b86fcb801Mussa        @param stop_index: int, index of the frame (excluded) to stop at.
50232a15dd607c55ed227b47591facd637b86fcb801Mussa        @return: a list of checksums of frames captured.
50332a15dd607c55ed227b47591facd637b86fcb801Mussa
50432a15dd607c55ed227b47591facd637b86fcb801Mussa        """
50532a15dd607c55ed227b47591facd637b86fcb801Mussa        return self.chameleond_proxy.GetCapturedChecksums(start_index,
50632a15dd607c55ed227b47591facd637b86fcb801Mussa                                                          stop_index)
50732a15dd607c55ed227b47591facd637b86fcb801Mussa
50832a15dd607c55ed227b47591facd637b86fcb801Mussa
50932a15dd607c55ed227b47591facd637b86fcb801Mussa    def get_captured_resolution(self):
51032a15dd607c55ed227b47591facd637b86fcb801Mussa        """
51132a15dd607c55ed227b47591facd637b86fcb801Mussa        @return: (width, height) tuple, the resolution of captured frames.
51232a15dd607c55ed227b47591facd637b86fcb801Mussa
51332a15dd607c55ed227b47591facd637b86fcb801Mussa        """
51432a15dd607c55ed227b47591facd637b86fcb801Mussa        return self.chameleond_proxy.GetCapturedResolution()
51532a15dd607c55ed227b47591facd637b86fcb801Mussa
51632a15dd607c55ed227b47591facd637b86fcb801Mussa
51732a15dd607c55ed227b47591facd637b86fcb801Mussa
5188578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tamclass ChameleonAudioInput(ChameleonPort):
5198578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam    """ChameleonAudioInput is an abstraction of an audio input port.
5208578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam
5218578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam    It contains some special methods to control an audio input.
5228578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam    """
5238578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam
5248578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam    def __init__(self, chameleon_port):
5258578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam        """Construct a ChameleonAudioInput.
5268578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam
5278578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam        @param chameleon_port: A general ChameleonPort object.
5288578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam        """
5298578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam        self.chameleond_proxy = chameleon_port.chameleond_proxy
5308578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam        self.port_id = chameleon_port.port_id
531c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam
532c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam
533e3bbd6188e6354b55bea1cad39004d587dbe7631Cheng-Yi Chiang    def start_capturing_audio(self):
534e3bbd6188e6354b55bea1cad39004d587dbe7631Cheng-Yi Chiang        """Starts capturing audio."""
5358578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam        return self.chameleond_proxy.StartCapturingAudio(self.port_id)
536e3bbd6188e6354b55bea1cad39004d587dbe7631Cheng-Yi Chiang
537e3bbd6188e6354b55bea1cad39004d587dbe7631Cheng-Yi Chiang
538e3bbd6188e6354b55bea1cad39004d587dbe7631Cheng-Yi Chiang    def stop_capturing_audio(self):
539e3bbd6188e6354b55bea1cad39004d587dbe7631Cheng-Yi Chiang        """Stops capturing audio.
540e3bbd6188e6354b55bea1cad39004d587dbe7631Cheng-Yi Chiang
541e3bbd6188e6354b55bea1cad39004d587dbe7631Cheng-Yi Chiang        Returns:
542b2f7b7dd0b6df2f88bcb8a333793cdc2e9b33cb7Cheng-Yi Chiang          A tuple (remote_path, format).
543b2f7b7dd0b6df2f88bcb8a333793cdc2e9b33cb7Cheng-Yi Chiang          remote_path: The captured file path on Chameleon.
544e3bbd6188e6354b55bea1cad39004d587dbe7631Cheng-Yi Chiang          format: A dict containing:
545e3bbd6188e6354b55bea1cad39004d587dbe7631Cheng-Yi Chiang            file_type: 'raw' or 'wav'.
546e3bbd6188e6354b55bea1cad39004d587dbe7631Cheng-Yi Chiang            sample_format: 'S32_LE' for 32-bit signed integer in little-endian.
547e3bbd6188e6354b55bea1cad39004d587dbe7631Cheng-Yi Chiang              Refer to aplay manpage for other formats.
548e3bbd6188e6354b55bea1cad39004d587dbe7631Cheng-Yi Chiang            channel: channel number.
549e3bbd6188e6354b55bea1cad39004d587dbe7631Cheng-Yi Chiang            rate: sampling rate.
550e3bbd6188e6354b55bea1cad39004d587dbe7631Cheng-Yi Chiang        """
551b2f7b7dd0b6df2f88bcb8a333793cdc2e9b33cb7Cheng-Yi Chiang        remote_path, data_format = self.chameleond_proxy.StopCapturingAudio(
5528578eeb003a7db21e0a4d85f0192fa45faf8ec80Tom Wai-Hong Tam                self.port_id)
553b2f7b7dd0b6df2f88bcb8a333793cdc2e9b33cb7Cheng-Yi Chiang        return remote_path, data_format
554e3bbd6188e6354b55bea1cad39004d587dbe7631Cheng-Yi Chiang
555e3bbd6188e6354b55bea1cad39004d587dbe7631Cheng-Yi Chiang
556d3fad2c8a0ba1508f5fc3efb90592687ec219d5cCheng-Yi Chiangclass ChameleonAudioOutput(ChameleonPort):
557d3fad2c8a0ba1508f5fc3efb90592687ec219d5cCheng-Yi Chiang    """ChameleonAudioOutput is an abstraction of an audio output port.
558d3fad2c8a0ba1508f5fc3efb90592687ec219d5cCheng-Yi Chiang
559d3fad2c8a0ba1508f5fc3efb90592687ec219d5cCheng-Yi Chiang    It contains some special methods to control an audio output.
560d3fad2c8a0ba1508f5fc3efb90592687ec219d5cCheng-Yi Chiang    """
561d3fad2c8a0ba1508f5fc3efb90592687ec219d5cCheng-Yi Chiang
562d3fad2c8a0ba1508f5fc3efb90592687ec219d5cCheng-Yi Chiang    def __init__(self, chameleon_port):
563d3fad2c8a0ba1508f5fc3efb90592687ec219d5cCheng-Yi Chiang        """Construct a ChameleonAudioOutput.
564d3fad2c8a0ba1508f5fc3efb90592687ec219d5cCheng-Yi Chiang
565d3fad2c8a0ba1508f5fc3efb90592687ec219d5cCheng-Yi Chiang        @param chameleon_port: A general ChameleonPort object.
566d3fad2c8a0ba1508f5fc3efb90592687ec219d5cCheng-Yi Chiang        """
567d3fad2c8a0ba1508f5fc3efb90592687ec219d5cCheng-Yi Chiang        self.chameleond_proxy = chameleon_port.chameleond_proxy
568d3fad2c8a0ba1508f5fc3efb90592687ec219d5cCheng-Yi Chiang        self.port_id = chameleon_port.port_id
569d3fad2c8a0ba1508f5fc3efb90592687ec219d5cCheng-Yi Chiang
570d3fad2c8a0ba1508f5fc3efb90592687ec219d5cCheng-Yi Chiang
57124a9b64a364a434167ceff8544bf188aa0c897e0Cheng-Yi Chiang    def start_playing_audio(self, path, data_format):
572d3fad2c8a0ba1508f5fc3efb90592687ec219d5cCheng-Yi Chiang        """Starts playing audio.
573d3fad2c8a0ba1508f5fc3efb90592687ec219d5cCheng-Yi Chiang
57424a9b64a364a434167ceff8544bf188aa0c897e0Cheng-Yi Chiang        @param path: The path to the file to play on Chameleon.
575d3fad2c8a0ba1508f5fc3efb90592687ec219d5cCheng-Yi Chiang        @param data_format: A dict containing data format. Currently Chameleon
576d3fad2c8a0ba1508f5fc3efb90592687ec219d5cCheng-Yi Chiang                            only accepts data format:
577d3fad2c8a0ba1508f5fc3efb90592687ec219d5cCheng-Yi Chiang                            dict(file_type='raw', sample_format='S32_LE',
578d3fad2c8a0ba1508f5fc3efb90592687ec219d5cCheng-Yi Chiang                                 channel=8, rate=48000).
579d3fad2c8a0ba1508f5fc3efb90592687ec219d5cCheng-Yi Chiang
580d3fad2c8a0ba1508f5fc3efb90592687ec219d5cCheng-Yi Chiang        """
58124a9b64a364a434167ceff8544bf188aa0c897e0Cheng-Yi Chiang        self.chameleond_proxy.StartPlayingAudio(self.port_id, path, data_format)
582d3fad2c8a0ba1508f5fc3efb90592687ec219d5cCheng-Yi Chiang
583d3fad2c8a0ba1508f5fc3efb90592687ec219d5cCheng-Yi Chiang
584d3fad2c8a0ba1508f5fc3efb90592687ec219d5cCheng-Yi Chiang    def stop_playing_audio(self):
585d3fad2c8a0ba1508f5fc3efb90592687ec219d5cCheng-Yi Chiang        """Stops capturing audio."""
586d3fad2c8a0ba1508f5fc3efb90592687ec219d5cCheng-Yi Chiang        self.chameleond_proxy.StopPlayingAudio(self.port_id)
587d3fad2c8a0ba1508f5fc3efb90592687ec219d5cCheng-Yi Chiang
588d3fad2c8a0ba1508f5fc3efb90592687ec219d5cCheng-Yi Chiang
589c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tamdef make_chameleon_hostname(dut_hostname):
590c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam    """Given a DUT's hostname, returns the hostname of its Chameleon.
591c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam
592c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam    @param dut_hostname: Hostname of a DUT.
593c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam
594c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam    @return Hostname of the DUT's Chameleon.
595c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam    """
596c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam    host_parts = dut_hostname.split('.')
597c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam    host_parts[0] = host_parts[0] + '-chameleon'
598c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam    return '.'.join(host_parts)
599c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam
600c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam
601c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tamdef create_chameleon_board(dut_hostname, args):
602c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam    """Given either DUT's hostname or argments, creates a ChameleonBoard object.
603c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam
604c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam    If the DUT's hostname is in the lab zone, it connects to the Chameleon by
605c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam    append the hostname with '-chameleon' suffix. If not, checks if the args
606c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam    contains the key-value pair 'chameleon_host=IP'.
607c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam
608c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam    @param dut_hostname: Hostname of a DUT.
609c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam    @param args: A string of arguments passed from the command line.
610c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam
611c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam    @return A ChameleonBoard object.
612c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam
613c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam    @raise ChameleonConnectionError if unknown hostname.
614c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam    """
615c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam    connection = None
616c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam    hostname = make_chameleon_hostname(dut_hostname)
617c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam    if utils.host_is_in_lab_zone(hostname):
618c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam        connection = ChameleonConnection(hostname)
619c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam    else:
620c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam        args_dict = utils.args_to_dict(args)
621c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam        hostname = args_dict.get('chameleon_host', None)
622c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam        port = args_dict.get('chameleon_port', CHAMELEON_PORT)
623c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam        if hostname:
624c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam            connection = ChameleonConnection(hostname, port)
625c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam        else:
626c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam            raise ChameleonConnectionError('No chameleon_host is given in args')
627c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam
628c3fb2f6ce00d4dad5c5f6478a6fb650dfd89f42cTom Wai-Hong Tam    return ChameleonBoard(connection)
629