1# Copyright 2017 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 5import logging 6import time 7from threading import Timer 8 9from autotest_lib.client.bin.input import linux_input 10from autotest_lib.client.common_lib import error 11from autotest_lib.server.cros.faft.firmware_test import FirmwareTest 12 13 14class firmware_BaseECKeyboard(FirmwareTest): 15 """Servo-based BaseEC keyboard test. 16 17 The base should be connected to the servo v4 board through an extra 18 micro-servo. It talks to the base EC to emulate key-press. 19 """ 20 version = 1 21 22 # Delay to ensure client is ready to read the key press. 23 KEY_PRESS_DELAY = 2 24 25 # Delay to wait until the UI starts. 26 START_UI_DELAY = 1 27 28 # Delay to wait until developer console is open. 29 DEV_CONSOLE_DELAY = 2 30 31 32 def initialize(self, host, cmdline_args): 33 super(firmware_BaseECKeyboard, self).initialize(host, cmdline_args) 34 # Don't require USB disk 35 self.setup_usbkey(usbkey=False) 36 # Only run in normal mode 37 self.switcher.setup_mode('normal') 38 39 40 def cleanup(self): 41 # Restart UI anyway, in case the test failed in the middle 42 try: 43 self.faft_client.system.run_shell_command('start ui | true') 44 except Exception as e: 45 logging.error("Caught exception: %s", str(e)) 46 super(firmware_BaseECKeyboard, self).cleanup() 47 48 49 def _base_keyboard_checker(self, press_action): 50 """Press key and check from DUT. 51 52 Args: 53 press_action: A callable that would press the keys when called. 54 55 Returns: 56 True if passed; or False if failed. 57 """ 58 # Stop UI so that key presses don't go to Chrome. 59 self.faft_client.system.run_shell_command('stop ui') 60 61 # Start a thread to perform the key-press action 62 Timer(self.KEY_PRESS_DELAY, press_action).start() 63 64 # Invoke client side script to monitor keystrokes. 65 # The codes are linux input event codes. 66 # The order doesn't matter. 67 result = self.faft_client.system.check_keys([ 68 linux_input.KEY_ENTER, 69 linux_input.KEY_LEFTCTRL, 70 linux_input.KEY_D]) 71 72 # Turn UI back on 73 self.faft_client.system.run_shell_command('start ui') 74 time.sleep(self.START_UI_DELAY) 75 76 return result 77 78 79 def keyboard_checker(self): 80 """Press 'd', Ctrl, ENTER by servo and check from DUT.""" 81 82 def keypress(): # pylint:disable=missing-docstring 83 self.servo.enter_key() 84 self.servo.ctrl_d() 85 86 return self._base_keyboard_checker(keypress) 87 88 89 def switch_tty2(self): 90 """Switch to tty2 console.""" 91 self.base_ec.key_down('<ctrl_l>') 92 self.base_ec.key_down('<alt_l>') 93 self.base_ec.key_down('<f2>') 94 self.base_ec.key_up('<f2>') 95 self.base_ec.key_up('<alt_l>') 96 self.base_ec.key_up('<ctrl_l>') 97 time.sleep(self.DEV_CONSOLE_DELAY) 98 99 100 def reboot_by_keyboard(self): 101 """Reboot DUT by keyboard. 102 103 Simulate key press sequence to log into console and then issue reboot 104 command. 105 """ 106 # Assume that DUT runs a test image, which has tty2 console and root 107 # access. 108 self.switch_tty2() 109 self.base_ec.send_key_string('root<enter>') 110 self.base_ec.send_key_string('test0000<enter>') 111 self.base_ec.send_key_string('reboot<enter>') 112 113 114 def run_once(self): 115 """Runs a single iteration of the test.""" 116 if not self.base_ec: 117 raise error.TestError('The base not found on servo. Wrong setup?') 118 119 logging.info('Testing keypress by servo...') 120 self.check_state(self.keyboard_checker) 121 122 logging.info('Use key press simulation to issue reboot command...') 123 self.switcher.mode_aware_reboot('custom', self.reboot_by_keyboard) 124