| # 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('<ctrl_l>') |
| self.base_ec.key_down('<alt_l>') |
| self.base_ec.key_down('<f2>') |
| self.base_ec.key_up('<f2>') |
| self.base_ec.key_up('<alt_l>') |
| self.base_ec.key_up('<ctrl_l>') |
| 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<enter>') |
| self.base_ec.send_key_string('test0000<enter>') |
| self.base_ec.send_key_string('reboot<enter>') |
| |
| |
| 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) |