# Copyright 2017 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. import logging import time from threading import Timer from autotest_lib.client.bin.input import linux_input from autotest_lib.client.common_lib import error from autotest_lib.server.cros.faft.firmware_test import FirmwareTest class firmware_BaseECKeyboard(FirmwareTest): """Servo-based BaseEC keyboard test. The base should be connected to the servo v4 board through an extra micro-servo. It talks to the base EC to emulate key-press. """ version = 1 # Delay to ensure client is ready to read the key press. KEY_PRESS_DELAY = 2 # Delay to wait until the UI starts. START_UI_DELAY = 1 # Delay to wait until developer console is open. DEV_CONSOLE_DELAY = 2 def initialize(self, host, cmdline_args): super(firmware_BaseECKeyboard, self).initialize(host, cmdline_args) # Don't require USB disk self.setup_usbkey(usbkey=False) # Only run in normal mode self.switcher.setup_mode('normal') def cleanup(self): # Restart UI anyway, in case the test failed in the middle try: self.faft_client.system.run_shell_command('start ui | true') except Exception as e: logging.error("Caught exception: %s", str(e)) super(firmware_BaseECKeyboard, self).cleanup() def _base_keyboard_checker(self, press_action): """Press key and check from DUT. Args: press_action: A callable that would press the keys when called. Returns: True if passed; or False if failed. """ # Stop UI so that key presses don't go to Chrome. self.faft_client.system.run_shell_command('stop ui') # Start a thread to perform the key-press action Timer(self.KEY_PRESS_DELAY, press_action).start() # Invoke client side script to monitor keystrokes. # The codes are linux input event codes. # The order doesn't matter. result = self.faft_client.system.check_keys([ linux_input.KEY_ENTER, linux_input.KEY_LEFTCTRL, linux_input.KEY_D]) # Turn UI back on self.faft_client.system.run_shell_command('start ui') time.sleep(self.START_UI_DELAY) return result def keyboard_checker(self): """Press 'd', Ctrl, ENTER by servo and check from DUT.""" def keypress(): # pylint:disable=missing-docstring self.servo.enter_key() self.servo.ctrl_d() return self._base_keyboard_checker(keypress) def switch_tty2(self): """Switch to tty2 console.""" self.base_ec.key_down('') self.base_ec.key_down('') self.base_ec.key_down('') self.base_ec.key_up('') self.base_ec.key_up('') self.base_ec.key_up('') time.sleep(self.DEV_CONSOLE_DELAY) def reboot_by_keyboard(self): """Reboot DUT by keyboard. Simulate key press sequence to log into console and then issue reboot command. """ # Assume that DUT runs a test image, which has tty2 console and root # access. self.switch_tty2() self.base_ec.send_key_string('root') self.base_ec.send_key_string('test0000') self.base_ec.send_key_string('reboot') def run_once(self): """Runs a single iteration of the test.""" if not self.base_ec: raise error.TestError('The base not found on servo. Wrong setup?') logging.info('Testing keypress by servo...') self.check_state(self.keyboard_checker) logging.info('Use key press simulation to issue reboot command...') self.switcher.mode_aware_reboot('custom', self.reboot_by_keyboard)