• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2016 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
5import logging
6import random
7import time
8
9from autotest_lib.client.common_lib import error
10from autotest_lib.server.cros.faft.firmware_test import FirmwareTest
11from autotest_lib.server.cros.servo import pd_device
12
13
14class firmware_PDTrySrc(FirmwareTest):
15    """
16    Servo based USB PD Try.SRC protocol test.
17
18    When a PD device supports Try.SRC mode and it's enabled, it will attempt
19    to always connect as a SRC device. This test is therefore only applicable
20    if both devices support dualrole and at least one device supports Try.SRC.
21
22    Pass criteria is that when Try.SRC is enabled the device connects > 95% of
23    the time in SRC mode. When it is disabled, there must be at least 25%
24    variation in connecting as SRC and SNK.
25    """
26    version = 1
27
28    CONNECT_ITERATIONS = 20
29    PD_DISCONNECT_TIME = 1
30    PD_CONNECT_DELAY = 4
31    SNK = 0
32    SRC = 1
33    TRYSRC_OFF_THRESHOLD = 15.0
34    TRYSRC_ON_THRESHOLD = 96.0
35
36    def _execute_connect_sequence(self, device):
37        """Execute mulitple connections and track power role
38
39        This method will disconnect/connect a TypeC PD port and
40        collect the power role statistics of each connection. The time
41        delay for reconnect adds a random delay so that test to increase
42        randomness for dualrole swaps.
43
44        @param device: PD device object
45
46        @returns list with number of SNK and SRC connections
47        """
48        stats = [0, 0]
49        random.seed()
50        # Try N disconnect/connects
51        for attempt in xrange(self.CONNECT_ITERATIONS):
52            try:
53                # Disconnect time from 1 to 2 seconds
54                disc_time = self.PD_DISCONNECT_TIME + random.random()
55                logging.info('Disconnect time = %.2f seconds', disc_time)
56                # Force disconnect/connect
57                device.cc_disconnect_connect(disc_time)
58                # Wait for connection to be reestablished
59                time.sleep(self.PD_DISCONNECT_TIME + self.PD_CONNECT_DELAY)
60                # Check power role and update connection stats
61                if device.is_snk():
62                    stats[self.SNK] += 1;
63                    logging.info('Power Role = SNK')
64                elif device.is_src():
65                    stats[self.SRC] += 1;
66                    logging.info('Power Role = SRC')
67            except NotImplementedError:
68                raise error.TestFail('TrySRC disconnect requires Plankton')
69        logging.info('SNK = %d: SRC = %d: Total = %d',
70                     stats[0], stats[1], self.CONNECT_ITERATIONS)
71        return stats
72
73    def initialize(self, host, cmdline_args):
74        super(firmware_PDTrySrc, self).initialize(host, cmdline_args)
75        # Only run in normal mode
76        self.switcher.setup_mode('normal')
77        # Turn off console prints, except for USBPD.
78        self.usbpd.send_command('chan 0x08000000')
79
80    def cleanup(self):
81        self.usbpd.send_command('chan 0xffffffff')
82        super(firmware_PDTrySrc, self).cleanup()
83
84    def run_once(self):
85        """Execute Try.SRC PD protocol test
86
87        1. Verify that DUT <-> Plankton device pair exists
88        2. Verify that DUT supports dualrole
89        3. Verify that DUT supports Try.SRC mode
90        4. Enable Try.SRC mode, execute disc/connect sequences
91        5. Disable Try.SRC mode, execute disc/connect sequences
92        6. Compute DUT SRC/SNK connect ratios for both modes
93        7. Compare SRC connect ratio to threholds to determine pass/fail
94        """
95
96        # Create list of available UART consoles
97        consoles = [self.usbpd, self.plankton]
98        port_partner = pd_device.PDPortPartner(consoles)
99        # Identify Plankton <-> DUT PD device pair
100        port_pair = port_partner.identify_pd_devices()
101        if not port_pair:
102            raise error.TestFail('No DUT to Plankton connection found!')
103
104        # TODO Device pair must have Plankton so that the disconnect/connect
105        # sequence does not affect the SRC/SNK connection. Plankton provides
106        # a 'fake_disconnect' feature which more closely resembles unplugging
107        # and replugging a Type C cable.
108
109        # Both devices must support dualrole mode for this test. In addtion,
110        # at least one device must support Try.SRC mode.
111        for side in xrange(len(port_pair)):
112            try:
113                if not port_pair[side].drp_set('on'):
114                    raise error.TestFail('Could not enable DRP')
115            except NotImplementedError:
116                raise error.TestFail('Both devices must support DRP')
117            if port_pair[side].is_plankton:
118                # Identify Plankton and DUT device
119                p_idx = side
120                d_idx = side ^ 1
121
122        # Make sure that DUT supports Try.SRC mode
123        if not port_pair[d_idx].try_src(True):
124            raise error.TestFail('DUT does not support Try.SRC feature')
125        # Run disconnect/connect sequence with Try.SRC enabled
126        stats_on = self._execute_connect_sequence(port_pair[p_idx])
127        # Disable Try.SRC mode
128        port_pair[d_idx].try_src(False)
129        # Run disconnect/connect sequence with Try.SRC disabled
130        stats_off = self._execute_connect_sequence(port_pair[p_idx])
131        # Reenable Try.SRC mode
132        port_pair[d_idx].try_src(True)
133
134        # Compute SRC connect ratio/percent for Try.SRC on and off cases
135        total_on = float(stats_on[self.SNK] + stats_on[self.SRC])
136        total_off = float(stats_off[self.SNK] + stats_off[self.SRC])
137        trysrc_on = float(stats_on[self.SNK]) / total_on * 100.0
138        trysrc_off = float(stats_off[self.SNK]) / total_off * 100.0
139        logging.info('DUT Try.SRC on = %.1f%%: off = %.1f%%',
140                      trysrc_off, trysrc_on)
141
142        # When Try.SRC is off, ideally the SNK/SRC ratio will be close to
143        # 50%. However, in practice there is a wide range related to the
144        # dualrole swap timers in firmware.
145        if (trysrc_off < self.TRYSRC_OFF_THRESHOLD or
146            trysrc_off > 100 - self.TRYSRC_OFF_THRESHOLD):
147            raise error.TestFail('SRC %% = %.1f: Must be > %.1f & < %.1f' %
148                                 (trysrc_off, self.TRYSRC_OFF_THRESHOLD,
149                                  100 - self.TRYSRC_OFF_THRESHOLD))
150        # When Try.SRC is on, the SRC/SNK, the DUT should connect in SRC
151        # mode nearly 100% of the time.
152        if trysrc_on < self.TRYSRC_ON_THRESHOLD:
153            raise error.TestFail('SRC %% = %.1f: Must be >  %.1f' %
154                                 (trysrc_on, self.TRYSRC_ON_THRESHOLD))
155
156