| # Copyright 2015 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import logging |
| |
| from autotest_lib.client.common_lib import error |
| from autotest_lib.server.cros.faft.firmware_test import FirmwareTest |
| from autotest_lib.server.cros.servo import pd_device |
| |
| |
| class firmware_PDConnect(FirmwareTest): |
| """ |
| Servo based USB PD connect/disconnect test. If PDTester is not one |
| of the device pair elements, then this test requires that at least |
| one of the devices support dual role mode in order to force a disconnect |
| to connect sequence. The test does not depend on the DUT acting as source |
| or sink, either mode should pass. |
| |
| Pass critera is 100% of connections resulting in successful connections |
| """ |
| version = 1 |
| CONNECT_ITERATIONS = 10 |
| def _test_connect(self, port_pair, dts_mode): |
| """Tests disconnect/connect sequence |
| |
| @param port_pair: list of 2 connected PD devices |
| @param dts_mode: the test is under DTS mode? |
| """ |
| # Delay in seconds between disconnect and connect commands |
| RECONNECT_DELAY = 10 |
| for dev in port_pair: |
| if dts_mode and not dev.is_pdtester: |
| logging.info('If DUT in DTS mode, it is always connected. ' |
| 'Unable to set it disconnected; skip this item.') |
| continue |
| |
| for attempt in xrange(self.CONNECT_ITERATIONS): |
| logging.info('Disconnect/Connect iteration %d', attempt) |
| try: |
| if dev.drp_disconnect_connect(RECONNECT_DELAY) == False: |
| raise error.TestFail('Disconnect/Connect Failed') |
| except NotImplementedError: |
| logging.warn('Device does not support disconnect/connect') |
| break |
| |
| def initialize(self, host, cmdline_args, flip_cc=False, dts_mode=False): |
| super(firmware_PDConnect, self).initialize(host, cmdline_args) |
| self.setup_pdtester(flip_cc, dts_mode) |
| # Only run in normal mode |
| self.switcher.setup_mode('normal') |
| self.usbpd.enable_console_channel('usbpd') |
| |
| |
| def cleanup(self): |
| self.usbpd.send_command('chan 0xffffffff') |
| super(firmware_PDConnect, self).cleanup() |
| |
| |
| def run_once(self, dts_mode=False): |
| """Exectue disconnect/connect sequence test |
| |
| """ |
| |
| # Create list of available UART consoles |
| consoles = [self.usbpd, self.pdtester] |
| port_partner = pd_device.PDPortPartner(consoles) |
| # Identify a valid test port pair |
| port_pair = port_partner.identify_pd_devices() |
| if not port_pair: |
| raise error.TestFail('No PD connection found!') |
| |
| # Test disconnect/connect sequences |
| self._test_connect(port_pair, dts_mode) |
| |
| # Swap power roles (if possible). Note the pr swap is attempted |
| # for both devices in the connection. This ensures that a device |
| # such as Plankton, which is dualrole capable, but has this mode |
| # disabled by default, won't prevent the device pair from role swapping. |
| swappable_dev = None; |
| for dev in port_pair: |
| try: |
| if dev.pr_swap(): |
| swappable_dev = dev |
| break |
| except NotImplementedError: |
| logging.warn('Power role swap not supported on the device') |
| |
| if swappable_dev: |
| try: |
| # Power role has been swapped, retest. |
| self._test_connect(port_pair, dts_mode) |
| finally: |
| # Swap power role again, back to the original |
| if not swappable_dev.pr_swap(): |
| logging.error('Failed to swap power role to the original') |
| else: |
| logging.warn('Device pair could not perform power role swap, ' |
| 'ending test') |