blob: 311e649d55b1ac7472a1d751f77c54a437c72d95 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001# SPDX-License-Identifier: GPL-2.0
Stephen Warren10e50632016-01-15 11:15:24 -07002# Copyright (c) 2015 Stephen Warren
3# Copyright (c) 2015-2016, NVIDIA CORPORATION. All rights reserved.
Stephen Warren10e50632016-01-15 11:15:24 -07004
5# Common logic to interact with U-Boot via the console. This class provides
6# the interface that tests use to execute U-Boot shell commands and wait for
7# their results. Sub-classes exist to perform board-type-specific setup
8# operations, such as spawning a sub-process for Sandbox, or attaching to the
9# serial console of real hardware.
10
11import multiplexed_log
12import os
13import pytest
14import re
15import sys
Stephen Warren97a54662016-01-22 12:30:09 -070016import u_boot_spawn
Simon Glass7a1e9b42024-10-09 18:29:04 -060017from u_boot_spawn import BootFail, Timeout, Unexpected, handle_exception
Stephen Warren10e50632016-01-15 11:15:24 -070018
19# Regexes for text we expect U-Boot to send to the console.
Heiko Schocherce251232018-12-05 11:29:54 +010020pattern_u_boot_spl_signon = re.compile('(U-Boot SPL \\d{4}\\.\\d{2}[^\r\n]*\\))')
Stephen Warren5af83c42016-02-05 18:04:43 -070021pattern_u_boot_main_signon = re.compile('(U-Boot \\d{4}\\.\\d{2}[^\r\n]*\\))')
Stephen Warren10e50632016-01-15 11:15:24 -070022pattern_stop_autoboot_prompt = re.compile('Hit any key to stop autoboot: ')
23pattern_unknown_command = re.compile('Unknown command \'.*\' - try \'help\'')
24pattern_error_notification = re.compile('## Error: ')
Stephen Warren3bd79d32016-01-27 23:57:50 -070025pattern_error_please_reset = re.compile('### ERROR ### Please RESET the board ###')
Simon Glass6cffce92024-11-12 07:13:15 -070026pattern_ready_prompt = re.compile('U-Boot is ready')
Stephen Warren10e50632016-01-15 11:15:24 -070027
Stephen Warren1115a972016-01-27 23:57:48 -070028PAT_ID = 0
29PAT_RE = 1
30
Simon Glass64914152024-10-09 18:28:58 -060031# Timeout before expecting the console to be ready (in milliseconds)
32TIMEOUT_MS = 30000
33
Stephen Warren1115a972016-01-27 23:57:48 -070034bad_pattern_defs = (
35 ('spl_signon', pattern_u_boot_spl_signon),
36 ('main_signon', pattern_u_boot_main_signon),
37 ('stop_autoboot_prompt', pattern_stop_autoboot_prompt),
38 ('unknown_command', pattern_unknown_command),
39 ('error_notification', pattern_error_notification),
Stephen Warren3bd79d32016-01-27 23:57:50 -070040 ('error_please_reset', pattern_error_please_reset),
Stephen Warren1115a972016-01-27 23:57:48 -070041)
42
Stephen Warren10e50632016-01-15 11:15:24 -070043class ConsoleDisableCheck(object):
Stephen Warren75e731e2016-01-26 13:41:30 -070044 """Context manager (for Python's with statement) that temporarily disables
Stephen Warren10e50632016-01-15 11:15:24 -070045 the specified console output error check. This is useful when deliberately
46 executing a command that is known to trigger one of the error checks, in
47 order to test that the error condition is actually raised. This class is
48 used internally by ConsoleBase::disable_check(); it is not intended for
Stephen Warren75e731e2016-01-26 13:41:30 -070049 direct usage."""
Stephen Warren10e50632016-01-15 11:15:24 -070050
51 def __init__(self, console, check_type):
52 self.console = console
53 self.check_type = check_type
54
55 def __enter__(self):
56 self.console.disable_check_count[self.check_type] += 1
Stephen Warren1115a972016-01-27 23:57:48 -070057 self.console.eval_bad_patterns()
Stephen Warren10e50632016-01-15 11:15:24 -070058
59 def __exit__(self, extype, value, traceback):
60 self.console.disable_check_count[self.check_type] -= 1
Stephen Warren1115a972016-01-27 23:57:48 -070061 self.console.eval_bad_patterns()
Stephen Warren10e50632016-01-15 11:15:24 -070062
Love Kumarc35e66e2024-05-22 18:45:13 +053063class ConsoleEnableCheck(object):
64 """Context manager (for Python's with statement) that temporarily enables
65 the specified console output error check. This is useful when executing a
66 command that might raise an extra bad pattern, beyond the default bad
67 patterns, in order to validate that the extra bad pattern is actually
68 detected. This class is used internally by ConsoleBase::enable_check(); it
69 is not intended for direct usage."""
70
71 def __init__(self, console, check_type, check_pattern):
72 self.console = console
73 self.check_type = check_type
74 self.check_pattern = check_pattern
75
76 def __enter__(self):
77 global bad_pattern_defs
78 self.default_bad_patterns = bad_pattern_defs
79 bad_pattern_defs += ((self.check_type, self.check_pattern),)
80 self.console.disable_check_count = {pat[PAT_ID]: 0 for pat in bad_pattern_defs}
81 self.console.eval_bad_patterns()
82
83 def __exit__(self, extype, value, traceback):
84 global bad_pattern_defs
85 bad_pattern_defs = self.default_bad_patterns
86 self.console.disable_check_count = {pat[PAT_ID]: 0 for pat in bad_pattern_defs}
87 self.console.eval_bad_patterns()
88
Michal Simek6b463182016-05-19 07:57:41 +020089class ConsoleSetupTimeout(object):
90 """Context manager (for Python's with statement) that temporarily sets up
91 timeout for specific command. This is useful when execution time is greater
92 then default 30s."""
93
94 def __init__(self, console, timeout):
95 self.p = console.p
96 self.orig_timeout = self.p.timeout
97 self.p.timeout = timeout
98
99 def __enter__(self):
100 return self
101
102 def __exit__(self, extype, value, traceback):
103 self.p.timeout = self.orig_timeout
104
Stephen Warren10e50632016-01-15 11:15:24 -0700105class ConsoleBase(object):
Stephen Warren75e731e2016-01-26 13:41:30 -0700106 """The interface through which test functions interact with the U-Boot
Stephen Warren10e50632016-01-15 11:15:24 -0700107 console. This primarily involves executing shell commands, capturing their
108 results, and checking for common error conditions. Some common utilities
Stephen Warren75e731e2016-01-26 13:41:30 -0700109 are also provided too."""
Stephen Warren10e50632016-01-15 11:15:24 -0700110
111 def __init__(self, log, config, max_fifo_fill):
Stephen Warren75e731e2016-01-26 13:41:30 -0700112 """Initialize a U-Boot console connection.
Stephen Warren10e50632016-01-15 11:15:24 -0700113
114 Can only usefully be called by sub-classes.
115
116 Args:
Simon Glass53d65832024-10-09 18:29:05 -0600117 log: A multiplexed_log.Logfile object, to which the U-Boot output
Stephen Warren10e50632016-01-15 11:15:24 -0700118 will be logged.
119 config: A configuration data structure, as built by conftest.py.
120 max_fifo_fill: The maximum number of characters to send to U-Boot
121 command-line before waiting for U-Boot to echo the characters
122 back. For UART-based HW without HW flow control, this value
123 should be set less than the UART RX FIFO size to avoid
124 overflow, assuming that U-Boot can't keep up with full-rate
125 traffic at the baud rate.
126
127 Returns:
128 Nothing.
Stephen Warren75e731e2016-01-26 13:41:30 -0700129 """
Stephen Warren10e50632016-01-15 11:15:24 -0700130
131 self.log = log
132 self.config = config
133 self.max_fifo_fill = max_fifo_fill
134
135 self.logstream = self.log.get_stream('console', sys.stdout)
136
137 # Array slice removes leading/trailing quotes
138 self.prompt = self.config.buildconfig['config_sys_prompt'][1:-1]
Stephen Warren6d083402016-08-16 19:58:59 -0600139 self.prompt_compiled = re.compile('^' + re.escape(self.prompt), re.MULTILINE)
Stephen Warren10e50632016-01-15 11:15:24 -0700140 self.p = None
Stephen Warren1115a972016-01-27 23:57:48 -0700141 self.disable_check_count = {pat[PAT_ID]: 0 for pat in bad_pattern_defs}
142 self.eval_bad_patterns()
Stephen Warren10e50632016-01-15 11:15:24 -0700143
144 self.at_prompt = False
145 self.at_prompt_logevt = None
Stephen Warren10e50632016-01-15 11:15:24 -0700146
Simon Glassf7990762022-02-11 13:23:23 -0700147 def get_spawn(self):
148 # This is not called, ssubclass must define this.
149 # Return a value to avoid:
150 # u_boot_console_base.py:348:12: E1128: Assigning result of a function
151 # call, where the function returns None (assignment-from-none)
152 return u_boot_spawn.Spawn([])
153
154
Stephen Warren1115a972016-01-27 23:57:48 -0700155 def eval_bad_patterns(self):
156 self.bad_patterns = [pat[PAT_RE] for pat in bad_pattern_defs \
157 if self.disable_check_count[pat[PAT_ID]] == 0]
158 self.bad_pattern_ids = [pat[PAT_ID] for pat in bad_pattern_defs \
159 if self.disable_check_count[pat[PAT_ID]] == 0]
160
Stephen Warren10e50632016-01-15 11:15:24 -0700161 def close(self):
Stephen Warren75e731e2016-01-26 13:41:30 -0700162 """Terminate the connection to the U-Boot console.
Stephen Warren10e50632016-01-15 11:15:24 -0700163
164 This function is only useful once all interaction with U-Boot is
165 complete. Once this function is called, data cannot be sent to or
166 received from U-Boot.
167
168 Args:
169 None.
170
171 Returns:
172 Nothing.
Stephen Warren75e731e2016-01-26 13:41:30 -0700173 """
Stephen Warren10e50632016-01-15 11:15:24 -0700174
175 if self.p:
176 self.p.close()
177 self.logstream.close()
178
Masami Hiramatsu4d3b9962022-02-16 15:16:02 +0900179 def wait_for_boot_prompt(self, loop_num = 1):
Masami Hiramatsu0ff22782022-02-16 15:15:52 +0900180 """Wait for the boot up until command prompt. This is for internal use only.
181 """
182 try:
183 bcfg = self.config.buildconfig
Masami Hiramatsu0ff22782022-02-16 15:15:52 +0900184 config_spl_serial = bcfg.get('config_spl_serial', 'n') == 'y'
185 env_spl_skipped = self.config.env.get('env__spl_skipped', False)
Tom Rinidec7ea02024-05-20 13:35:03 -0600186 env_spl_banner_times = self.config.env.get('env__spl_banner_times', 1)
Masami Hiramatsu0ff22782022-02-16 15:15:52 +0900187
Masami Hiramatsu4d3b9962022-02-16 15:16:02 +0900188 while loop_num > 0:
189 loop_num -= 1
Tom Rinidec7ea02024-05-20 13:35:03 -0600190 while config_spl_serial and not env_spl_skipped and env_spl_banner_times > 0:
Masami Hiramatsu4d3b9962022-02-16 15:16:02 +0900191 m = self.p.expect([pattern_u_boot_spl_signon] +
192 self.bad_patterns)
193 if m != 0:
Simon Glass573171e2024-10-09 18:29:02 -0600194 raise BootFail('Bad pattern found on SPL console: ' +
Masami Hiramatsu4d3b9962022-02-16 15:16:02 +0900195 self.bad_pattern_ids[m - 1])
Tom Rinidec7ea02024-05-20 13:35:03 -0600196 env_spl_banner_times -= 1
197
Masami Hiramatsu4d3b9962022-02-16 15:16:02 +0900198 m = self.p.expect([pattern_u_boot_main_signon] + self.bad_patterns)
Masami Hiramatsu0ff22782022-02-16 15:15:52 +0900199 if m != 0:
Simon Glass573171e2024-10-09 18:29:02 -0600200 raise BootFail('Bad pattern found on console: ' +
Masami Hiramatsu0ff22782022-02-16 15:15:52 +0900201 self.bad_pattern_ids[m - 1])
Masami Hiramatsu0ff22782022-02-16 15:15:52 +0900202 self.u_boot_version_string = self.p.after
203 while True:
Simon Glass6cffce92024-11-12 07:13:15 -0700204 m = self.p.expect([self.prompt_compiled, pattern_ready_prompt,
Masami Hiramatsu0ff22782022-02-16 15:15:52 +0900205 pattern_stop_autoboot_prompt] + self.bad_patterns)
Simon Glass6cffce92024-11-12 07:13:15 -0700206 if m == 0 or m == 1:
Masami Hiramatsu0ff22782022-02-16 15:15:52 +0900207 break
Simon Glass6cffce92024-11-12 07:13:15 -0700208 if m == 2:
Masami Hiramatsu0ff22782022-02-16 15:15:52 +0900209 self.p.send(' ')
210 continue
Simon Glass573171e2024-10-09 18:29:02 -0600211 raise BootFail('Bad pattern found on console: ' +
Simon Glass6cffce92024-11-12 07:13:15 -0700212 self.bad_pattern_ids[m - 3])
Masami Hiramatsu0ff22782022-02-16 15:15:52 +0900213
Masami Hiramatsu0ff22782022-02-16 15:15:52 +0900214 finally:
215 self.log.timestamp()
216
Stephen Warren10e50632016-01-15 11:15:24 -0700217 def run_command(self, cmd, wait_for_echo=True, send_nl=True,
Masami Hiramatsu0ff22782022-02-16 15:15:52 +0900218 wait_for_prompt=True, wait_for_reboot=False):
Stephen Warren75e731e2016-01-26 13:41:30 -0700219 """Execute a command via the U-Boot console.
Stephen Warren10e50632016-01-15 11:15:24 -0700220
221 The command is always sent to U-Boot.
222
223 U-Boot echoes any command back to its output, and this function
224 typically waits for that to occur. The wait can be disabled by setting
225 wait_for_echo=False, which is useful e.g. when sending CTRL-C to
226 interrupt a long-running command such as "ums".
227
228 Command execution is typically triggered by sending a newline
229 character. This can be disabled by setting send_nl=False, which is
230 also useful when sending CTRL-C.
231
232 This function typically waits for the command to finish executing, and
233 returns the console output that it generated. This can be disabled by
234 setting wait_for_prompt=False, which is useful when invoking a long-
235 running command such as "ums".
236
237 Args:
238 cmd: The command to send.
Heinrich Schuchardtbec160a2017-09-14 12:27:07 +0200239 wait_for_echo: Boolean indicating whether to wait for U-Boot to
Stephen Warren10e50632016-01-15 11:15:24 -0700240 echo the command text back to its output.
241 send_nl: Boolean indicating whether to send a newline character
242 after the command string.
243 wait_for_prompt: Boolean indicating whether to wait for the
244 command prompt to be sent by U-Boot. This typically occurs
245 immediately after the command has been executed.
Masami Hiramatsu0ff22782022-02-16 15:15:52 +0900246 wait_for_reboot: Boolean indication whether to wait for the
247 reboot U-Boot. If this sets True, wait_for_prompt must also
248 be True.
Stephen Warren10e50632016-01-15 11:15:24 -0700249
250 Returns:
251 If wait_for_prompt == False:
252 Nothing.
253 Else:
254 The output from U-Boot during command execution. In other
255 words, the text U-Boot emitted between the point it echod the
256 command string and emitted the subsequent command prompts.
Stephen Warren75e731e2016-01-26 13:41:30 -0700257 """
Stephen Warren10e50632016-01-15 11:15:24 -0700258
Stephen Warren10e50632016-01-15 11:15:24 -0700259 if self.at_prompt and \
260 self.at_prompt_logevt != self.logstream.logfile.cur_evt:
261 self.logstream.write(self.prompt, implicit=True)
262
Stephen Warren10e50632016-01-15 11:15:24 -0700263 try:
264 self.at_prompt = False
265 if send_nl:
266 cmd += '\n'
267 while cmd:
268 # Limit max outstanding data, so UART FIFOs don't overflow
269 chunk = cmd[:self.max_fifo_fill]
270 cmd = cmd[self.max_fifo_fill:]
271 self.p.send(chunk)
272 if not wait_for_echo:
273 continue
274 chunk = re.escape(chunk)
275 chunk = chunk.replace('\\\n', '[\r\n]')
Stephen Warren1115a972016-01-27 23:57:48 -0700276 m = self.p.expect([chunk] + self.bad_patterns)
Stephen Warren10e50632016-01-15 11:15:24 -0700277 if m != 0:
278 self.at_prompt = False
Simon Glass573171e2024-10-09 18:29:02 -0600279 raise BootFail('Bad pattern found on console: ' +
Stephen Warren1115a972016-01-27 23:57:48 -0700280 self.bad_pattern_ids[m - 1])
Stephen Warren10e50632016-01-15 11:15:24 -0700281 if not wait_for_prompt:
282 return
Masami Hiramatsu0ff22782022-02-16 15:15:52 +0900283 if wait_for_reboot:
284 self.wait_for_boot_prompt()
285 else:
286 m = self.p.expect([self.prompt_compiled] + self.bad_patterns)
287 if m != 0:
288 self.at_prompt = False
Simon Glass573171e2024-10-09 18:29:02 -0600289 raise BootFail('Missing prompt on console: ' +
Masami Hiramatsu0ff22782022-02-16 15:15:52 +0900290 self.bad_pattern_ids[m - 1])
Stephen Warren10e50632016-01-15 11:15:24 -0700291 self.at_prompt = True
292 self.at_prompt_logevt = self.logstream.logfile.cur_evt
293 # Only strip \r\n; space/TAB might be significant if testing
294 # indentation.
295 return self.p.before.strip('\r\n')
Simon Glass573171e2024-10-09 18:29:02 -0600296 except Timeout as exc:
Simon Glass7a1e9b42024-10-09 18:29:04 -0600297 handle_exception(self.config, self, self.log, exc, 'Lab failure',
298 True)
Simon Glass573171e2024-10-09 18:29:02 -0600299 raise
Simon Glass7a1e9b42024-10-09 18:29:04 -0600300 except BootFail as exc:
301 handle_exception(self.config, self, self.log, exc, 'Boot fail',
302 True, self.get_spawn_output())
Stephen Warren10e50632016-01-15 11:15:24 -0700303 raise
Stephen Warrenb1c556a2017-10-27 11:04:08 -0600304 finally:
305 self.log.timestamp()
Stephen Warren10e50632016-01-15 11:15:24 -0700306
Simon Glass2436bb02016-07-03 09:40:42 -0600307 def run_command_list(self, cmds):
308 """Run a list of commands.
309
310 This is a helper function to call run_command() with default arguments
311 for each command in a list.
312
313 Args:
Simon Glassd5deca02016-07-31 17:35:04 -0600314 cmd: List of commands (each a string).
Simon Glass2436bb02016-07-03 09:40:42 -0600315 Returns:
Simon Glass2ca73112016-07-31 17:35:09 -0600316 A list of output strings from each command, one element for each
317 command.
Simon Glass2436bb02016-07-03 09:40:42 -0600318 """
Simon Glass2ca73112016-07-31 17:35:09 -0600319 output = []
Simon Glass2436bb02016-07-03 09:40:42 -0600320 for cmd in cmds:
Simon Glass2ca73112016-07-31 17:35:09 -0600321 output.append(self.run_command(cmd))
Simon Glass2436bb02016-07-03 09:40:42 -0600322 return output
323
Stephen Warren10e50632016-01-15 11:15:24 -0700324 def ctrlc(self):
Stephen Warren75e731e2016-01-26 13:41:30 -0700325 """Send a CTRL-C character to U-Boot.
Stephen Warren10e50632016-01-15 11:15:24 -0700326
327 This is useful in order to stop execution of long-running synchronous
328 commands such as "ums".
329
330 Args:
331 None.
332
333 Returns:
334 Nothing.
Stephen Warren75e731e2016-01-26 13:41:30 -0700335 """
Stephen Warren10e50632016-01-15 11:15:24 -0700336
Stephen Warrena88c4172016-01-22 12:30:10 -0700337 self.log.action('Sending Ctrl-C')
Stephen Warren10e50632016-01-15 11:15:24 -0700338 self.run_command(chr(3), wait_for_echo=False, send_nl=False)
339
Stephen Warrenef824f52016-01-22 12:30:12 -0700340 def wait_for(self, text):
Stephen Warren75e731e2016-01-26 13:41:30 -0700341 """Wait for a pattern to be emitted by U-Boot.
Stephen Warrenef824f52016-01-22 12:30:12 -0700342
343 This is useful when a long-running command such as "dfu" is executing,
344 and it periodically emits some text that should show up at a specific
345 location in the log file.
346
347 Args:
348 text: The text to wait for; either a string (containing raw text,
349 not a regular expression) or an re object.
350
351 Returns:
352 Nothing.
Stephen Warren75e731e2016-01-26 13:41:30 -0700353 """
Stephen Warrenef824f52016-01-22 12:30:12 -0700354
355 if type(text) == type(''):
356 text = re.escape(text)
Stephen Warren68a9bb62016-01-27 23:57:49 -0700357 m = self.p.expect([text] + self.bad_patterns)
358 if m != 0:
Simon Glass573171e2024-10-09 18:29:02 -0600359 raise Unexpected(
360 "Unexpected pattern found on console (exp '{text}': " +
361 self.bad_pattern_ids[m - 1])
Stephen Warrenef824f52016-01-22 12:30:12 -0700362
Stephen Warren97a54662016-01-22 12:30:09 -0700363 def drain_console(self):
Stephen Warren75e731e2016-01-26 13:41:30 -0700364 """Read from and log the U-Boot console for a short time.
Stephen Warren97a54662016-01-22 12:30:09 -0700365
366 U-Boot's console output is only logged when the test code actively
367 waits for U-Boot to emit specific data. There are cases where tests
368 can fail without doing this. For example, if a test asks U-Boot to
369 enable USB device mode, then polls until a host-side device node
370 exists. In such a case, it is useful to log U-Boot's console output
371 in case U-Boot printed clues as to why the host-side even did not
372 occur. This function will do that.
373
374 Args:
375 None.
376
377 Returns:
378 Nothing.
Stephen Warren75e731e2016-01-26 13:41:30 -0700379 """
Stephen Warren97a54662016-01-22 12:30:09 -0700380
381 # If we are already not connected to U-Boot, there's nothing to drain.
382 # This should only happen when a previous call to run_command() or
383 # wait_for() failed (and hence the output has already been logged), or
384 # the system is shutting down.
385 if not self.p:
386 return
387
388 orig_timeout = self.p.timeout
389 try:
390 # Drain the log for a relatively short time.
391 self.p.timeout = 1000
392 # Wait for something U-Boot will likely never send. This will
393 # cause the console output to be read and logged.
394 self.p.expect(['This should never match U-Boot output'])
Stephen Warren677b9cc2018-09-20 16:55:03 -0600395 except:
396 # We expect a timeout, since U-Boot won't print what we waited
397 # for. Squash it when it happens.
398 #
399 # Squash any other exception too. This function is only used to
400 # drain (and log) the U-Boot console output after a failed test.
401 # The U-Boot process will be restarted, or target board reset, once
402 # this function returns. So, we don't care about detecting any
403 # additional errors, so they're squashed so that the rest of the
404 # post-test-failure cleanup code can continue operation, and
405 # correctly terminate any log sections, etc.
Stephen Warren97a54662016-01-22 12:30:09 -0700406 pass
407 finally:
408 self.p.timeout = orig_timeout
409
Masami Hiramatsu4d3b9962022-02-16 15:16:02 +0900410 def ensure_spawned(self, expect_reset=False):
Stephen Warren75e731e2016-01-26 13:41:30 -0700411 """Ensure a connection to a correctly running U-Boot instance.
Stephen Warren10e50632016-01-15 11:15:24 -0700412
413 This may require spawning a new Sandbox process or resetting target
414 hardware, as defined by the implementation sub-class.
415
416 This is an internal function and should not be called directly.
417
418 Args:
Masami Hiramatsu4d3b9962022-02-16 15:16:02 +0900419 expect_reset: Boolean indication whether this boot is expected
420 to be reset while the 1st boot process after main boot before
421 prompt. False by default.
Stephen Warren10e50632016-01-15 11:15:24 -0700422
423 Returns:
424 Nothing.
Stephen Warren75e731e2016-01-26 13:41:30 -0700425 """
Stephen Warren10e50632016-01-15 11:15:24 -0700426
427 if self.p:
Bin Meng739b3862022-05-17 23:24:43 +0800428 # Reset the console timeout value as some tests may change
429 # its default value during the execution
430 if not self.config.gdbserver:
Simon Glass64914152024-10-09 18:28:58 -0600431 self.p.timeout = TIMEOUT_MS
Stephen Warren10e50632016-01-15 11:15:24 -0700432 return
433 try:
Stephen Warren80eea632016-02-11 11:46:12 -0700434 self.log.start_section('Starting U-Boot')
Stephen Warren10e50632016-01-15 11:15:24 -0700435 self.at_prompt = False
Stephen Warren10e50632016-01-15 11:15:24 -0700436 self.p = self.get_spawn()
437 # Real targets can take a long time to scroll large amounts of
438 # text if LCD is enabled. This value may need tweaking in the
439 # future, possibly per-test to be optimal. This works for 'help'
440 # on board 'seaboard'.
Stephen Warren33db1ee2016-02-04 16:11:50 -0700441 if not self.config.gdbserver:
Simon Glass64914152024-10-09 18:28:58 -0600442 self.p.timeout = TIMEOUT_MS
Stephen Warren10e50632016-01-15 11:15:24 -0700443 self.p.logfile_read = self.logstream
Simon Glassf1b1bb82024-11-12 07:13:17 -0700444 if self.config.use_running_system:
445 # Send an empty command to set up the 'expect' logic. This has
446 # the side effect of ensuring that there was no partial command
447 # line entered
448 self.run_command(' ')
Masami Hiramatsu4d3b9962022-02-16 15:16:02 +0900449 else:
Simon Glassf1b1bb82024-11-12 07:13:17 -0700450 if expect_reset:
451 loop_num = 2
452 else:
453 loop_num = 1
454 self.wait_for_boot_prompt(loop_num = loop_num)
Stephen Warren10e50632016-01-15 11:15:24 -0700455 self.at_prompt = True
456 self.at_prompt_logevt = self.logstream.logfile.cur_evt
457 except Exception as ex:
458 self.log.error(str(ex))
459 self.cleanup_spawn()
460 raise
Stephen Warren80eea632016-02-11 11:46:12 -0700461 finally:
Stephen Warrenb1c556a2017-10-27 11:04:08 -0600462 self.log.timestamp()
Stephen Warren80eea632016-02-11 11:46:12 -0700463 self.log.end_section('Starting U-Boot')
Stephen Warren10e50632016-01-15 11:15:24 -0700464
465 def cleanup_spawn(self):
Stephen Warren75e731e2016-01-26 13:41:30 -0700466 """Shut down all interaction with the U-Boot instance.
Stephen Warren10e50632016-01-15 11:15:24 -0700467
468 This is used when an error is detected prior to re-establishing a
469 connection with a fresh U-Boot instance.
470
471 This is an internal function and should not be called directly.
472
473 Args:
474 None.
475
476 Returns:
477 Nothing.
Stephen Warren75e731e2016-01-26 13:41:30 -0700478 """
Stephen Warren10e50632016-01-15 11:15:24 -0700479
480 try:
481 if self.p:
482 self.p.close()
483 except:
484 pass
485 self.p = None
486
Masami Hiramatsu4d3b9962022-02-16 15:16:02 +0900487 def restart_uboot(self, expect_reset=False):
Simon Glass37c2ce12016-07-31 17:35:08 -0600488 """Shut down and restart U-Boot."""
489 self.cleanup_spawn()
Masami Hiramatsu4d3b9962022-02-16 15:16:02 +0900490 self.ensure_spawned(expect_reset)
Simon Glass37c2ce12016-07-31 17:35:08 -0600491
Simon Glass9bc20832016-07-04 11:58:39 -0600492 def get_spawn_output(self):
493 """Return the start-up output from U-Boot
494
495 Returns:
496 The output produced by ensure_spawed(), as a string.
497 """
498 if self.p:
499 return self.p.get_expect_output()
500 return None
501
Stephen Warren10e50632016-01-15 11:15:24 -0700502 def validate_version_string_in_text(self, text):
Stephen Warren75e731e2016-01-26 13:41:30 -0700503 """Assert that a command's output includes the U-Boot signon message.
Stephen Warren10e50632016-01-15 11:15:24 -0700504
505 This is primarily useful for validating the "version" command without
506 duplicating the signon text regex in a test function.
507
508 Args:
509 text: The command output text to check.
510
511 Returns:
512 Nothing. An exception is raised if the validation fails.
Stephen Warren75e731e2016-01-26 13:41:30 -0700513 """
Stephen Warren10e50632016-01-15 11:15:24 -0700514
515 assert(self.u_boot_version_string in text)
516
517 def disable_check(self, check_type):
Stephen Warren75e731e2016-01-26 13:41:30 -0700518 """Temporarily disable an error check of U-Boot's output.
Stephen Warren10e50632016-01-15 11:15:24 -0700519
520 Create a new context manager (for use with the "with" statement) which
521 temporarily disables a particular console output error check.
522
523 Args:
524 check_type: The type of error-check to disable. Valid values may
525 be found in self.disable_check_count above.
526
527 Returns:
528 A context manager object.
Stephen Warren75e731e2016-01-26 13:41:30 -0700529 """
Stephen Warren10e50632016-01-15 11:15:24 -0700530
531 return ConsoleDisableCheck(self, check_type)
Michal Simek6b463182016-05-19 07:57:41 +0200532
Love Kumarc35e66e2024-05-22 18:45:13 +0530533 def enable_check(self, check_type, check_pattern):
534 """Temporarily enable an error check of U-Boot's output.
535
536 Create a new context manager (for use with the "with" statement) which
537 temporarily enables a particular console output error check. The
538 arguments form a new element of bad_pattern_defs defined above.
539
540 Args:
541 check_type: The type of error-check or bad pattern to enable.
542 check_pattern: The regexes for text error pattern or bad pattern
543 to be checked.
544
545 Returns:
546 A context manager object.
547 """
548
549 return ConsoleEnableCheck(self, check_type, check_pattern)
550
Michal Simek6b463182016-05-19 07:57:41 +0200551 def temporary_timeout(self, timeout):
552 """Temporarily set up different timeout for commands.
553
554 Create a new context manager (for use with the "with" statement) which
555 temporarily change timeout.
556
557 Args:
558 timeout: Time in milliseconds.
559
560 Returns:
561 A context manager object.
562 """
563
564 return ConsoleSetupTimeout(self, timeout)