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 re 7 8 from collections import defaultdict 9 10 from autotest_lib.client.common_lib import error 11 from autotest_lib.server.cros.faft.firmware_test import FirmwareTest 12 13 class firmware_PDProtocol(FirmwareTest): 14 """ 15 Servo based USB PD protocol test. 16 17 A charger must be connected to the DUT for this test. 18 19 This test checks that when an appropriate zinger charger is connected that 20 the PD is properly negotiated in dev mode and when booted from a test image 21 through recovery that the PD is not negotiated. 22 23 Example: 24 PD Successfully negotiated 25 - ectool usbpdpower should output Charger PD 26 27 PD not negotiated 28 - ectool usbpdpower should not output Charger PD 29 30 """ 31 version = 1 32 33 NEGOTIATED_PATTERN = 'Charger PD' 34 PD_NOT_SUPPORTED_PATTERN = 'INVALID_COMMAND' 35 36 ECTOOL_CMD_DICT = defaultdict(lambda: 'ectool usbpdpower') 37 38 def initialize(self, host, cmdline_args): 39 super(firmware_PDProtocol, self).initialize(host, cmdline_args) 40 41 self.ECTOOL_CMD_DICT['samus'] = 'ectool --dev=1 usbpdpower' 42 43 self.current_board = self.servo.get_board(); 44 45 self.check_if_pd_supported() 46 self.assert_test_image_in_usb_disk() 47 self.switcher.setup_mode('dev') 48 self.setup_usbkey(usbkey=True, host=False) 49 50 self.original_dev_boot_usb = self.faft_client.system.get_dev_boot_usb() 51 logging.info('Original dev_boot_usb value: %s', 52 str(self.original_dev_boot_usb)) 53 54 def cleanup(self): 55 self.ensure_internal_device_boot() 56 super(firmware_PDProtocol, self).cleanup() 57 58 def check_if_pd_supported(self): 59 """ Checks if the DUT responds to ectool usbpdpower and skips the test 60 if it isn't supported on the device. 61 """ 62 output = self.run_command(self.ECTOOL_CMD_DICT[self.current_board]) 63 64 if (not output or 65 self.check_ec_output(output, self.PD_NOT_SUPPORTED_PATTERN)): 66 raise error.TestNAError("PD not supported skipping test.") 67 68 def ensure_internal_device_boot(self): 69 """Ensure internal device boot; if not, reboot into it. 70 71 If not, it may be a test failure during step 2 or 3, try to reboot 72 and press Ctrl-D to internal device boot. 73 """ 74 if self.faft_client.system.is_removable_device_boot(): 75 logging.info('Reboot into internal disk...') 76 self.faft_client.system.set_dev_boot_usb(self.original_dev_boot_usb) 77 self.switcher.mode_aware_reboot() 78 79 self.check_state((self.checkers.dev_boot_usb_checker, 80 False, 81 'Did not boot from internal disk.')) 82 83 def boot_to_recovery(self): 84 """Boot device into recovery mode.""" 85 logging.info('Reboot into Recovery...') 86 self.assert_test_image_in_usb_disk() 87 self.switcher.reboot_to_mode(to_mode='rec') 88 89 self.check_state((self.checkers.crossystem_checker, 90 {'mainfw_type': 'recovery'})) 91 92 def run_command(self, command): 93 """Runs the specified command and returns the output 94 as a list of strings. 95 96 @param command: The command to run on the DUT 97 @return A list of strings of the command output 98 """ 99 logging.info('Command to run: %s', command) 100 101 output = self.faft_client.system.run_shell_command_get_output(command) 102 103 logging.info('Command output: %s', output) 104 105 return output 106 107 def check_ec_output(self, output, pattern): 108 """Checks if any line in the output matches the given pattern. 109 110 @param output: A list of strings containg the output to search 111 @param pattern: The regex to search the output for 112 113 @return True upon first match found or False 114 """ 115 logging.info('Checking %s for %s.', output, pattern) 116 117 for line in output: 118 if bool(re.search(pattern, line)): 119 return True 120 121 return False 122 123 124 def run_once(self): 125 self.ensure_internal_device_boot() 126 output = self.run_command(self.ECTOOL_CMD_DICT[self.current_board]) 127 128 if not self.check_ec_output(output, self.NEGOTIATED_PATTERN): 129 raise error.TestFail( 130 'ectool usbpdpower output %s did not match %s', 131 (output, self.NEGOTIATED_PATTERN)) 132 133 134 self.boot_to_recovery() 135 output = self.run_command(self.ECTOOL_CMD_DICT[self.current_board]) 136 137 if self.check_ec_output(output, self.NEGOTIATED_PATTERN): 138 raise error.TestFail( 139 'ectool usbpdpower output %s matched %s', 140 (output, self.NEGOTIATED_PATTERN)) 141 142