| # Copyright 2015 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 |
| |
| |
| class ModeSwitcher(object): |
| """Class that controls firmware mode switching.""" |
| |
| def __init__(self, faft_framework): |
| self.faft_framework = faft_framework |
| self.faft_client = faft_framework.faft_client |
| self.servo = faft_framework.servo |
| self.faft_config = faft_framework.faft_config |
| self.checkers = faft_framework.checkers |
| self._backup_mode = None |
| |
| |
| def setup_mode(self, mode): |
| """Setup for the requested mode. |
| |
| It makes sure the system in the requested mode. If not, it tries to |
| do so. |
| |
| @param mode: A string of mode, one of 'normal', 'dev', or 'rec'. |
| """ |
| if not self.checkers.mode_checker(mode): |
| logging.info('System not in expected %s mode. Reboot into it.', |
| mode) |
| if self._backup_mode is None: |
| # Only resume to normal/dev mode after test, not recovery. |
| self._backup_mode = 'dev' if mode == 'normal' else 'normal' |
| self.reboot_to_mode(mode) |
| if mode == 'dev': |
| self.faft_framework.wait_dev_screen_and_ctrl_d() |
| |
| |
| def restore_mode(self): |
| """Restores original dev mode status if it has changed.""" |
| if self._backup_mode is not None: |
| self.reboot_to_mode(self._backup_mode) |
| if self._backup_mode == 'dev': |
| self.faft_framework.wait_dev_screen_and_ctrl_d() |
| |
| |
| def reboot_to_mode(self, to_mode, from_mode=None): |
| """Reboot and execute the mode switching sequence. |
| |
| This method does not wait DUT online. May need additional |
| operations to pass the firmware screen, e.g. pressing Ctrl-D. |
| |
| @param to_mode: The target mode, one of 'normal', 'dev', or 'rec'. |
| @param from_mode: The original mode, optional, one of 'normal, 'dev', |
| or 'rec'. |
| """ |
| logging.info('-[ModeSwitcher]-[ start reboot_to_mode(%r, %r) ]-', |
| to_mode, from_mode) |
| if to_mode == 'rec': |
| self._enable_rec_mode_and_reboot(usb_state='dut') |
| elif to_mode == 'dev': |
| self._enable_dev_mode_and_reboot() |
| elif to_mode == 'normal': |
| self._enable_normal_mode_and_reboot() |
| else: |
| raise NotImplementedError( |
| 'Not supported mode switching from %s to %s' % |
| (str(from_mode), to_mode)) |
| logging.info('-[ModeSwitcher]-[ end reboot_to_mode(%r, %r) ]-', |
| to_mode, from_mode) |
| |
| |
| def _enable_rec_mode_and_reboot(self, usb_state=None): |
| """Switch to rec mode and reboot. |
| |
| This method emulates the behavior of the old physical recovery switch, |
| i.e. switch ON + reboot + switch OFF, and the new keyboard controlled |
| recovery mode, i.e. just press Power + Esc + Refresh. |
| |
| @param usb_state: A string, one of 'dut', 'host', or 'off'. |
| """ |
| self.faft_framework.blocking_sync() |
| psc = self.servo.get_power_state_controller() |
| psc.power_off() |
| if usb_state: |
| self.servo.switch_usbkey(usb_state) |
| psc.power_on(psc.REC_ON) |
| |
| |
| def _enable_dev_mode_and_reboot(self): |
| """Switch to developer mode and reboot.""" |
| if self.faft_config.keyboard_dev: |
| self._enable_keyboard_dev_mode() |
| else: |
| self.servo.enable_development_mode() |
| self.faft_client.system.run_shell_command( |
| 'chromeos-firmwareupdate --mode todev && reboot') |
| |
| |
| def _enable_normal_mode_and_reboot(self): |
| """Switch to normal mode and reboot.""" |
| if self.faft_config.keyboard_dev: |
| self._disable_keyboard_dev_mode() |
| else: |
| self.servo.disable_development_mode() |
| self.faft_client.system.run_shell_command( |
| 'chromeos-firmwareupdate --mode tonormal && reboot') |
| |
| |
| def _enable_keyboard_dev_mode(self): |
| """Enable keyboard controlled developer mode""" |
| logging.info("Enabling keyboard controlled developer mode") |
| # Rebooting EC with rec mode on. Should power on AP. |
| # Plug out USB disk for preventing recovery boot without warning |
| self._enable_rec_mode_and_reboot(usb_state='host') |
| self.faft_framework.wait_for_client_offline() |
| self._wait_fw_screen_and_switch_keyboard_dev_mode(dev=True) |
| |
| # TODO (crosbug.com/p/16231) remove this conditional completely if/when |
| # issue is resolved. |
| if self.faft_config.platform == 'Parrot': |
| self.faft_framework.wait_for_client_offline() |
| self.faft_framwork.reboot_cold_trigger() |
| |
| |
| def _disable_keyboard_dev_mode(self): |
| """Disable keyboard controlled developer mode""" |
| logging.info("Disabling keyboard controlled developer mode") |
| if (not self.faft_config.chrome_ec and |
| not self.faft_config.broken_rec_mode): |
| self.servo.disable_recovery_mode() |
| self.faft_framework.sync_and_cold_reboot() |
| self.faft_framework.wait_for_client_offline() |
| self._wait_fw_screen_and_switch_keyboard_dev_mode(dev=False) |
| |
| |
| def _wait_fw_screen_and_switch_keyboard_dev_mode(self, dev): |
| """Wait for firmware screen and then switch into or out of dev mode. |
| |
| @param dev: True if switching into dev mode. Otherwise, False. |
| """ |
| time.sleep(self.faft_config.firmware_screen) |
| if dev: |
| self.servo.ctrl_d() |
| time.sleep(self.faft_config.confirm_screen) |
| if self.faft_config.rec_button_dev_switch: |
| logging.info('RECOVERY button pressed to switch to dev mode') |
| self.servo.set('rec_mode', 'on') |
| time.sleep(self.faft_config.hold_cold_reset) |
| self.servo.set('rec_mode', 'off') |
| else: |
| logging.info('ENTER pressed to switch to dev mode') |
| self.servo.enter_key() |
| else: |
| self.servo.enter_key() |
| time.sleep(self.faft_config.confirm_screen) |
| self.servo.enter_key() |