xref: /aosp_15_r20/external/autotest/server/site_tests/display_Resolution/display_Resolution.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1# Lint as: python2, python3
2# Copyright 2014 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""This is a server side resolution display test using the Chameleon board."""
7
8import logging
9import os
10import time
11
12from autotest_lib.client.bin import utils
13from autotest_lib.client.common_lib import error
14from autotest_lib.client.cros.chameleon import chameleon_port_finder
15from autotest_lib.client.cros.chameleon import chameleon_screen_test
16from autotest_lib.client.cros.chameleon import edid
17from autotest_lib.server import test
18from autotest_lib.server.cros.multimedia import remote_facade_factory
19
20
21class display_Resolution(test.test):
22    """Server side external display test.
23
24    This test talks to a Chameleon board and a DUT to set up, run, and verify
25    external display function of the DUT.
26    """
27    version = 1
28
29    # Allowed timeout for reboot.
30    REBOOT_TIMEOUT = 30
31    # Time to allow lid transition to take effect
32    WAIT_TIME_LID_TRANSITION = 5
33
34    DEFAULT_RESOLUTION_LIST = [
35            ('EDIDv1', 1280, 800),
36            ('EDIDv1', 1440, 900),
37            ('EDIDv1', 1600, 900),
38            ('EDIDv1', 1680, 1050),
39            ('EDIDv2', 1280, 720),
40            ('EDIDv2', 1920, 1080),
41    ]
42    # These boards are unable to work with servo - crosbug.com/p/27591.
43    INCOMPATIBLE_SERVO_BOARDS = ['daisy', 'falco']
44
45    # These boards and EDID resolutions are not compatible -crbug.com/905415
46    INCOMPATIBLE_EDID_RESOLUTION_LIST =  [
47           ('EDIDv1', 1280, 800),
48           ('EDIDv1', 1600, 900),
49    ]
50    INCOMPATIBLE_EDID_BOARDS = ['coral', 'eve', 'grunt', 'nami', 'rammus',
51        'zork']
52
53    def run_once(self, host, test_mirrored=False, test_suspend_resume=False,
54                 test_reboot=False, test_lid_close_open=False,
55                 resolution_list=None):
56        """Check conditions, do setup and run test.
57        """
58
59        # Check the servo object.
60        if test_lid_close_open and host.servo is None:
61            raise error.TestError('Invalid servo object found on the host.')
62        if test_lid_close_open and not host.get_board_type() == 'CHROMEBOOK':
63            raise error.TestNAError('DUT is not Chromebook. Test Skipped')
64        if test_mirrored and not host.get_board_type() == 'CHROMEBOOK':
65            raise error.TestNAError('DUT is not Chromebook. Test Skipped')
66
67        # Check for incompatible with servo chromebooks.
68        board_name = host.get_board().split(':')[1]
69        if board_name in self.INCOMPATIBLE_SERVO_BOARDS:
70            raise error.TestNAError(
71                    'DUT is incompatible with servo. Skipping test.')
72
73        self.host = host
74        factory = remote_facade_factory.RemoteFacadeFactory(host)
75        display_facade = factory.create_display_facade()
76        chameleon_board = host.chameleon
77
78        chameleon_board.setup_and_reset(self.outputdir)
79        finder = chameleon_port_finder.ChameleonVideoInputFinder(
80                chameleon_board, display_facade)
81
82        errors = []
83        if resolution_list is None:
84            resolution_list = self.DEFAULT_RESOLUTION_LIST
85
86        # Remove board specific incompatible EDIDs.
87        if board_name.replace('-kernelnext', '') in \
88            self.INCOMPATIBLE_EDID_BOARDS:
89            for edid_value in self.INCOMPATIBLE_EDID_RESOLUTION_LIST:
90                if edid_value in resolution_list:
91                    resolution_list.remove(edid_value)
92
93        chameleon_supported = True
94        for chameleon_port in finder.iterate_all_ports():
95            screen_test = chameleon_screen_test.ChameleonScreenTest(
96                    host, chameleon_port, display_facade, self.outputdir)
97            chameleon_port_name = chameleon_port.get_connector_type()
98            logging.info('Detected %s chameleon port.', chameleon_port_name)
99            for label, width, height in resolution_list:
100                test_resolution = (width, height)
101                test_name = "%s_%dx%d" % ((label,) + test_resolution)
102
103                # The chameleon DP RX doesn't support 4K resolution.
104                # The max supported resolution is 2560x1600.
105                # See crbug/585900
106                if (chameleon_port_name.startswith('DP') and
107                    test_resolution > (2560,1600)):
108                    chameleon_supported = False
109
110                if not edid.is_edid_supported(host, width, height):
111                    logging.info('Skip unsupported EDID: %s', test_name)
112                    continue
113
114                if test_lid_close_open:
115                    logging.info('Close lid...')
116                    host.servo.lid_close()
117                    time.sleep(self.WAIT_TIME_LID_TRANSITION)
118
119                if test_reboot:
120                    # Unplug the monitor explicitly. Otherwise, the following
121                    # use_edid_file() call would expect a valid video signal,
122                    # which is not true during reboot.
123                    chameleon_port.unplug()
124                    logging.info('Reboot...')
125                    boot_id = host.get_boot_id()
126                    host.reboot(wait=False)
127                    host.test_wait_for_shutdown(self.REBOOT_TIMEOUT)
128
129                path = os.path.join(self.bindir, 'test_data', 'edids',
130                                    test_name)
131                logging.info('Use EDID: %s', test_name)
132                with chameleon_port.use_edid_file(path):
133                    if test_lid_close_open:
134                        logging.info('Open lid...')
135                        host.servo.lid_open()
136                        time.sleep(self.WAIT_TIME_LID_TRANSITION)
137
138                    if test_reboot:
139                        host.test_wait_for_boot(boot_id)
140                        chameleon_port.plug()
141
142                    utils.wait_for_value_changed(
143                            display_facade.get_external_connector_name,
144                            old_value=False)
145
146                    logging.info('Set mirrored: %s', test_mirrored)
147                    display_facade.set_mirrored(test_mirrored)
148                    if test_suspend_resume:
149                        if test_mirrored:
150                            # magic sleep to wake up nyan_big in mirrored mode
151                            # TODO: find root cause
152                            time.sleep(6)
153                        logging.info('Going to suspend...')
154                        display_facade.suspend_resume()
155                        logging.info('Resumed back')
156
157                    screen_test.test_screen_with_image(test_resolution,
158                            test_mirrored, errors, chameleon_supported)
159
160        if errors:
161            raise error.TestFail('; '.join(set(errors)))
162
163    def cleanup(self):
164        """Test cleanup"""
165        # Keep device in lid open sate.
166        if self.host.servo:
167            logging.info('Open lid...')
168            self.host.servo.lid_open()
169            time.sleep(self.WAIT_TIME_LID_TRANSITION)
170