| # Copyright (c) 2012 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| from threading import Timer |
| import logging |
| import re |
| import time |
| |
| from autotest_lib.client.common_lib import error |
| from autotest_lib.server.cros.faft.firmware_test import FirmwareTest |
| |
| |
| def delayed(seconds): # pylint:disable=missing-docstring |
| def decorator(f): # pylint:disable=missing-docstring |
| def wrapper(*args, **kargs): # pylint:disable=missing-docstring |
| t = Timer(seconds, f, args, kargs) |
| t.start() |
| return wrapper |
| return decorator |
| |
| |
| class firmware_ECLidSwitch(FirmwareTest): |
| """ |
| Servo based EC lid switch test. |
| """ |
| version = 1 |
| |
| # Delay between closing and opening the lid |
| LID_DELAY = 1 |
| |
| # Delay to allow FAFT client receive command |
| RPC_DELAY = 2 |
| |
| # Delay between shutdown and wakeup by lid switch |
| WAKE_DELAY = 10 |
| |
| def initialize(self, host, cmdline_args): |
| super(firmware_ECLidSwitch, self).initialize(host, cmdline_args) |
| # Only run in normal mode |
| self.switcher.setup_mode('normal') |
| |
| def _open_lid(self): |
| """Open lid by servo.""" |
| self.servo.set('lid_open', 'yes') |
| |
| def _close_lid(self): |
| """Close lid by servo.""" |
| self.servo.set('lid_open', 'no') |
| |
| @delayed(RPC_DELAY) |
| def delayed_open_lid(self): |
| """Delay by RPC_DELAY and then open lid by servo.""" |
| self._open_lid() |
| |
| @delayed(RPC_DELAY) |
| def delayed_close_lid(self): |
| """Delay by RPC_DELAY and then close lid by servo.""" |
| self._close_lid() |
| |
| def _wake_by_lid_switch(self): |
| """Wake DUT with lid switch.""" |
| self._close_lid() |
| time.sleep(self.LID_DELAY) |
| self._open_lid() |
| |
| def delayed_wake(self): |
| """ |
| Confirm the device is in G3, wait for WAKE_DELAY, and then wake DUT |
| with lid switch. |
| """ |
| self.check_shutdown_power_state(self.POWER_STATE_G3, pwr_retries=10) |
| time.sleep(self.WAKE_DELAY) |
| self._wake_by_lid_switch() |
| |
| def immediate_wake(self): |
| """Confirm the device is in G3 and then wake DUT with lid switch.""" |
| self.check_shutdown_power_state(self.POWER_STATE_G3, pwr_retries=10) |
| self._wake_by_lid_switch() |
| |
| def shutdown_and_wake(self, shutdown_func, wake_func): |
| """Software shutdown and wake. |
| |
| Args: |
| shutdown_func: Function to shut down DUT. |
| wake_func: Delayed function to wake DUT. |
| """ |
| shutdown_func() |
| wake_func() |
| |
| def _get_keyboard_backlight(self): |
| """Get keyboard backlight brightness. |
| |
| Returns: |
| Backlight brightness percentage 0~100. If it is disabled, 0 is |
| returned. |
| """ |
| cmd = 'ectool pwmgetkblight' |
| pattern_percent = re.compile( |
| 'Current keyboard backlight percent: (\d*)') |
| pattern_disable = re.compile('Keyboard backlight disabled.') |
| lines = self.faft_client.system.run_shell_command_get_output(cmd) |
| for line in lines: |
| matched_percent = pattern_percent.match(line) |
| if matched_percent is not None: |
| return int(matched_percent.group(1)) |
| matched_disable = pattern_disable.match(line) |
| if matched_disable is not None: |
| return 0 |
| raise error.TestError('Cannot get keyboard backlight status.') |
| |
| def _set_keyboard_backlight(self, value): |
| """Set keyboard backlight brightness. |
| |
| Args: |
| value: Backlight brightness percentage 0~100. |
| """ |
| cmd = 'ectool pwmsetkblight %d' % value |
| self.faft_client.system.run_shell_command(cmd) |
| |
| def check_keycode(self): |
| """Check that lid open/close do not send power button keycode. |
| |
| Returns: |
| True if no power button keycode is captured. Otherwise, False. |
| """ |
| # Don't check the keycode if we don't have a keyboard. |
| if not self.check_ec_capability(['keyboard'], suppress_warning=True): |
| return True |
| |
| self._open_lid() |
| self.delayed_close_lid() |
| if self.faft_client.system.check_keys([]) < 0: |
| return False |
| self.delayed_open_lid() |
| if self.faft_client.system.check_keys([]) < 0: |
| return False |
| return True |
| |
| def check_backlight(self): |
| """Check if lid open/close controls keyboard backlight as expected. |
| |
| Returns: |
| True if keyboard backlight is turned off when lid close and on when |
| lid open. |
| """ |
| if not self.check_ec_capability(['kblight'], suppress_warning=True): |
| return True |
| ok = True |
| original_value = self._get_keyboard_backlight() |
| self._set_keyboard_backlight(100) |
| |
| self._close_lid() |
| if self._get_keyboard_backlight() != 0: |
| logging.error("Keyboard backlight still on when lid close.") |
| ok = False |
| self._open_lid() |
| if self._get_keyboard_backlight() == 0: |
| logging.error("Keyboard backlight still off when lid open.") |
| ok = False |
| |
| self._set_keyboard_backlight(original_value) |
| return ok |
| |
| def check_keycode_and_backlight(self): |
| """ |
| Disable powerd to prevent DUT shutting down during test. Then check |
| if lid switch event controls keycode and backlight as we expected. |
| """ |
| ok = True |
| logging.info("Stopping powerd") |
| self.faft_client.system.run_shell_command('stop powerd') |
| if not self.check_keycode(): |
| logging.error("check_keycode failed.") |
| ok = False |
| if not self.check_backlight(): |
| logging.error("check_backlight failed.") |
| ok = False |
| logging.info("Restarting powerd") |
| self.faft_client.system.run_shell_command('start powerd') |
| return ok |
| |
| def run_once(self): |
| """Runs a single iteration of the test.""" |
| if not self.check_ec_capability(['lid']): |
| raise error.TestNAError("Nothing needs to be tested on this device") |
| |
| logging.info("Shut down and then wake up DUT after a delay.") |
| self.switcher.mode_aware_reboot( |
| 'custom', |
| lambda:self.shutdown_and_wake( |
| shutdown_func=self.run_shutdown_cmd, |
| wake_func=self.delayed_wake)) |
| logging.info("Shut down and then wake up DUT immediately.") |
| self.switcher.mode_aware_reboot( |
| 'custom', |
| lambda:self.shutdown_and_wake( |
| shutdown_func=self.run_shutdown_cmd, |
| wake_func=self.immediate_wake)) |
| logging.info("Close and then open the lid when not logged in.") |
| self.switcher.mode_aware_reboot( |
| 'custom', |
| lambda:self.shutdown_and_wake( |
| shutdown_func=self._close_lid, |
| wake_func=self.immediate_wake)) |
| logging.info("Check keycode and backlight.") |
| self.check_state(self.check_keycode_and_backlight) |