Mary Ruthven | 300b1fa | 2017-05-30 10:24:23 -0700 | [diff] [blame] | 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 | |
| 5 | import functools |
| 6 | import logging |
Mary Ruthven | 61060f8 | 2017-05-30 20:50:39 -0700 | [diff] [blame] | 7 | import time |
Mary Ruthven | 300b1fa | 2017-05-30 10:24:23 -0700 | [diff] [blame] | 8 | |
| 9 | from autotest_lib.client.bin import utils |
| 10 | from autotest_lib.client.common_lib import error |
Mary Ruthven | a30e065 | 2017-08-18 13:29:48 -0700 | [diff] [blame] | 11 | from autotest_lib.client.common_lib.cros import cr50_utils |
Mary Ruthven | 300b1fa | 2017-05-30 10:24:23 -0700 | [diff] [blame] | 12 | from autotest_lib.server.cros.servo import chrome_ec |
| 13 | |
| 14 | |
Mary Ruthven | fd3d7aa | 2018-01-26 17:07:52 -0800 | [diff] [blame] | 15 | def servo_v4_command(func): |
| 16 | """Decorator for methods only relevant to tests running with servo v4.""" |
Mary Ruthven | 300b1fa | 2017-05-30 10:24:23 -0700 | [diff] [blame] | 17 | @functools.wraps(func) |
| 18 | def wrapper(instance, *args, **kwargs): |
Mary Ruthven | fd3d7aa | 2018-01-26 17:07:52 -0800 | [diff] [blame] | 19 | """Ignore servo v4 functions it's not being used.""" |
| 20 | if instance.using_servo_v4(): |
Mary Ruthven | 300b1fa | 2017-05-30 10:24:23 -0700 | [diff] [blame] | 21 | return func(instance, *args, **kwargs) |
Mary Ruthven | fd3d7aa | 2018-01-26 17:07:52 -0800 | [diff] [blame] | 22 | logging.info("not using servo v4. ignoring %s", func.func_name) |
Mary Ruthven | 300b1fa | 2017-05-30 10:24:23 -0700 | [diff] [blame] | 23 | return wrapper |
| 24 | |
| 25 | |
| 26 | class ChromeCr50(chrome_ec.ChromeConsole): |
| 27 | """Manages control of a Chrome Cr50. |
| 28 | |
| 29 | We control the Chrome Cr50 via the console of a Servo board. Chrome Cr50 |
| 30 | provides many interfaces to set and get its behavior via console commands. |
| 31 | This class is to abstract these interfaces. |
| 32 | """ |
Mary Ruthven | 3ff9949 | 2017-11-06 16:29:26 -0800 | [diff] [blame] | 33 | # The amount of time you need to show physical presence. |
| 34 | PP_SHORT = 15 |
| 35 | PP_LONG = 300 |
Mary Ruthven | 300b1fa | 2017-05-30 10:24:23 -0700 | [diff] [blame] | 36 | IDLE_COUNT = 'count: (\d+)' |
Mary Ruthven | ec74b46 | 2017-09-27 15:04:49 -0700 | [diff] [blame] | 37 | # The version has four groups: the partition, the header version, debug |
| 38 | # descriptor and then version string. |
| 39 | # There are two partitions A and B. The active partition is marked with a |
| 40 | # '*'. If it is a debug image '/DBG' is added to the version string. If the |
| 41 | # image has been corrupted, the version information will be replaced with |
| 42 | # 'Error'. |
| 43 | # So the output may look something like this. |
| 44 | # RW_A: 0.0.21/cr50_v1.1.6133-fd788b |
| 45 | # RW_B: * 0.0.22/DBG/cr50_v1.1.6138-b9f0b1d |
| 46 | # Or like this if the region was corrupted. |
| 47 | # RW_A: * 0.0.21/cr50_v1.1.6133-fd788b |
| 48 | # RW_B: Error |
| 49 | VERSION_FORMAT = '\nRW_(A|B): +%s +(\d+\.\d+\.\d+|Error)(/DBG)?(\S+)?\s' |
Mary Ruthven | d89b559 | 2017-09-28 11:41:10 -0700 | [diff] [blame] | 50 | INACTIVE_VERSION = VERSION_FORMAT % '' |
| 51 | ACTIVE_VERSION = VERSION_FORMAT % '\*' |
Mary Ruthven | ec74b46 | 2017-09-27 15:04:49 -0700 | [diff] [blame] | 52 | # Following lines of the version output may print the image board id |
| 53 | # information. eg. |
| 54 | # BID A: 5a5a4146:ffffffff:00007f00 Yes |
| 55 | # BID B: 00000000:00000000:00000000 Yes |
| 56 | # Use the first group from ACTIVE_VERSION to match the active board id |
| 57 | # partition. |
Mary Ruthven | d73fe4a | 2017-12-12 21:55:09 -0800 | [diff] [blame] | 58 | BID_ERROR = 'read_board_id: failed' |
| 59 | BID_FORMAT = ':\s+[a-f0-9:]+ ' |
| 60 | ACTIVE_BID = r'%s.*(\1%s|%s.*>)' % (ACTIVE_VERSION, BID_FORMAT, |
| 61 | BID_ERROR) |
Mary Ruthven | d29ee88 | 2018-04-05 17:27:25 -0700 | [diff] [blame] | 62 | WAKE_CHAR = '\n\n' |
| 63 | WAKE_RESPONSE = ['(>|Console is enabled)'] |
Mary Ruthven | 5655829 | 2017-05-30 12:31:29 -0700 | [diff] [blame] | 64 | START_UNLOCK_TIMEOUT = 20 |
Mary Ruthven | 5655829 | 2017-05-30 12:31:29 -0700 | [diff] [blame] | 65 | GETTIME = ['= (\S+)'] |
Mary Ruthven | 9a0ce56 | 2017-05-30 13:01:47 -0700 | [diff] [blame] | 66 | FWMP_LOCKED_PROD = ["Managed device console can't be unlocked"] |
| 67 | FWMP_LOCKED_DBG = ['Ignoring FWMP unlock setting'] |
Mary Ruthven | 3c5dcf9 | 2017-06-26 15:55:15 -0700 | [diff] [blame] | 68 | MAX_RETRY_COUNT = 5 |
Mary Ruthven | 0f3e834 | 2017-07-07 11:15:39 -0700 | [diff] [blame] | 69 | START_STR = ['(.*Console is enabled;)'] |
Mary Ruthven | 024c2dc | 2017-11-08 15:48:40 -0800 | [diff] [blame] | 70 | REBOOT_DELAY_WITH_CCD = 60 |
| 71 | REBOOT_DELAY_WITH_FLEX = 3 |
Mary Ruthven | 2478d85 | 2017-12-13 13:09:02 -0800 | [diff] [blame] | 72 | ON_STRINGS = ['enable', 'enabled', 'on'] |
Mary Ruthven | 300b1fa | 2017-05-30 10:24:23 -0700 | [diff] [blame] | 73 | |
| 74 | |
| 75 | def __init__(self, servo): |
Mary Ruthven | ce81d6e | 2017-11-28 14:48:22 -0800 | [diff] [blame] | 76 | super(ChromeCr50, self).__init__(servo, 'cr50_uart') |
Mary Ruthven | 300b1fa | 2017-05-30 10:24:23 -0700 | [diff] [blame] | 77 | |
| 78 | |
Mary Ruthven | d29ee88 | 2018-04-05 17:27:25 -0700 | [diff] [blame] | 79 | def wake_cr50(self): |
| 80 | """Wake up cr50 by sending some linebreaks and wait for the response""" |
| 81 | logging.debug(super(ChromeCr50, self).send_command_get_output( |
| 82 | self.WAKE_CHAR, self.WAKE_RESPONSE)) |
| 83 | |
| 84 | |
Mary Ruthven | 300b1fa | 2017-05-30 10:24:23 -0700 | [diff] [blame] | 85 | def send_command(self, commands): |
| 86 | """Send command through UART. |
| 87 | |
| 88 | Cr50 will drop characters input to the UART when it resumes from sleep. |
| 89 | If servo is not using ccd, send some dummy characters before sending the |
| 90 | real command to make sure cr50 is awake. |
| 91 | """ |
| 92 | if not self.using_ccd(): |
Mary Ruthven | d29ee88 | 2018-04-05 17:27:25 -0700 | [diff] [blame] | 93 | self.wake_cr50() |
Mary Ruthven | 300b1fa | 2017-05-30 10:24:23 -0700 | [diff] [blame] | 94 | super(ChromeCr50, self).send_command(commands) |
| 95 | |
| 96 | |
Mary Ruthven | 0e0aba8 | 2018-04-26 17:01:38 -0700 | [diff] [blame] | 97 | def set_cap(self, cap, config): |
| 98 | """Set the capability to the config value""" |
| 99 | self.set_caps({ cap : config }) |
| 100 | |
| 101 | |
| 102 | def set_caps(self, cap_dict): |
| 103 | """Use cap_dict to set all the cap values |
| 104 | |
| 105 | Set all of the capabilities in cap_dict to the correct config. |
| 106 | |
| 107 | Args: |
| 108 | cap_dict: A dictionary with the capability as key and the desired |
| 109 | setting as values |
| 110 | """ |
| 111 | for cap, config in cap_dict.iteritems(): |
| 112 | self.send_command('ccd set %s %s' % (cap, config)) |
| 113 | current_cap_settings = self.get_cap_dict() |
| 114 | for cap, config in cap_dict.iteritems(): |
| 115 | if current_cap_settings[cap].lower() != config.lower(): |
| 116 | raise error.TestFail('Failed to set %s to %s' % (cap, config)) |
| 117 | |
| 118 | |
| 119 | def get_cap_dict(self): |
| 120 | """Get the current ccd capability settings. |
| 121 | |
| 122 | Returns: |
| 123 | A dictionary with the capability as the key and the setting as the |
| 124 | value |
| 125 | """ |
| 126 | caps = {} |
| 127 | rv = self.send_command_get_output('ccd', |
Mary Ruthven | b393cbf | 2018-05-11 15:23:25 -0700 | [diff] [blame] | 128 | ["Capabilities:\s+[\da-f]+\s(.*)Use 'ccd help'"])[0][1] |
Mary Ruthven | 0e0aba8 | 2018-04-26 17:01:38 -0700 | [diff] [blame] | 129 | for line in rv.splitlines(): |
| 130 | # Line information is separated with an = |
| 131 | # RebootECAP Y 0=Default (IfOpened) |
| 132 | # Extract the capability name and the value. The first word after |
| 133 | # the equals sign is the only one that matters. 'Default' is the |
| 134 | # value not IfOpened |
| 135 | line = line.strip() |
| 136 | if '=' not in line: |
| 137 | continue |
| 138 | logging.info(line) |
| 139 | start, end = line.split('=') |
| 140 | caps[start.split()[0]] = end.split()[0] |
| 141 | logging.debug(caps) |
| 142 | return caps |
| 143 | |
| 144 | |
Mary Ruthven | 300b1fa | 2017-05-30 10:24:23 -0700 | [diff] [blame] | 145 | def send_command_get_output(self, command, regexp_list): |
| 146 | """Send command through UART and wait for response. |
| 147 | |
| 148 | Cr50 will drop characters input to the UART when it resumes from sleep. |
| 149 | If servo is not using ccd, send some dummy characters before sending the |
| 150 | real command to make sure cr50 is awake. |
| 151 | """ |
| 152 | if not self.using_ccd(): |
Mary Ruthven | d29ee88 | 2018-04-05 17:27:25 -0700 | [diff] [blame] | 153 | self.wake_cr50() |
Mary Ruthven | ad847b7 | 2018-05-25 17:24:54 -0700 | [diff] [blame] | 154 | |
| 155 | # We have started prepending '\n' to separate cr50 console junk from |
| 156 | # the real command. If someone is just searching for .*>, then they will |
| 157 | # only get the output from the first '\n' we added. Raise an error to |
| 158 | # change the test to look for something more specific ex command.*>. |
| 159 | # cr50 will print the command in the output, so that is an easy way to |
| 160 | # modify '.*>' to match the real command output. |
| 161 | if '.*>' in regexp_list: |
| 162 | raise error.TestError('Send more specific regexp %r %r' % (command, |
| 163 | regexp_list)) |
| 164 | |
| 165 | # prepend \n to separate the command from any junk that may have been |
| 166 | # sent to the cr50 uart. |
| 167 | command = '\n' + command |
Mary Ruthven | 300b1fa | 2017-05-30 10:24:23 -0700 | [diff] [blame] | 168 | return super(ChromeCr50, self).send_command_get_output(command, |
| 169 | regexp_list) |
| 170 | |
Mary Ruthven | 599395b | 2018-05-25 15:31:31 -0700 | [diff] [blame] | 171 | def send_command_retry_get_output(self, command, regexp_list, tries=3): |
| 172 | """Retry sending a command if we can't find the output. |
| 173 | |
| 174 | Cr50 may print irrelevant output while printing command output. It may |
| 175 | prevent the regex from matching. Send command and get the output. If it |
| 176 | fails try again. |
| 177 | |
| 178 | If it fails every time, raise an error. |
| 179 | |
| 180 | Don't use this to set something that should only be set once. |
| 181 | """ |
| 182 | # TODO(b/80319784): once chan is unrestricted, use it to restrict what |
| 183 | # output cr50 prints while we are sending commands. |
| 184 | for i in range(tries): |
| 185 | try: |
| 186 | return self.send_command_get_output(command, regexp_list) |
| 187 | except error.TestFail, e: |
| 188 | logging.info('Failed to get %r output: %r', command, e.message) |
| 189 | # Raise the last error, if we never successfully returned the command |
| 190 | # output |
| 191 | logging.info('Could not get %r output after %d tries', command, tries) |
| 192 | raise |
| 193 | |
| 194 | |
Mary Ruthven | 300b1fa | 2017-05-30 10:24:23 -0700 | [diff] [blame] | 195 | |
| 196 | def get_deep_sleep_count(self): |
| 197 | """Get the deep sleep count from the idle task""" |
Mary Ruthven | f23dde1 | 2018-05-25 15:50:09 -0700 | [diff] [blame] | 198 | result = self.send_command_retry_get_output('idle', [self.IDLE_COUNT]) |
Mary Ruthven | 300b1fa | 2017-05-30 10:24:23 -0700 | [diff] [blame] | 199 | return int(result[0][1]) |
| 200 | |
| 201 | |
| 202 | def clear_deep_sleep_count(self): |
| 203 | """Clear the deep sleep count""" |
Mary Ruthven | f23dde1 | 2018-05-25 15:50:09 -0700 | [diff] [blame] | 204 | result = self.send_command_retry_get_output('idle c', [self.IDLE_COUNT]) |
Mary Ruthven | 300b1fa | 2017-05-30 10:24:23 -0700 | [diff] [blame] | 205 | if int(result[0][1]): |
| 206 | raise error.TestFail("Could not clear deep sleep count") |
| 207 | |
| 208 | |
Mary Ruthven | 9d4ba2a | 2018-05-04 17:52:43 -0700 | [diff] [blame] | 209 | def get_board_properties(self): |
| 210 | """Get information from the version command""" |
Mary Ruthven | f23dde1 | 2018-05-25 15:50:09 -0700 | [diff] [blame] | 211 | rv = self.send_command_retry_get_output('brdprop', |
Mary Ruthven | 9d4ba2a | 2018-05-04 17:52:43 -0700 | [diff] [blame] | 212 | ['properties = (\S+)']) |
| 213 | return int(rv[0][1], 16) |
| 214 | |
| 215 | |
Mary Ruthven | 300b1fa | 2017-05-30 10:24:23 -0700 | [diff] [blame] | 216 | def has_command(self, cmd): |
| 217 | """Returns 1 if cr50 has the command 0 if it doesn't""" |
| 218 | try: |
Mary Ruthven | f23dde1 | 2018-05-25 15:50:09 -0700 | [diff] [blame] | 219 | self.send_command_retry_get_output('help', [cmd]) |
Mary Ruthven | 300b1fa | 2017-05-30 10:24:23 -0700 | [diff] [blame] | 220 | except: |
| 221 | logging.info("Image does not include '%s' command", cmd) |
| 222 | return 0 |
| 223 | return 1 |
| 224 | |
| 225 | |
| 226 | def erase_nvmem(self): |
| 227 | """Use flasherase to erase both nvmem sections""" |
| 228 | if not self.has_command('flasherase'): |
| 229 | raise error.TestError("need image with 'flasherase'") |
| 230 | |
| 231 | self.send_command('flasherase 0x7d000 0x3000') |
| 232 | self.send_command('flasherase 0x3d000 0x3000') |
| 233 | |
| 234 | |
| 235 | def reboot(self): |
Mary Ruthven | fc25974 | 2017-08-08 14:25:50 -0700 | [diff] [blame] | 236 | """Reboot Cr50 and wait for cr50 to reset""" |
| 237 | response = [] if self.using_ccd() else self.START_STR |
Mary Ruthven | 6d0a39a | 2017-09-19 13:32:50 -0700 | [diff] [blame] | 238 | self.send_command_get_output('reboot', response) |
Mary Ruthven | fc25974 | 2017-08-08 14:25:50 -0700 | [diff] [blame] | 239 | |
| 240 | # ccd will stop working after the reboot. Wait until that happens and |
| 241 | # reenable it. |
| 242 | if self.using_ccd(): |
| 243 | self.wait_for_reboot() |
| 244 | |
| 245 | |
| 246 | def _uart_wait_for_reboot(self, timeout=60): |
| 247 | """Wait for the cr50 to reboot and enable the console. |
| 248 | |
| 249 | This will wait up to timeout seconds for cr50 to print the start string. |
| 250 | |
| 251 | Args: |
| 252 | timeout: seconds to wait to detect the reboot. |
| 253 | """ |
Mary Ruthven | ce81d6e | 2017-11-28 14:48:22 -0800 | [diff] [blame] | 254 | original_timeout = float(self._servo.get('cr50_uart_timeout')) |
Mary Ruthven | fc25974 | 2017-08-08 14:25:50 -0700 | [diff] [blame] | 255 | # Change the console timeout to timeout, so we wait at least that long |
| 256 | # for cr50 to print the start string. |
Mary Ruthven | ce81d6e | 2017-11-28 14:48:22 -0800 | [diff] [blame] | 257 | self._servo.set_nocheck('cr50_uart_timeout', timeout) |
Mary Ruthven | fc25974 | 2017-08-08 14:25:50 -0700 | [diff] [blame] | 258 | try: |
| 259 | self.send_command_get_output('\n', self.START_STR) |
Mary Ruthven | 024c2dc | 2017-11-08 15:48:40 -0800 | [diff] [blame] | 260 | logging.debug('Detected cr50 reboot') |
Mary Ruthven | fc25974 | 2017-08-08 14:25:50 -0700 | [diff] [blame] | 261 | except error.TestFail, e: |
Mary Ruthven | 024c2dc | 2017-11-08 15:48:40 -0800 | [diff] [blame] | 262 | logging.debug('Failed to detect cr50 reboot') |
Mary Ruthven | fc25974 | 2017-08-08 14:25:50 -0700 | [diff] [blame] | 263 | # Reset the timeout. |
Mary Ruthven | ce81d6e | 2017-11-28 14:48:22 -0800 | [diff] [blame] | 264 | self._servo.set_nocheck('cr50_uart_timeout', original_timeout) |
Mary Ruthven | 0f3e834 | 2017-07-07 11:15:39 -0700 | [diff] [blame] | 265 | |
| 266 | |
| 267 | def wait_for_reboot(self, timeout=60): |
| 268 | """Wait for cr50 to reboot""" |
Mary Ruthven | 0ddea91 | 2017-06-27 14:31:58 -0700 | [diff] [blame] | 269 | if self.using_ccd(): |
Mary Ruthven | 0f3e834 | 2017-07-07 11:15:39 -0700 | [diff] [blame] | 270 | # Cr50 USB is reset when it reboots. Wait for the CCD connection to |
| 271 | # go down to detect the reboot. |
| 272 | self.wait_for_ccd_disable(timeout, raise_error=False) |
Mary Ruthven | 0ddea91 | 2017-06-27 14:31:58 -0700 | [diff] [blame] | 273 | self.ccd_enable() |
| 274 | else: |
Mary Ruthven | fc25974 | 2017-08-08 14:25:50 -0700 | [diff] [blame] | 275 | self._uart_wait_for_reboot(timeout) |
Mary Ruthven | 300b1fa | 2017-05-30 10:24:23 -0700 | [diff] [blame] | 276 | |
| 277 | |
Mary Ruthven | 4e1bb11 | 2017-08-24 13:17:24 -0700 | [diff] [blame] | 278 | def rollback(self, eraseflashinfo=True, chip_bid=None, chip_flags=None): |
| 279 | """Set the reset counter high enough to force a rollback then reboot |
| 280 | |
| 281 | Set the new board id before rolling back if one is given. |
| 282 | |
| 283 | Args: |
| 284 | eraseflashinfo: True if eraseflashinfo should be run before rollback |
| 285 | chip_bid: the integer representation of chip board id or None if the |
| 286 | board id should be erased during rollback |
| 287 | chip_flags: the integer representation of chip board id flags or |
| 288 | None if the board id should be erased during rollback |
| 289 | """ |
Mary Ruthven | 024c2dc | 2017-11-08 15:48:40 -0800 | [diff] [blame] | 290 | if (not self.has_command('rollback') or not |
| 291 | self.has_command('eraseflashinfo')): |
| 292 | raise error.TestError("need image with 'rollback' and " |
| 293 | "'eraseflashinfo'") |
Mary Ruthven | 300b1fa | 2017-05-30 10:24:23 -0700 | [diff] [blame] | 294 | |
Mary Ruthven | 3c5dcf9 | 2017-06-26 15:55:15 -0700 | [diff] [blame] | 295 | inactive_partition = self.get_inactive_version_info()[0] |
Mary Ruthven | 4e1bb11 | 2017-08-24 13:17:24 -0700 | [diff] [blame] | 296 | # Set the board id if both the board id and flags have been given. |
| 297 | set_bid = chip_bid and chip_flags |
| 298 | |
| 299 | # Erase the infomap |
| 300 | if eraseflashinfo or set_bid: |
Mary Ruthven | 3c5dcf9 | 2017-06-26 15:55:15 -0700 | [diff] [blame] | 301 | self.send_command('eraseflashinfo') |
Mary Ruthven | 300b1fa | 2017-05-30 10:24:23 -0700 | [diff] [blame] | 302 | |
Mary Ruthven | 4e1bb11 | 2017-08-24 13:17:24 -0700 | [diff] [blame] | 303 | # Update the board id after it has been erased |
| 304 | if set_bid: |
| 305 | self.send_command('bid 0x%x 0x%x' % (chip_bid, chip_flags)) |
| 306 | |
Mary Ruthven | c82325e | 2018-03-27 20:40:45 -0700 | [diff] [blame] | 307 | if self.using_ccd(): |
| 308 | self.send_command('rollback') |
| 309 | self.wait_for_reboot() |
| 310 | else: |
| 311 | logging.debug(self.send_command_get_output('rollback', |
| 312 | ['.*Console is enabled'])[0]) |
Mary Ruthven | 300b1fa | 2017-05-30 10:24:23 -0700 | [diff] [blame] | 313 | |
Mary Ruthven | 3c5dcf9 | 2017-06-26 15:55:15 -0700 | [diff] [blame] | 314 | running_partition = self.get_active_version_info()[0] |
| 315 | if inactive_partition != running_partition: |
| 316 | raise error.TestError("Failed to rollback to inactive image") |
| 317 | |
| 318 | |
| 319 | def rolledback(self): |
| 320 | """Returns true if cr50 just rolled back""" |
Mary Ruthven | 6fbb812 | 2018-03-28 11:16:18 -0700 | [diff] [blame] | 321 | return 'Rollback detected' in self.send_command_get_output('sysinfo', |
Mary Ruthven | afe51ef | 2018-05-25 17:58:55 -0700 | [diff] [blame] | 322 | ['sysinfo.*>'])[0] |
Mary Ruthven | 3c5dcf9 | 2017-06-26 15:55:15 -0700 | [diff] [blame] | 323 | |
Mary Ruthven | 300b1fa | 2017-05-30 10:24:23 -0700 | [diff] [blame] | 324 | |
| 325 | def get_version_info(self, regexp): |
| 326 | """Get information from the version command""" |
Mary Ruthven | f23dde1 | 2018-05-25 15:50:09 -0700 | [diff] [blame] | 327 | return self.send_command_retry_get_output('ver', [regexp])[0][1::] |
Mary Ruthven | 300b1fa | 2017-05-30 10:24:23 -0700 | [diff] [blame] | 328 | |
| 329 | |
| 330 | def get_inactive_version_info(self): |
| 331 | """Get the active partition, version, and hash""" |
Mary Ruthven | d89b559 | 2017-09-28 11:41:10 -0700 | [diff] [blame] | 332 | return self.get_version_info(self.INACTIVE_VERSION) |
Mary Ruthven | 300b1fa | 2017-05-30 10:24:23 -0700 | [diff] [blame] | 333 | |
| 334 | |
| 335 | def get_active_version_info(self): |
| 336 | """Get the active partition, version, and hash""" |
Mary Ruthven | d89b559 | 2017-09-28 11:41:10 -0700 | [diff] [blame] | 337 | return self.get_version_info(self.ACTIVE_VERSION) |
Mary Ruthven | 300b1fa | 2017-05-30 10:24:23 -0700 | [diff] [blame] | 338 | |
| 339 | |
Mary Ruthven | ac1d147 | 2018-03-15 14:52:41 -0700 | [diff] [blame] | 340 | def using_prod_rw_keys(self): |
| 341 | """Returns True if the RW keyid is prod""" |
Mary Ruthven | f23dde1 | 2018-05-25 15:50:09 -0700 | [diff] [blame] | 342 | rv = self.send_command_retry_get_output('sysinfo', |
Mary Ruthven | ac1d147 | 2018-03-15 14:52:41 -0700 | [diff] [blame] | 343 | ['RW keyid:.*\(([a-z]+)\)']) |
| 344 | logging.info(rv) |
| 345 | return rv[0][1] == 'prod' |
| 346 | |
| 347 | |
Mary Ruthven | a30e065 | 2017-08-18 13:29:48 -0700 | [diff] [blame] | 348 | def get_active_board_id_str(self): |
| 349 | """Get the running image board id. |
| 350 | |
| 351 | Returns: |
| 352 | The board id string or None if the image does not support board id |
| 353 | or the image is not board id locked. |
| 354 | """ |
| 355 | # Getting the board id from the version console command is only |
| 356 | # supported in board id locked images .22 and above. Any image that is |
| 357 | # board id locked will have support for getting the image board id. |
| 358 | # |
| 359 | # If board id is not supported on the device, return None. This is |
| 360 | # still expected on all current non board id locked release images. |
Mary Ruthven | d73fe4a | 2017-12-12 21:55:09 -0800 | [diff] [blame] | 361 | try: |
| 362 | version_info = self.get_version_info(self.ACTIVE_BID) |
| 363 | except error.TestFail, e: |
| 364 | logging.info(e.message) |
Mary Ruthven | a30e065 | 2017-08-18 13:29:48 -0700 | [diff] [blame] | 365 | logging.info('Cannot use the version to get the board id') |
| 366 | return None |
| 367 | |
Mary Ruthven | d73fe4a | 2017-12-12 21:55:09 -0800 | [diff] [blame] | 368 | if self.BID_ERROR in version_info[4]: |
| 369 | raise error.TestError(version_info) |
| 370 | bid = version_info[4].split()[1] |
Mary Ruthven | a30e065 | 2017-08-18 13:29:48 -0700 | [diff] [blame] | 371 | return bid if bid != cr50_utils.EMPTY_IMAGE_BID else None |
| 372 | |
| 373 | |
Mary Ruthven | 2b7980b | 2017-06-28 15:05:30 -0700 | [diff] [blame] | 374 | def get_version(self): |
| 375 | """Get the RW version""" |
| 376 | return self.get_active_version_info()[1].strip() |
| 377 | |
| 378 | |
Mary Ruthven | 300b1fa | 2017-05-30 10:24:23 -0700 | [diff] [blame] | 379 | def using_servo_v4(self): |
| 380 | """Returns true if the console is being served using servo v4""" |
| 381 | return 'servo_v4' in self._servo.get_servo_version() |
| 382 | |
| 383 | |
| 384 | def using_ccd(self): |
| 385 | """Returns true if the console is being served using CCD""" |
| 386 | return 'ccd_cr50' in self._servo.get_servo_version() |
| 387 | |
| 388 | |
Mary Ruthven | fd3d7aa | 2018-01-26 17:07:52 -0800 | [diff] [blame] | 389 | def ccd_is_enabled(self): |
| 390 | """Return True if ccd is enabled. |
| 391 | |
| 392 | If the test is running through ccd, return the ccd_state value. If |
| 393 | a flex cable is being used, use the CCD_MODE_L gpio setting to determine |
| 394 | if Cr50 has ccd enabled. |
Mary Ruthven | 300b1fa | 2017-05-30 10:24:23 -0700 | [diff] [blame] | 395 | |
| 396 | Returns: |
| 397 | 'off' or 'on' based on whether the cr50 console is working. |
| 398 | """ |
Mary Ruthven | fd3d7aa | 2018-01-26 17:07:52 -0800 | [diff] [blame] | 399 | if self.using_ccd(): |
| 400 | return self._servo.get('ccd_state') == 'on' |
| 401 | else: |
Mary Ruthven | f23dde1 | 2018-05-25 15:50:09 -0700 | [diff] [blame] | 402 | result = self.send_command_retry_get_output('gpioget', |
Mary Ruthven | fd3d7aa | 2018-01-26 17:07:52 -0800 | [diff] [blame] | 403 | ['(0|1)..CCD_MODE_L']) |
| 404 | return not bool(int(result[0][1])) |
Mary Ruthven | 300b1fa | 2017-05-30 10:24:23 -0700 | [diff] [blame] | 405 | |
| 406 | |
Mary Ruthven | fd3d7aa | 2018-01-26 17:07:52 -0800 | [diff] [blame] | 407 | @servo_v4_command |
| 408 | def wait_for_ccd_state(self, state, timeout, raise_error): |
Mary Ruthven | 300b1fa | 2017-05-30 10:24:23 -0700 | [diff] [blame] | 409 | """Wait up to timeout seconds for CCD to be 'on' or 'off' |
| 410 | Args: |
| 411 | state: a string either 'on' or 'off'. |
| 412 | timeout: time in seconds to wait |
| 413 | raise_error: Raise TestFail if the value is state is not reached. |
| 414 | |
| 415 | Raises |
| 416 | TestFail if ccd never reaches the specified state |
| 417 | """ |
Mary Ruthven | fd3d7aa | 2018-01-26 17:07:52 -0800 | [diff] [blame] | 418 | wait_for_enable = state == 'on' |
Mary Ruthven | 300b1fa | 2017-05-30 10:24:23 -0700 | [diff] [blame] | 419 | logging.info("Wait until ccd is '%s'", state) |
Mary Ruthven | fd3d7aa | 2018-01-26 17:07:52 -0800 | [diff] [blame] | 420 | value = utils.wait_for_value(self.ccd_is_enabled, wait_for_enable, |
Mary Ruthven | 300b1fa | 2017-05-30 10:24:23 -0700 | [diff] [blame] | 421 | timeout_sec=timeout) |
Mary Ruthven | fd3d7aa | 2018-01-26 17:07:52 -0800 | [diff] [blame] | 422 | if value != wait_for_enable: |
Mary Ruthven | 300b1fa | 2017-05-30 10:24:23 -0700 | [diff] [blame] | 423 | error_msg = "timed out before detecting ccd '%s'" % state |
| 424 | if raise_error: |
| 425 | raise error.TestFail(error_msg) |
| 426 | logging.warning(error_msg) |
Mary Ruthven | fd3d7aa | 2018-01-26 17:07:52 -0800 | [diff] [blame] | 427 | logging.info("ccd is '%s'", state) |
Mary Ruthven | 300b1fa | 2017-05-30 10:24:23 -0700 | [diff] [blame] | 428 | |
| 429 | |
Mary Ruthven | fd3d7aa | 2018-01-26 17:07:52 -0800 | [diff] [blame] | 430 | @servo_v4_command |
Mary Ruthven | 300b1fa | 2017-05-30 10:24:23 -0700 | [diff] [blame] | 431 | def wait_for_ccd_disable(self, timeout=60, raise_error=True): |
| 432 | """Wait for the cr50 console to stop working""" |
| 433 | self.wait_for_ccd_state('off', timeout, raise_error) |
| 434 | |
| 435 | |
Mary Ruthven | fd3d7aa | 2018-01-26 17:07:52 -0800 | [diff] [blame] | 436 | @servo_v4_command |
| 437 | def wait_for_ccd_enable(self, timeout=60, raise_error=False): |
Mary Ruthven | 300b1fa | 2017-05-30 10:24:23 -0700 | [diff] [blame] | 438 | """Wait for the cr50 console to start working""" |
Mary Ruthven | fd3d7aa | 2018-01-26 17:07:52 -0800 | [diff] [blame] | 439 | self.wait_for_ccd_state('on', timeout, raise_error) |
Mary Ruthven | 300b1fa | 2017-05-30 10:24:23 -0700 | [diff] [blame] | 440 | |
| 441 | |
Mary Ruthven | fd3d7aa | 2018-01-26 17:07:52 -0800 | [diff] [blame] | 442 | @servo_v4_command |
| 443 | def ccd_disable(self, raise_error=True): |
Mary Ruthven | 300b1fa | 2017-05-30 10:24:23 -0700 | [diff] [blame] | 444 | """Change the values of the CC lines to disable CCD""" |
Mary Ruthven | fd3d7aa | 2018-01-26 17:07:52 -0800 | [diff] [blame] | 445 | logging.info("disable ccd") |
| 446 | self._servo.set_nocheck('servo_v4_dts_mode', 'off') |
| 447 | self.wait_for_ccd_disable(raise_error=raise_error) |
Mary Ruthven | 300b1fa | 2017-05-30 10:24:23 -0700 | [diff] [blame] | 448 | |
| 449 | |
Mary Ruthven | fd3d7aa | 2018-01-26 17:07:52 -0800 | [diff] [blame] | 450 | @servo_v4_command |
| 451 | def ccd_enable(self, raise_error=False): |
Mary Ruthven | 300b1fa | 2017-05-30 10:24:23 -0700 | [diff] [blame] | 452 | """Reenable CCD and reset servo interfaces""" |
| 453 | logging.info("reenable ccd") |
Mary Ruthven | 300b1fa | 2017-05-30 10:24:23 -0700 | [diff] [blame] | 454 | self._servo.set_nocheck('servo_v4_dts_mode', 'on') |
Mary Ruthven | fd3d7aa | 2018-01-26 17:07:52 -0800 | [diff] [blame] | 455 | # If the test is actually running with ccd, reset usb and wait for |
| 456 | # communication to come up. |
| 457 | if self.using_ccd(): |
| 458 | self._servo.set_nocheck('power_state', 'ccd_reset') |
| 459 | self.wait_for_ccd_enable(raise_error=raise_error) |
Mary Ruthven | 5655829 | 2017-05-30 12:31:29 -0700 | [diff] [blame] | 460 | |
| 461 | |
Mary Ruthven | ec8d3d2 | 2017-09-15 14:45:21 -0700 | [diff] [blame] | 462 | def _level_change_req_pp(self, level): |
| 463 | """Returns True if setting the level will require physical presence""" |
| 464 | testlab_pp = level != 'testlab open' and 'testlab' in level |
| 465 | open_pp = level == 'open' |
| 466 | return testlab_pp or open_pp |
Mary Ruthven | 5655829 | 2017-05-30 12:31:29 -0700 | [diff] [blame] | 467 | |
| 468 | |
Mary Ruthven | 2478d85 | 2017-12-13 13:09:02 -0800 | [diff] [blame] | 469 | def _state_to_bool(self, state): |
| 470 | """Converts the state string to True or False""" |
| 471 | # TODO(mruthven): compare to 'on' once servo is up to date in the lab |
| 472 | return state.lower() in self.ON_STRINGS |
| 473 | |
| 474 | |
Mary Ruthven | 603a661 | 2018-05-31 15:24:57 -0700 | [diff] [blame^] | 475 | def fast_open(self, enable_testlab=False): |
| 476 | """Try to use testlab open. If that fails do regular open |
| 477 | |
| 478 | Args: |
| 479 | enable_testlab: If True enable testlab after device is open |
| 480 | """ |
| 481 | self.send_command('ccd testlab open') |
| 482 | self.set_ccd_level('open') |
| 483 | if enable_testlab: |
| 484 | self.set_ccd_testlab('on') |
| 485 | |
| 486 | |
Mary Ruthven | 2478d85 | 2017-12-13 13:09:02 -0800 | [diff] [blame] | 487 | def testlab_is_on(self): |
| 488 | """Returns True of testlab mode is on""" |
| 489 | return self._state_to_bool(self._servo.get('cr50_testlab')) |
| 490 | |
| 491 | |
Mary Ruthven | 6260024 | 2017-12-14 14:30:46 -0800 | [diff] [blame] | 492 | def set_ccd_testlab(self, state): |
Mary Ruthven | 3ff9949 | 2017-11-06 16:29:26 -0800 | [diff] [blame] | 493 | """Set the testlab mode |
| 494 | |
| 495 | Args: |
Mary Ruthven | 2478d85 | 2017-12-13 13:09:02 -0800 | [diff] [blame] | 496 | state: the desired testlab mode string: 'on' or 'off' |
Mary Ruthven | 3ff9949 | 2017-11-06 16:29:26 -0800 | [diff] [blame] | 497 | |
| 498 | Raises: |
| 499 | TestFail if testlab mode was not changed |
| 500 | """ |
| 501 | if self.using_ccd(): |
| 502 | raise error.TestError('Cannot set testlab mode with CCD. Use flex ' |
| 503 | 'cable instead.') |
| 504 | |
Mary Ruthven | 2478d85 | 2017-12-13 13:09:02 -0800 | [diff] [blame] | 505 | request_on = self._state_to_bool(state) |
| 506 | testlab_on = self.testlab_is_on() |
| 507 | request_str = 'on' if request_on else 'off' |
| 508 | |
| 509 | if testlab_on == request_on: |
| 510 | logging.info('ccd testlab already set to %s', request_str) |
Mary Ruthven | 3ff9949 | 2017-11-06 16:29:26 -0800 | [diff] [blame] | 511 | return |
| 512 | |
Mary Ruthven | b975793 | 2017-12-14 13:17:18 -0800 | [diff] [blame] | 513 | original_level = self.get_ccd_level() |
Mary Ruthven | 3ff9949 | 2017-11-06 16:29:26 -0800 | [diff] [blame] | 514 | |
| 515 | # We can only change the testlab mode when the device is open. If |
| 516 | # testlab mode is already enabled, we can go directly to open using 'ccd |
| 517 | # testlab open'. This will save 5 minutes, because we can skip the |
| 518 | # physical presence check. |
Mary Ruthven | 2478d85 | 2017-12-13 13:09:02 -0800 | [diff] [blame] | 519 | if testlab_on: |
Mary Ruthven | 3ff9949 | 2017-11-06 16:29:26 -0800 | [diff] [blame] | 520 | self.send_command('ccd testlab open') |
| 521 | else: |
Mary Ruthven | 9498d67 | 2017-12-14 13:50:39 -0800 | [diff] [blame] | 522 | self.set_ccd_level('open') |
Mary Ruthven | 3ff9949 | 2017-11-06 16:29:26 -0800 | [diff] [blame] | 523 | |
| 524 | # Set testlab mode |
Mary Ruthven | 2478d85 | 2017-12-13 13:09:02 -0800 | [diff] [blame] | 525 | rv = self.send_command_get_output('ccd testlab %s' % request_str, |
Mary Ruthven | afe51ef | 2018-05-25 17:58:55 -0700 | [diff] [blame] | 526 | ['ccd.*>'])[0] |
Mary Ruthven | 3ff9949 | 2017-11-06 16:29:26 -0800 | [diff] [blame] | 527 | if 'Access Denied' in rv: |
Mary Ruthven | 2478d85 | 2017-12-13 13:09:02 -0800 | [diff] [blame] | 528 | raise error.TestFail("'ccd %s' %s" % (request_str, rv)) |
Mary Ruthven | 3ff9949 | 2017-11-06 16:29:26 -0800 | [diff] [blame] | 529 | |
| 530 | # Press the power button once a second for 15 seconds. |
| 531 | self.run_pp(self.PP_SHORT) |
| 532 | |
Mary Ruthven | 9498d67 | 2017-12-14 13:50:39 -0800 | [diff] [blame] | 533 | self.set_ccd_level(original_level) |
Mary Ruthven | 3ff9949 | 2017-11-06 16:29:26 -0800 | [diff] [blame] | 534 | |
Mary Ruthven | d43ebd3 | 2018-01-09 11:08:43 -0800 | [diff] [blame] | 535 | if request_on != self.testlab_is_on(): |
Mary Ruthven | 3ff9949 | 2017-11-06 16:29:26 -0800 | [diff] [blame] | 536 | raise error.TestFail('Failed to set ccd testlab to %s' % state) |
| 537 | |
| 538 | |
Mary Ruthven | b975793 | 2017-12-14 13:17:18 -0800 | [diff] [blame] | 539 | def get_ccd_level(self): |
| 540 | """Returns the current ccd privilege level""" |
| 541 | # TODO(mruthven): delete the part removing the trailing 'ed' once |
| 542 | # servo is up to date in the lab |
| 543 | return self._servo.get('cr50_ccd_level').lower().rstrip('ed') |
Mary Ruthven | 5655829 | 2017-05-30 12:31:29 -0700 | [diff] [blame] | 544 | |
Mary Ruthven | b975793 | 2017-12-14 13:17:18 -0800 | [diff] [blame] | 545 | |
| 546 | def set_ccd_level(self, level): |
| 547 | """Set the Cr50 CCD privilege level. |
| 548 | |
| 549 | Args: |
| 550 | level: a string of the ccd privilege level: 'open', 'lock', or |
| 551 | 'unlock'. |
| 552 | |
| 553 | Raises: |
| 554 | TestFail if the level couldn't be set |
| 555 | .""" |
| 556 | # TODO(mruthven): add support for CCD password |
| 557 | level = level.lower() |
| 558 | |
| 559 | if level == self.get_ccd_level(): |
Mary Ruthven | ec8d3d2 | 2017-09-15 14:45:21 -0700 | [diff] [blame] | 560 | logging.info('CCD privilege level is already %s', level) |
| 561 | return |
Mary Ruthven | 5655829 | 2017-05-30 12:31:29 -0700 | [diff] [blame] | 562 | |
Mary Ruthven | ec8d3d2 | 2017-09-15 14:45:21 -0700 | [diff] [blame] | 563 | if 'testlab' in level: |
| 564 | raise error.TestError("Can't change testlab mode using " |
| 565 | "ccd_set_level") |
Mary Ruthven | 5655829 | 2017-05-30 12:31:29 -0700 | [diff] [blame] | 566 | |
Mary Ruthven | 2478d85 | 2017-12-13 13:09:02 -0800 | [diff] [blame] | 567 | testlab_on = self._state_to_bool(self._servo.get('cr50_testlab')) |
Mary Ruthven | ec8d3d2 | 2017-09-15 14:45:21 -0700 | [diff] [blame] | 568 | req_pp = self._level_change_req_pp(level) |
| 569 | has_pp = not self.using_ccd() |
| 570 | dbg_en = 'DBG' in self._servo.get('cr50_version') |
| 571 | |
| 572 | if req_pp and not has_pp: |
| 573 | raise error.TestError("Can't change privilege level to '%s' " |
| 574 | "without physical presence." % level) |
| 575 | |
Mary Ruthven | 2478d85 | 2017-12-13 13:09:02 -0800 | [diff] [blame] | 576 | if not testlab_on and not has_pp: |
Mary Ruthven | ec8d3d2 | 2017-09-15 14:45:21 -0700 | [diff] [blame] | 577 | raise error.TestError("Wont change privilege level without " |
| 578 | "physical presence or testlab mode enabled") |
| 579 | |
Mary Ruthven | ec8d3d2 | 2017-09-15 14:45:21 -0700 | [diff] [blame] | 580 | # Start the unlock process. |
Mary Ruthven | afe51ef | 2018-05-25 17:58:55 -0700 | [diff] [blame] | 581 | rv = self.send_command_get_output('ccd %s' % level, ['ccd.*>'])[0] |
Mary Ruthven | 3ff9949 | 2017-11-06 16:29:26 -0800 | [diff] [blame] | 582 | logging.info(rv) |
| 583 | if 'Access Denied' in rv: |
| 584 | raise error.TestFail("'ccd %s' %s" % (level, rv)) |
Mary Ruthven | ec8d3d2 | 2017-09-15 14:45:21 -0700 | [diff] [blame] | 585 | |
Mary Ruthven | 3ff9949 | 2017-11-06 16:29:26 -0800 | [diff] [blame] | 586 | # Press the power button once a second, if we need physical presence. |
Mary Ruthven | ec8d3d2 | 2017-09-15 14:45:21 -0700 | [diff] [blame] | 587 | if req_pp: |
| 588 | # DBG images have shorter unlock processes |
Mary Ruthven | 3ff9949 | 2017-11-06 16:29:26 -0800 | [diff] [blame] | 589 | self.run_pp(self.PP_SHORT if dbg_en else self.PP_LONG) |
Mary Ruthven | ec8d3d2 | 2017-09-15 14:45:21 -0700 | [diff] [blame] | 590 | |
Mary Ruthven | b975793 | 2017-12-14 13:17:18 -0800 | [diff] [blame] | 591 | if level != self.get_ccd_level(): |
Mary Ruthven | ec8d3d2 | 2017-09-15 14:45:21 -0700 | [diff] [blame] | 592 | raise error.TestFail('Could not set privilege level to %s' % level) |
| 593 | |
| 594 | logging.info('Successfully set CCD privelege level to %s', level) |
Mary Ruthven | 4d3a77a | 2017-08-10 17:27:59 -0700 | [diff] [blame] | 595 | |
| 596 | |
Mary Ruthven | 3ff9949 | 2017-11-06 16:29:26 -0800 | [diff] [blame] | 597 | def run_pp(self, unlock_timeout): |
| 598 | """Press the power button a for unlock_timeout seconds. |
| 599 | |
| 600 | This will press the power button many more times than it needs to be |
| 601 | pressed. Cr50 doesn't care if you press it too often. It just cares that |
| 602 | you press the power button at least once within the detect interval. |
| 603 | |
| 604 | For privilege level changes you need to press the power button 5 times |
| 605 | in the short interval and then 4 times within the long interval. |
| 606 | Short Interval |
| 607 | 100msec < power button press < 5 seconds |
| 608 | Long Interval |
| 609 | 60s < power button press < 300s |
| 610 | |
| 611 | For testlab enable/disable you must press the power button 5 times |
| 612 | spaced between 100msec and 5 seconds apart. |
| 613 | """ |
| 614 | end_time = time.time() + unlock_timeout |
| 615 | |
| 616 | logging.info('Pressing power button for %ds to unlock the console.', |
| 617 | unlock_timeout) |
| 618 | logging.info('The process should end at %s', time.ctime(end_time)) |
| 619 | |
| 620 | # Press the power button once a second to unlock the console. |
| 621 | while time.time() < end_time: |
| 622 | self._servo.power_short_press() |
| 623 | time.sleep(1) |
| 624 | |
| 625 | |
Mary Ruthven | 4d3a77a | 2017-08-10 17:27:59 -0700 | [diff] [blame] | 626 | def gettime(self): |
| 627 | """Get the current cr50 system time""" |
Mary Ruthven | f23dde1 | 2018-05-25 15:50:09 -0700 | [diff] [blame] | 628 | result = self.send_command_retry_get_output('gettime', [' = (.*) s']) |
Mary Ruthven | 4d3a77a | 2017-08-10 17:27:59 -0700 | [diff] [blame] | 629 | return float(result[0][1]) |
| 630 | |
Mary Ruthven | a30e065 | 2017-08-18 13:29:48 -0700 | [diff] [blame] | 631 | |
Mary Ruthven | fd3d7aa | 2018-01-26 17:07:52 -0800 | [diff] [blame] | 632 | def servo_v4_supports_dts_mode(self): |
| 633 | """Returns True if cr50 registers changes in servo v4 dts mode.""" |
| 634 | # This is to test that Cr50 actually recognizes the change in ccd state |
| 635 | # We cant do that with tests using ccd, because the cr50 communication |
| 636 | # goes down once ccd is enabled. |
| 637 | if 'servo_v4_with_servo_micro' != self._servo.get_servo_version(): |
| 638 | return False |
| 639 | |
Mary Ruthven | 0a999e6 | 2018-04-18 16:11:21 -0700 | [diff] [blame] | 640 | ccd_start = 'on' if self.ccd_is_enabled() else 'off' |
| 641 | dts_start = self._servo.get('servo_v4_dts_mode') |
Mary Ruthven | fd3d7aa | 2018-01-26 17:07:52 -0800 | [diff] [blame] | 642 | try: |
| 643 | # Verify both ccd enable and disable |
| 644 | self.ccd_disable(raise_error=True) |
| 645 | self.ccd_enable(raise_error=True) |
| 646 | rv = True |
| 647 | except Exception, e: |
| 648 | logging.info(e) |
| 649 | rv = False |
Mary Ruthven | 0a999e6 | 2018-04-18 16:11:21 -0700 | [diff] [blame] | 650 | self._servo.set_nocheck('servo_v4_dts_mode', dts_start) |
| 651 | self.wait_for_ccd_state(ccd_start, 60, True) |
Mary Ruthven | fd3d7aa | 2018-01-26 17:07:52 -0800 | [diff] [blame] | 652 | logging.info('Test setup does%s support servo DTS mode', |
| 653 | '' if rv else 'n\'t') |
| 654 | return rv |
| 655 | |
| 656 | |
Mary Ruthven | 4d3a77a | 2017-08-10 17:27:59 -0700 | [diff] [blame] | 657 | def wait_until_update_is_allowed(self): |
| 658 | """Wait until cr50 will be able to accept an update. |
| 659 | |
| 660 | Cr50 rejects any attempt to update if it has been less than 60 seconds |
| 661 | since it last recovered from deep sleep or came up from reboot. This |
| 662 | will wait until cr50 gettime shows a time greater than 60. |
| 663 | """ |
Mary Ruthven | 91d8618 | 2017-09-29 13:46:21 -0700 | [diff] [blame] | 664 | if self.get_active_version_info()[2]: |
| 665 | logging.info("Running DBG image. Don't need to wait for update.") |
| 666 | return |
Mary Ruthven | 4d3a77a | 2017-08-10 17:27:59 -0700 | [diff] [blame] | 667 | cr50_time = self.gettime() |
| 668 | if cr50_time < 60: |
| 669 | sleep_time = 61 - cr50_time |
| 670 | logging.info('Cr50 has been up for %ds waiting %ds before update', |
| 671 | cr50_time, sleep_time) |
| 672 | time.sleep(sleep_time) |