Home | History | Annotate | Download | only in firmware_PDVbusRequest
      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 
      5 import logging
      6 import math
      7 import time
      8 
      9 from autotest_lib.client.common_lib import error
     10 from autotest_lib.server.cros.faft.firmware_test import FirmwareTest
     11 from autotest_lib.server.cros.servo import pd_console
     12 
     13 
     14 class firmware_PDVbusRequest(FirmwareTest):
     15     """
     16     Servo based USB PD VBUS level test. This test is written to use both
     17     the DUT and Plankton test board. It requires that the DUT support
     18     dualrole (SRC or SNK) operation. VBUS change requests occur in two
     19     methods. First, with the DUT in SNK mode, it uses the pd console command
     20     'pd 0/1 dev V' command where V is the desired voltage 5/12/20. The 2nd
     21     test initiates the VBUS change by using special Plankton feature to
     22     send new SRC CAP message. This causes the DUT to request a new VBUS
     23     voltage mathcing what's in the SRC CAP message.
     24 
     25     Pass critera is all voltage transitions are successful.
     26 
     27     """
     28     version = 1
     29 
     30     PD_SETTLE_DELAY = 4
     31     USBC_SINK_VOLTAGE = 5
     32     USBC_MAX_VOLTAGE = 20
     33     VBUS_TOLERANCE = 0.12
     34 
     35     VOLTAGE_SEQUENCE = [5, 12, 20, 12, 5, 20, 5, 5, 12, 12, 20]
     36 
     37     def _compare_vbus(self, expected_vbus_voltage):
     38         """Check VBUS using plankton
     39 
     40         @param expected_vbus_voltage: nominal VBUS level (in volts)
     41 
     42         @returns: a tuple containing pass/fail indication and logging string
     43         """
     44         # Get Vbus voltage and current
     45         vbus_voltage = self.plankton.vbus_voltage
     46         vbus_current = self.plankton.vbus_current
     47         # Compute voltage tolerance range
     48         tolerance = self.VBUS_TOLERANCE * expected_vbus_voltage
     49         voltage_difference = math.fabs(expected_vbus_voltage - vbus_voltage)
     50         result_str = 'Target = %02dV:\tAct = %.2f\tDelta = %.2f' % \
     51                      (expected_vbus_voltage, vbus_voltage, voltage_difference)
     52         # Verify that measured Vbus voltage is within expected range
     53         voltage_difference = math.fabs(expected_vbus_voltage - vbus_voltage)
     54         if voltage_difference > tolerance:
     55             result = 'FAIL'
     56         else:
     57             result = 'PASS'
     58         return result, result_str
     59 
     60     def initialize(self, host, cmdline_args):
     61         super(firmware_PDVbusRequest, self).initialize(host, cmdline_args)
     62         # Only run in normal mode
     63         self.switcher.setup_mode('normal')
     64         self.usbpd.send_command('chan 0')
     65 
     66     def cleanup(self):
     67         self.usbpd.send_command('chan 0xffffffff')
     68         super(firmware_PDVbusRequest, self).cleanup()
     69 
     70     def run_once(self):
     71         """Exectue VBUS request test.
     72 
     73         """
     74 
     75         # create objects for pd utilities
     76         pd_dut_utils = pd_console.PDConsoleUtils(self.usbpd)
     77         pd_plankton_utils = pd_console.PDConsoleUtils(self.plankton)
     78 
     79         # Make sure PD support exists in the UART console
     80         if pd_dut_utils.verify_pd_console() == False:
     81             raise error.TestFail("pd command not present on console!")
     82 
     83         # Type C connection (PD contract) should exist at this point
     84         dut_state = pd_dut_utils.query_pd_connection()
     85         logging.info('DUT PD connection state: %r', dut_state)
     86         if dut_state['connect'] == False:
     87             raise error.TestFail("pd connection not found")
     88         if dut_state['role'] != pd_dut_utils.SNK_CONNECT:
     89             # DUT needs to be in SINK Mode, attempt to force change
     90             pd_dut_utils.set_pd_dualrole('snk')
     91             time.sleep(self.PD_SETTLE_DELAY)
     92             if pd_dut_utils.get_pd_state(dut_state['port']) != pd_dut_utils.SNK_CONNECT:
     93                 raise error.TestFail("DUT not able to connect in SINK mode")
     94 
     95         # Plankton must be set to 20V SRC mode in order for the DUT
     96         # to be able to request all 3 possible voltage levels (5, 12, 20).
     97         # The DUT must be in SNK mode for the pd <port> dev <voltage>
     98         # command to have an effect.
     99         self.plankton.charge(self.USBC_MAX_VOLTAGE)
    100         time.sleep(self.PD_SETTLE_DELAY)
    101         logging.info('Start of DUT initiated tests')
    102         dut_failures = []
    103         for v in self.VOLTAGE_SEQUENCE:
    104             # Build 'pd <port> dev <voltage> command
    105             cmd = 'pd %d dev %d' % (dut_state['port'], v)
    106             pd_dut_utils.send_pd_command(cmd)
    107             time.sleep(self.PD_SETTLE_DELAY)
    108             result, result_str = self._compare_vbus(v)
    109             logging.info('%s, %s', result_str, result)
    110             if result == 'FAIL':
    111                 dut_failures.append(result_str)
    112 
    113         # Make sure Plankton is set back to 20VSRC so DUT will accept all options
    114         cmd = 'pd %d dev %d' % (dut_state['port'], self.USBC_MAX_VOLTAGE)
    115         time.sleep(self.PD_SETTLE_DELAY)
    116         # The next group of tests need DUT to connect in SNK and SRC modes
    117         pd_dut_utils.set_pd_dualrole('on')
    118 
    119         plankton_failures = []
    120         logging.info('Start Plankton initiated tests')
    121         for voltage in self.plankton.get_charging_voltages():
    122             logging.info('********* %r *********', voltage)
    123             # Set charging voltage
    124             self.plankton.charge(voltage)
    125             # Wait for new PD contract to be established
    126             time.sleep(self.PD_SETTLE_DELAY)
    127             # Get current Plankton PD state
    128             plankton_state = pd_plankton_utils.get_pd_state(0)
    129             expected_vbus_voltage = self.plankton.charging_voltage
    130             # If Plankton is sink, then Vbus_exp = 5v
    131             if plankton_state == pd_plankton_utils.SNK_CONNECT:
    132                 expected_vbus_voltage = self.USBC_SINK_VOLTAGE
    133             result, result_str = self._compare_vbus(expected_vbus_voltage)
    134             logging.info('%s, %s', result_str, result)
    135             if result == 'FAIL':
    136                 plankton_failures.append(result_str)
    137 
    138         if dut_failures:
    139             logging.error('DUT voltage request failures')
    140             for fail in dut_failures:
    141                 logging.error('%s', fail)
    142 
    143         if plankton_failures:
    144             logging.error('Plankton voltage source cap failures')
    145             for fail in plankton_failures:
    146                 logging.error('%s', fail)
    147 
    148         if dut_failures or plankton_failures:
    149             if dut_failures and plankton_failures:
    150                 test = 'DUT and Plankton'
    151                 number = len(dut_failures) + len(plankton_failures)
    152             elif dut_failures:
    153                 test = 'DUT'
    154                 number = len(dut_failures)
    155             else:
    156                 test = 'Plankton'
    157                 number = len(plankton_failures)
    158             raise error.TestFail('%s failed %d times' % (test, number))
    159