1# Copyright (c) 2012 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 5from threading import Timer 6import logging 7import re 8import time 9 10from autotest_lib.client.common_lib import error 11from autotest_lib.server.cros.faft.firmware_test import FirmwareTest 12 13 14def delayed(seconds): # pylint:disable=missing-docstring 15 def decorator(f): # pylint:disable=missing-docstring 16 def wrapper(*args, **kargs): # pylint:disable=missing-docstring 17 t = Timer(seconds, f, args, kargs) 18 t.start() 19 return wrapper 20 return decorator 21 22 23class firmware_ECLidSwitch(FirmwareTest): 24 """ 25 Servo based EC lid switch test. 26 """ 27 version = 1 28 29 # Delay between closing and opening the lid 30 LID_DELAY = 1 31 32 # Delay to allow FAFT client receive command 33 RPC_DELAY = 2 34 35 # Delay between shutdown and wakeup by lid switch 36 WAKE_DELAY = 10 37 38 def initialize(self, host, cmdline_args): 39 super(firmware_ECLidSwitch, self).initialize(host, cmdline_args) 40 # Only run in normal mode 41 self.switcher.setup_mode('normal') 42 43 def _open_lid(self): 44 """Open lid by servo.""" 45 self.servo.set('lid_open', 'yes') 46 47 def _close_lid(self): 48 """Close lid by servo.""" 49 self.servo.set('lid_open', 'no') 50 51 @delayed(RPC_DELAY) 52 def delayed_open_lid(self): 53 """Delay by RPC_DELAY and then open lid by servo.""" 54 self._open_lid() 55 56 @delayed(RPC_DELAY) 57 def delayed_close_lid(self): 58 """Delay by RPC_DELAY and then close lid by servo.""" 59 self._close_lid() 60 61 def _wake_by_lid_switch(self): 62 """Wake DUT with lid switch.""" 63 self._close_lid() 64 time.sleep(self.LID_DELAY) 65 self._open_lid() 66 67 def delayed_wake(self): 68 """ 69 Confirm the device is in G3, wait for WAKE_DELAY, and then wake DUT 70 with lid switch. 71 """ 72 self.check_shutdown_power_state(self.POWER_STATE_G3, pwr_retries=10) 73 time.sleep(self.WAKE_DELAY) 74 self._wake_by_lid_switch() 75 76 def immediate_wake(self): 77 """Confirm the device is in G3 and then wake DUT with lid switch.""" 78 self.check_shutdown_power_state(self.POWER_STATE_G3, pwr_retries=10) 79 self._wake_by_lid_switch() 80 81 def shutdown_and_wake(self, shutdown_func, wake_func): 82 """Software shutdown and wake. 83 84 Args: 85 shutdown_func: Function to shut down DUT. 86 wake_func: Delayed function to wake DUT. 87 """ 88 shutdown_func() 89 wake_func() 90 91 def _get_keyboard_backlight(self): 92 """Get keyboard backlight brightness. 93 94 Returns: 95 Backlight brightness percentage 0~100. If it is disabled, 0 is 96 returned. 97 """ 98 cmd = 'ectool pwmgetkblight' 99 pattern_percent = re.compile( 100 'Current keyboard backlight percent: (\d*)') 101 pattern_disable = re.compile('Keyboard backlight disabled.') 102 lines = self.faft_client.system.run_shell_command_get_output(cmd) 103 for line in lines: 104 matched_percent = pattern_percent.match(line) 105 if matched_percent is not None: 106 return int(matched_percent.group(1)) 107 matched_disable = pattern_disable.match(line) 108 if matched_disable is not None: 109 return 0 110 raise error.TestError('Cannot get keyboard backlight status.') 111 112 def _set_keyboard_backlight(self, value): 113 """Set keyboard backlight brightness. 114 115 Args: 116 value: Backlight brightness percentage 0~100. 117 """ 118 cmd = 'ectool pwmsetkblight %d' % value 119 self.faft_client.system.run_shell_command(cmd) 120 121 def check_keycode(self): 122 """Check that lid open/close do not send power button keycode. 123 124 Returns: 125 True if no power button keycode is captured. Otherwise, False. 126 """ 127 # Don't check the keycode if we don't have a keyboard. 128 if not self.check_ec_capability(['keyboard'], suppress_warning=True): 129 return True 130 131 self._open_lid() 132 self.delayed_close_lid() 133 if self.faft_client.system.check_keys([]) < 0: 134 return False 135 self.delayed_open_lid() 136 if self.faft_client.system.check_keys([]) < 0: 137 return False 138 return True 139 140 def check_backlight(self): 141 """Check if lid open/close controls keyboard backlight as expected. 142 143 Returns: 144 True if keyboard backlight is turned off when lid close and on when 145 lid open. 146 """ 147 if not self.check_ec_capability(['kblight'], suppress_warning=True): 148 return True 149 ok = True 150 original_value = self._get_keyboard_backlight() 151 self._set_keyboard_backlight(100) 152 153 self._close_lid() 154 if self._get_keyboard_backlight() != 0: 155 logging.error("Keyboard backlight still on when lid close.") 156 ok = False 157 self._open_lid() 158 if self._get_keyboard_backlight() == 0: 159 logging.error("Keyboard backlight still off when lid open.") 160 ok = False 161 162 self._set_keyboard_backlight(original_value) 163 return ok 164 165 def check_keycode_and_backlight(self): 166 """ 167 Disable powerd to prevent DUT shutting down during test. Then check 168 if lid switch event controls keycode and backlight as we expected. 169 """ 170 ok = True 171 logging.info("Stopping powerd") 172 self.faft_client.system.run_shell_command('stop powerd') 173 if not self.check_keycode(): 174 logging.error("check_keycode failed.") 175 ok = False 176 if not self.check_backlight(): 177 logging.error("check_backlight failed.") 178 ok = False 179 logging.info("Restarting powerd") 180 self.faft_client.system.run_shell_command('start powerd') 181 return ok 182 183 def run_once(self): 184 """Runs a single iteration of the test.""" 185 if not self.check_ec_capability(['lid']): 186 raise error.TestNAError("Nothing needs to be tested on this device") 187 188 logging.info("Shut down and then wake up DUT after a delay.") 189 self.switcher.mode_aware_reboot( 190 'custom', 191 lambda:self.shutdown_and_wake( 192 shutdown_func=self.run_shutdown_cmd, 193 wake_func=self.delayed_wake)) 194 logging.info("Shut down and then wake up DUT immediately.") 195 self.switcher.mode_aware_reboot( 196 'custom', 197 lambda:self.shutdown_and_wake( 198 shutdown_func=self.run_shutdown_cmd, 199 wake_func=self.immediate_wake)) 200 logging.info("Close and then open the lid when not logged in.") 201 self.switcher.mode_aware_reboot( 202 'custom', 203 lambda:self.shutdown_and_wake( 204 shutdown_func=self._close_lid, 205 wake_func=self.immediate_wake)) 206 logging.info("Check keycode and backlight.") 207 self.check_state(self.check_keycode_and_backlight) 208