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