1# Copyright 2015 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""This is a USB type C USB3 probing test using PDTester board."""
6
7import logging
8import re
9
10from autotest_lib.client.bin import utils
11from autotest_lib.client.common_lib import error
12from autotest_lib.server.cros.faft.firmware_test import FirmwareTest
13
14class firmware_TypeCProbeUSB3(FirmwareTest):
15    """USB type C USB3 probing test."""
16    version = 1
17
18    RE_SUPERSPEED_DEVICE = r' Port \d+: .+, 5000M$'
19    CHARGING_VOLTAGE = 12
20    SINK = 0
21    POLL_USB3_SECS = 10
22
23
24    def get_usb_devices_and_buses(self):
25        """Gets set from the list of USB devices and buses."""
26        result = self.pdtester_host.run_short('lsusb -t')
27        return set(result.stdout.splitlines())
28
29
30    def is_superspeed(self, lsusb_line):
31        """Checks if the lsusb output contains 5000M."""
32        return re.search(self.RE_SUPERSPEED_DEVICE, lsusb_line)
33
34
35    def run_once(self):
36        """Checks DUT USB3 device.
37
38        @raise TestFail: If USB3 can't be found when switch to USB mode.
39        """
40        # Enumerate USB devices when charging.
41        self.pdtester.charge(self.CHARGING_VOLTAGE)
42        devices_charging = self.get_usb_devices_and_buses()
43        logging.info('number of devices while charging: %d',
44                     len(devices_charging))
45        # Enumerate USB devices when switching to DP.
46        self.pdtester.set_usbc_mux('dp')
47        self.pdtester.charge(self.SINK)
48        self.pdtester.poll_pd_state('sink')
49        devices_dp = self.get_usb_devices_and_buses()
50        self.pdtester.charge(self.CHARGING_VOLTAGE)
51        logging.info('number of devices when switch to dp: %d',
52                     len(devices_dp))
53        # Enumerate USB devices when switching to USB3
54        self.pdtester.set_usbc_mux('usb')
55        self.pdtester.charge(self.SINK)
56        self.pdtester.poll_pd_state('sink')
57        # It takes a short period for DUT to get USB3.0 device.
58        utils.poll_for_condition(
59            lambda: len(self.get_usb_devices_and_buses()) > len(devices_dp),
60            exception=error.TestFail(
61                    'Can\'t find new device when switching to USB '
62                    'after %d seconds' % self.POLL_USB3_SECS),
63            timeout=self.POLL_USB3_SECS)
64        devices_usb = self.get_usb_devices_and_buses()
65        self.pdtester.charge(self.CHARGING_VOLTAGE)
66        logging.info('number of devices when switch to usb: %d',
67                     len(devices_usb))
68
69        # For Samus USB2.0 signal power swap while usbc_role changes due to
70        # lack of UFP. Port number of lsusb may change since the device is
71        # disconnected for a short period.
72        if len(devices_dp) != len(devices_charging):
73            raise error.TestFail(
74                    'Number of USB devices changed on switching to DP')
75
76        if not any(map(self.is_superspeed, devices_usb - devices_dp)):
77            raise error.TestFail('Can\'t find new USB3 device')
78