xref: /rk3399_rockchip-uboot/test/py/u_boot_console_base.py (revision 1151fbe6486d939516c6980af35f8e8e08d4fb23)
1d201506cSStephen Warren# Copyright (c) 2015 Stephen Warren
2d201506cSStephen Warren# Copyright (c) 2015-2016, NVIDIA CORPORATION. All rights reserved.
3d201506cSStephen Warren#
4d201506cSStephen Warren# SPDX-License-Identifier: GPL-2.0
5d201506cSStephen Warren
6d201506cSStephen Warren# Common logic to interact with U-Boot via the console. This class provides
7d201506cSStephen Warren# the interface that tests use to execute U-Boot shell commands and wait for
8d201506cSStephen Warren# their results. Sub-classes exist to perform board-type-specific setup
9d201506cSStephen Warren# operations, such as spawning a sub-process for Sandbox, or attaching to the
10d201506cSStephen Warren# serial console of real hardware.
11d201506cSStephen Warren
12d201506cSStephen Warrenimport multiplexed_log
13d201506cSStephen Warrenimport os
14d201506cSStephen Warrenimport pytest
15d201506cSStephen Warrenimport re
16d201506cSStephen Warrenimport sys
17c10eb9d3SStephen Warrenimport u_boot_spawn
18d201506cSStephen Warren
19d201506cSStephen Warren# Regexes for text we expect U-Boot to send to the console.
20c82ce04aSStephen Warrenpattern_u_boot_spl_signon = re.compile('(U-Boot SPL \\d{4}\\.\\d{2}[^\r\n]*\\))')
21c82ce04aSStephen Warrenpattern_u_boot_main_signon = re.compile('(U-Boot \\d{4}\\.\\d{2}[^\r\n]*\\))')
22d201506cSStephen Warrenpattern_stop_autoboot_prompt = re.compile('Hit any key to stop autoboot: ')
23d201506cSStephen Warrenpattern_unknown_command = re.compile('Unknown command \'.*\' - try \'help\'')
24d201506cSStephen Warrenpattern_error_notification = re.compile('## Error: ')
259129d9f5SStephen Warrenpattern_error_please_reset = re.compile('### ERROR ### Please RESET the board ###')
26d201506cSStephen Warren
27e4119ebbSStephen WarrenPAT_ID = 0
28e4119ebbSStephen WarrenPAT_RE = 1
29e4119ebbSStephen Warren
30e4119ebbSStephen Warrenbad_pattern_defs = (
31e4119ebbSStephen Warren    ('spl_signon', pattern_u_boot_spl_signon),
32e4119ebbSStephen Warren    ('main_signon', pattern_u_boot_main_signon),
33e4119ebbSStephen Warren    ('stop_autoboot_prompt', pattern_stop_autoboot_prompt),
34e4119ebbSStephen Warren    ('unknown_command', pattern_unknown_command),
35e4119ebbSStephen Warren    ('error_notification', pattern_error_notification),
369129d9f5SStephen Warren    ('error_please_reset', pattern_error_please_reset),
37e4119ebbSStephen Warren)
38e4119ebbSStephen Warren
39d201506cSStephen Warrenclass ConsoleDisableCheck(object):
40e8debf39SStephen Warren    """Context manager (for Python's with statement) that temporarily disables
41d201506cSStephen Warren    the specified console output error check. This is useful when deliberately
42d201506cSStephen Warren    executing a command that is known to trigger one of the error checks, in
43d201506cSStephen Warren    order to test that the error condition is actually raised. This class is
44d201506cSStephen Warren    used internally by ConsoleBase::disable_check(); it is not intended for
45e8debf39SStephen Warren    direct usage."""
46d201506cSStephen Warren
47d201506cSStephen Warren    def __init__(self, console, check_type):
48d201506cSStephen Warren        self.console = console
49d201506cSStephen Warren        self.check_type = check_type
50d201506cSStephen Warren
51d201506cSStephen Warren    def __enter__(self):
52d201506cSStephen Warren        self.console.disable_check_count[self.check_type] += 1
53e4119ebbSStephen Warren        self.console.eval_bad_patterns()
54d201506cSStephen Warren
55d201506cSStephen Warren    def __exit__(self, extype, value, traceback):
56d201506cSStephen Warren        self.console.disable_check_count[self.check_type] -= 1
57e4119ebbSStephen Warren        self.console.eval_bad_patterns()
58d201506cSStephen Warren
5987861c19SMichal Simekclass ConsoleSetupTimeout(object):
6087861c19SMichal Simek    """Context manager (for Python's with statement) that temporarily sets up
6187861c19SMichal Simek    timeout for specific command. This is useful when execution time is greater
6287861c19SMichal Simek    then default 30s."""
6387861c19SMichal Simek
6487861c19SMichal Simek    def __init__(self, console, timeout):
6587861c19SMichal Simek        self.p = console.p
6687861c19SMichal Simek        self.orig_timeout = self.p.timeout
6787861c19SMichal Simek        self.p.timeout = timeout
6887861c19SMichal Simek
6987861c19SMichal Simek    def __enter__(self):
7087861c19SMichal Simek        return self
7187861c19SMichal Simek
7287861c19SMichal Simek    def __exit__(self, extype, value, traceback):
7387861c19SMichal Simek        self.p.timeout = self.orig_timeout
7487861c19SMichal Simek
75d201506cSStephen Warrenclass ConsoleBase(object):
76e8debf39SStephen Warren    """The interface through which test functions interact with the U-Boot
77d201506cSStephen Warren    console. This primarily involves executing shell commands, capturing their
78d201506cSStephen Warren    results, and checking for common error conditions. Some common utilities
79e8debf39SStephen Warren    are also provided too."""
80d201506cSStephen Warren
81d201506cSStephen Warren    def __init__(self, log, config, max_fifo_fill):
82e8debf39SStephen Warren        """Initialize a U-Boot console connection.
83d201506cSStephen Warren
84d201506cSStephen Warren        Can only usefully be called by sub-classes.
85d201506cSStephen Warren
86d201506cSStephen Warren        Args:
87d201506cSStephen Warren            log: A mulptiplex_log.Logfile object, to which the U-Boot output
88d201506cSStephen Warren                will be logged.
89d201506cSStephen Warren            config: A configuration data structure, as built by conftest.py.
90d201506cSStephen Warren            max_fifo_fill: The maximum number of characters to send to U-Boot
91d201506cSStephen Warren                command-line before waiting for U-Boot to echo the characters
92d201506cSStephen Warren                back. For UART-based HW without HW flow control, this value
93d201506cSStephen Warren                should be set less than the UART RX FIFO size to avoid
94d201506cSStephen Warren                overflow, assuming that U-Boot can't keep up with full-rate
95d201506cSStephen Warren                traffic at the baud rate.
96d201506cSStephen Warren
97d201506cSStephen Warren        Returns:
98d201506cSStephen Warren            Nothing.
99e8debf39SStephen Warren        """
100d201506cSStephen Warren
101d201506cSStephen Warren        self.log = log
102d201506cSStephen Warren        self.config = config
103d201506cSStephen Warren        self.max_fifo_fill = max_fifo_fill
104d201506cSStephen Warren
105d201506cSStephen Warren        self.logstream = self.log.get_stream('console', sys.stdout)
106d201506cSStephen Warren
107d201506cSStephen Warren        # Array slice removes leading/trailing quotes
108d201506cSStephen Warren        self.prompt = self.config.buildconfig['config_sys_prompt'][1:-1]
1094ba58bdaSStephen Warren        self.prompt_compiled = re.compile('^' + re.escape(self.prompt), re.MULTILINE)
110d201506cSStephen Warren        self.p = None
111e4119ebbSStephen Warren        self.disable_check_count = {pat[PAT_ID]: 0 for pat in bad_pattern_defs}
112e4119ebbSStephen Warren        self.eval_bad_patterns()
113d201506cSStephen Warren
114d201506cSStephen Warren        self.at_prompt = False
115d201506cSStephen Warren        self.at_prompt_logevt = None
116d201506cSStephen Warren
117e4119ebbSStephen Warren    def eval_bad_patterns(self):
118e4119ebbSStephen Warren        self.bad_patterns = [pat[PAT_RE] for pat in bad_pattern_defs \
119e4119ebbSStephen Warren            if self.disable_check_count[pat[PAT_ID]] == 0]
120e4119ebbSStephen Warren        self.bad_pattern_ids = [pat[PAT_ID] for pat in bad_pattern_defs \
121e4119ebbSStephen Warren            if self.disable_check_count[pat[PAT_ID]] == 0]
122e4119ebbSStephen Warren
123d201506cSStephen Warren    def close(self):
124e8debf39SStephen Warren        """Terminate the connection to the U-Boot console.
125d201506cSStephen Warren
126d201506cSStephen Warren        This function is only useful once all interaction with U-Boot is
127d201506cSStephen Warren        complete. Once this function is called, data cannot be sent to or
128d201506cSStephen Warren        received from U-Boot.
129d201506cSStephen Warren
130d201506cSStephen Warren        Args:
131d201506cSStephen Warren            None.
132d201506cSStephen Warren
133d201506cSStephen Warren        Returns:
134d201506cSStephen Warren            Nothing.
135e8debf39SStephen Warren        """
136d201506cSStephen Warren
137d201506cSStephen Warren        if self.p:
138d201506cSStephen Warren            self.p.close()
139d201506cSStephen Warren        self.logstream.close()
140d201506cSStephen Warren
141d201506cSStephen Warren    def run_command(self, cmd, wait_for_echo=True, send_nl=True,
142d201506cSStephen Warren            wait_for_prompt=True):
143e8debf39SStephen Warren        """Execute a command via the U-Boot console.
144d201506cSStephen Warren
145d201506cSStephen Warren        The command is always sent to U-Boot.
146d201506cSStephen Warren
147d201506cSStephen Warren        U-Boot echoes any command back to its output, and this function
148d201506cSStephen Warren        typically waits for that to occur. The wait can be disabled by setting
149d201506cSStephen Warren        wait_for_echo=False, which is useful e.g. when sending CTRL-C to
150d201506cSStephen Warren        interrupt a long-running command such as "ums".
151d201506cSStephen Warren
152d201506cSStephen Warren        Command execution is typically triggered by sending a newline
153d201506cSStephen Warren        character. This can be disabled by setting send_nl=False, which is
154d201506cSStephen Warren        also useful when sending CTRL-C.
155d201506cSStephen Warren
156d201506cSStephen Warren        This function typically waits for the command to finish executing, and
157d201506cSStephen Warren        returns the console output that it generated. This can be disabled by
158d201506cSStephen Warren        setting wait_for_prompt=False, which is useful when invoking a long-
159d201506cSStephen Warren        running command such as "ums".
160d201506cSStephen Warren
161d201506cSStephen Warren        Args:
162d201506cSStephen Warren            cmd: The command to send.
16370478c70SHeinrich Schuchardt            wait_for_echo: Boolean indicating whether to wait for U-Boot to
164d201506cSStephen Warren                echo the command text back to its output.
165d201506cSStephen Warren            send_nl: Boolean indicating whether to send a newline character
166d201506cSStephen Warren                after the command string.
167d201506cSStephen Warren            wait_for_prompt: Boolean indicating whether to wait for the
168d201506cSStephen Warren                command prompt to be sent by U-Boot. This typically occurs
169d201506cSStephen Warren                immediately after the command has been executed.
170d201506cSStephen Warren
171d201506cSStephen Warren        Returns:
172d201506cSStephen Warren            If wait_for_prompt == False:
173d201506cSStephen Warren                Nothing.
174d201506cSStephen Warren            Else:
175d201506cSStephen Warren                The output from U-Boot during command execution. In other
176d201506cSStephen Warren                words, the text U-Boot emitted between the point it echod the
177d201506cSStephen Warren                command string and emitted the subsequent command prompts.
178e8debf39SStephen Warren        """
179d201506cSStephen Warren
180d201506cSStephen Warren        if self.at_prompt and \
181d201506cSStephen Warren                self.at_prompt_logevt != self.logstream.logfile.cur_evt:
182d201506cSStephen Warren            self.logstream.write(self.prompt, implicit=True)
183d201506cSStephen Warren
184d201506cSStephen Warren        try:
185d201506cSStephen Warren            self.at_prompt = False
186d201506cSStephen Warren            if send_nl:
187d201506cSStephen Warren                cmd += '\n'
188d201506cSStephen Warren            while cmd:
189d201506cSStephen Warren                # Limit max outstanding data, so UART FIFOs don't overflow
190d201506cSStephen Warren                chunk = cmd[:self.max_fifo_fill]
191d201506cSStephen Warren                cmd = cmd[self.max_fifo_fill:]
192d201506cSStephen Warren                self.p.send(chunk)
193d201506cSStephen Warren                if not wait_for_echo:
194d201506cSStephen Warren                    continue
195d201506cSStephen Warren                chunk = re.escape(chunk)
196d201506cSStephen Warren                chunk = chunk.replace('\\\n', '[\r\n]')
197e4119ebbSStephen Warren                m = self.p.expect([chunk] + self.bad_patterns)
198d201506cSStephen Warren                if m != 0:
199d201506cSStephen Warren                    self.at_prompt = False
200d201506cSStephen Warren                    raise Exception('Bad pattern found on console: ' +
201e4119ebbSStephen Warren                                    self.bad_pattern_ids[m - 1])
202d201506cSStephen Warren            if not wait_for_prompt:
203d201506cSStephen Warren                return
2044ba58bdaSStephen Warren            m = self.p.expect([self.prompt_compiled] + self.bad_patterns)
205d201506cSStephen Warren            if m != 0:
206d201506cSStephen Warren                self.at_prompt = False
207d201506cSStephen Warren                raise Exception('Bad pattern found on console: ' +
208e4119ebbSStephen Warren                                self.bad_pattern_ids[m - 1])
209d201506cSStephen Warren            self.at_prompt = True
210d201506cSStephen Warren            self.at_prompt_logevt = self.logstream.logfile.cur_evt
211d201506cSStephen Warren            # Only strip \r\n; space/TAB might be significant if testing
212d201506cSStephen Warren            # indentation.
213d201506cSStephen Warren            return self.p.before.strip('\r\n')
214d201506cSStephen Warren        except Exception as ex:
215d201506cSStephen Warren            self.log.error(str(ex))
216d201506cSStephen Warren            self.cleanup_spawn()
217d201506cSStephen Warren            raise
218*1151fbe6SStephen Warren        finally:
219*1151fbe6SStephen Warren            self.log.timestamp()
220d201506cSStephen Warren
22173a9054dSSimon Glass    def run_command_list(self, cmds):
22273a9054dSSimon Glass        """Run a list of commands.
22373a9054dSSimon Glass
22473a9054dSSimon Glass        This is a helper function to call run_command() with default arguments
22573a9054dSSimon Glass        for each command in a list.
22673a9054dSSimon Glass
22773a9054dSSimon Glass        Args:
22872f52268SSimon Glass            cmd: List of commands (each a string).
22973a9054dSSimon Glass        Returns:
230f6d34651SSimon Glass            A list of output strings from each command, one element for each
231f6d34651SSimon Glass            command.
23273a9054dSSimon Glass        """
233f6d34651SSimon Glass        output = []
23473a9054dSSimon Glass        for cmd in cmds:
235f6d34651SSimon Glass            output.append(self.run_command(cmd))
23673a9054dSSimon Glass        return output
23773a9054dSSimon Glass
238d201506cSStephen Warren    def ctrlc(self):
239e8debf39SStephen Warren        """Send a CTRL-C character to U-Boot.
240d201506cSStephen Warren
241d201506cSStephen Warren        This is useful in order to stop execution of long-running synchronous
242d201506cSStephen Warren        commands such as "ums".
243d201506cSStephen Warren
244d201506cSStephen Warren        Args:
245d201506cSStephen Warren            None.
246d201506cSStephen Warren
247d201506cSStephen Warren        Returns:
248d201506cSStephen Warren            Nothing.
249e8debf39SStephen Warren        """
250d201506cSStephen Warren
251783cbcd3SStephen Warren        self.log.action('Sending Ctrl-C')
252d201506cSStephen Warren        self.run_command(chr(3), wait_for_echo=False, send_nl=False)
253d201506cSStephen Warren
25476b46939SStephen Warren    def wait_for(self, text):
255e8debf39SStephen Warren        """Wait for a pattern to be emitted by U-Boot.
25676b46939SStephen Warren
25776b46939SStephen Warren        This is useful when a long-running command such as "dfu" is executing,
25876b46939SStephen Warren        and it periodically emits some text that should show up at a specific
25976b46939SStephen Warren        location in the log file.
26076b46939SStephen Warren
26176b46939SStephen Warren        Args:
26276b46939SStephen Warren            text: The text to wait for; either a string (containing raw text,
26376b46939SStephen Warren                not a regular expression) or an re object.
26476b46939SStephen Warren
26576b46939SStephen Warren        Returns:
26676b46939SStephen Warren            Nothing.
267e8debf39SStephen Warren        """
26876b46939SStephen Warren
26976b46939SStephen Warren        if type(text) == type(''):
27076b46939SStephen Warren            text = re.escape(text)
2710c6189b5SStephen Warren        m = self.p.expect([text] + self.bad_patterns)
2720c6189b5SStephen Warren        if m != 0:
2730c6189b5SStephen Warren            raise Exception('Bad pattern found on console: ' +
2740c6189b5SStephen Warren                            self.bad_pattern_ids[m - 1])
27576b46939SStephen Warren
276c10eb9d3SStephen Warren    def drain_console(self):
277e8debf39SStephen Warren        """Read from and log the U-Boot console for a short time.
278c10eb9d3SStephen Warren
279c10eb9d3SStephen Warren        U-Boot's console output is only logged when the test code actively
280c10eb9d3SStephen Warren        waits for U-Boot to emit specific data. There are cases where tests
281c10eb9d3SStephen Warren        can fail without doing this. For example, if a test asks U-Boot to
282c10eb9d3SStephen Warren        enable USB device mode, then polls until a host-side device node
283c10eb9d3SStephen Warren        exists. In such a case, it is useful to log U-Boot's console output
284c10eb9d3SStephen Warren        in case U-Boot printed clues as to why the host-side even did not
285c10eb9d3SStephen Warren        occur. This function will do that.
286c10eb9d3SStephen Warren
287c10eb9d3SStephen Warren        Args:
288c10eb9d3SStephen Warren            None.
289c10eb9d3SStephen Warren
290c10eb9d3SStephen Warren        Returns:
291c10eb9d3SStephen Warren            Nothing.
292e8debf39SStephen Warren        """
293c10eb9d3SStephen Warren
294c10eb9d3SStephen Warren        # If we are already not connected to U-Boot, there's nothing to drain.
295c10eb9d3SStephen Warren        # This should only happen when a previous call to run_command() or
296c10eb9d3SStephen Warren        # wait_for() failed (and hence the output has already been logged), or
297c10eb9d3SStephen Warren        # the system is shutting down.
298c10eb9d3SStephen Warren        if not self.p:
299c10eb9d3SStephen Warren            return
300c10eb9d3SStephen Warren
301c10eb9d3SStephen Warren        orig_timeout = self.p.timeout
302c10eb9d3SStephen Warren        try:
303c10eb9d3SStephen Warren            # Drain the log for a relatively short time.
304c10eb9d3SStephen Warren            self.p.timeout = 1000
305c10eb9d3SStephen Warren            # Wait for something U-Boot will likely never send. This will
306c10eb9d3SStephen Warren            # cause the console output to be read and logged.
307c10eb9d3SStephen Warren            self.p.expect(['This should never match U-Boot output'])
308c10eb9d3SStephen Warren        except u_boot_spawn.Timeout:
309c10eb9d3SStephen Warren            pass
310c10eb9d3SStephen Warren        finally:
311c10eb9d3SStephen Warren            self.p.timeout = orig_timeout
312c10eb9d3SStephen Warren
313d201506cSStephen Warren    def ensure_spawned(self):
314e8debf39SStephen Warren        """Ensure a connection to a correctly running U-Boot instance.
315d201506cSStephen Warren
316d201506cSStephen Warren        This may require spawning a new Sandbox process or resetting target
317d201506cSStephen Warren        hardware, as defined by the implementation sub-class.
318d201506cSStephen Warren
319d201506cSStephen Warren        This is an internal function and should not be called directly.
320d201506cSStephen Warren
321d201506cSStephen Warren        Args:
322d201506cSStephen Warren            None.
323d201506cSStephen Warren
324d201506cSStephen Warren        Returns:
325d201506cSStephen Warren            Nothing.
326e8debf39SStephen Warren        """
327d201506cSStephen Warren
328d201506cSStephen Warren        if self.p:
329d201506cSStephen Warren            return
330d201506cSStephen Warren        try:
33197255438SStephen Warren            self.log.start_section('Starting U-Boot')
332d201506cSStephen Warren            self.at_prompt = False
333d201506cSStephen Warren            self.p = self.get_spawn()
334d201506cSStephen Warren            # Real targets can take a long time to scroll large amounts of
335d201506cSStephen Warren            # text if LCD is enabled. This value may need tweaking in the
336d201506cSStephen Warren            # future, possibly per-test to be optimal. This works for 'help'
337d201506cSStephen Warren            # on board 'seaboard'.
33889ab8410SStephen Warren            if not self.config.gdbserver:
339d201506cSStephen Warren                self.p.timeout = 30000
340d201506cSStephen Warren            self.p.logfile_read = self.logstream
341b1309a23SHeiko Schocher            bcfg = self.config.buildconfig
342b1309a23SHeiko Schocher            config_spl = bcfg.get('config_spl', 'n') == 'y'
343b1309a23SHeiko Schocher            config_spl_serial_support = bcfg.get('config_spl_serial_support',
344b1309a23SHeiko Schocher                                                 'n') == 'y'
345299e5bb7SMichal Simek            env_spl_skipped = self.config.env.get('env__spl_skipped',
346299e5bb7SMichal Simek                                                  False)
347299e5bb7SMichal Simek            if config_spl and config_spl_serial_support and not env_spl_skipped:
348b1309a23SHeiko Schocher                m = self.p.expect([pattern_u_boot_spl_signon] +
349b1309a23SHeiko Schocher                                  self.bad_patterns)
3500c6189b5SStephen Warren                if m != 0:
351c7f636f5SSimon Glass                    raise Exception('Bad pattern found on SPL console: ' +
3520c6189b5SStephen Warren                                    self.bad_pattern_ids[m - 1])
3530c6189b5SStephen Warren            m = self.p.expect([pattern_u_boot_main_signon] + self.bad_patterns)
3540c6189b5SStephen Warren            if m != 0:
3550c6189b5SStephen Warren                raise Exception('Bad pattern found on console: ' +
3560c6189b5SStephen Warren                                self.bad_pattern_ids[m - 1])
357c82ce04aSStephen Warren            self.u_boot_version_string = self.p.after
358d201506cSStephen Warren            while True:
3594ba58bdaSStephen Warren                m = self.p.expect([self.prompt_compiled,
3600c6189b5SStephen Warren                    pattern_stop_autoboot_prompt] + self.bad_patterns)
3610c6189b5SStephen Warren                if m == 0:
3620c6189b5SStephen Warren                    break
3630c6189b5SStephen Warren                if m == 1:
36438831ca3SStephen Warren                    self.p.send(' ')
365d201506cSStephen Warren                    continue
3660c6189b5SStephen Warren                raise Exception('Bad pattern found on console: ' +
3670c6189b5SStephen Warren                                self.bad_pattern_ids[m - 2])
368d201506cSStephen Warren            self.at_prompt = True
369d201506cSStephen Warren            self.at_prompt_logevt = self.logstream.logfile.cur_evt
370d201506cSStephen Warren        except Exception as ex:
371d201506cSStephen Warren            self.log.error(str(ex))
372d201506cSStephen Warren            self.cleanup_spawn()
373d201506cSStephen Warren            raise
37497255438SStephen Warren        finally:
375*1151fbe6SStephen Warren            self.log.timestamp()
37697255438SStephen Warren            self.log.end_section('Starting U-Boot')
377d201506cSStephen Warren
378d201506cSStephen Warren    def cleanup_spawn(self):
379e8debf39SStephen Warren        """Shut down all interaction with the U-Boot instance.
380d201506cSStephen Warren
381d201506cSStephen Warren        This is used when an error is detected prior to re-establishing a
382d201506cSStephen Warren        connection with a fresh U-Boot instance.
383d201506cSStephen Warren
384d201506cSStephen Warren        This is an internal function and should not be called directly.
385d201506cSStephen Warren
386d201506cSStephen Warren        Args:
387d201506cSStephen Warren            None.
388d201506cSStephen Warren
389d201506cSStephen Warren        Returns:
390d201506cSStephen Warren            Nothing.
391e8debf39SStephen Warren        """
392d201506cSStephen Warren
393d201506cSStephen Warren        try:
394d201506cSStephen Warren            if self.p:
395d201506cSStephen Warren                self.p.close()
396d201506cSStephen Warren        except:
397d201506cSStephen Warren            pass
398d201506cSStephen Warren        self.p = None
399d201506cSStephen Warren
40027c087d5SSimon Glass    def restart_uboot(self):
40127c087d5SSimon Glass        """Shut down and restart U-Boot."""
40227c087d5SSimon Glass        self.cleanup_spawn()
40327c087d5SSimon Glass        self.ensure_spawned()
40427c087d5SSimon Glass
405ebec58fbSSimon Glass    def get_spawn_output(self):
406ebec58fbSSimon Glass        """Return the start-up output from U-Boot
407ebec58fbSSimon Glass
408ebec58fbSSimon Glass        Returns:
409ebec58fbSSimon Glass            The output produced by ensure_spawed(), as a string.
410ebec58fbSSimon Glass        """
411ebec58fbSSimon Glass        if self.p:
412ebec58fbSSimon Glass            return self.p.get_expect_output()
413ebec58fbSSimon Glass        return None
414ebec58fbSSimon Glass
415d201506cSStephen Warren    def validate_version_string_in_text(self, text):
416e8debf39SStephen Warren        """Assert that a command's output includes the U-Boot signon message.
417d201506cSStephen Warren
418d201506cSStephen Warren        This is primarily useful for validating the "version" command without
419d201506cSStephen Warren        duplicating the signon text regex in a test function.
420d201506cSStephen Warren
421d201506cSStephen Warren        Args:
422d201506cSStephen Warren            text: The command output text to check.
423d201506cSStephen Warren
424d201506cSStephen Warren        Returns:
425d201506cSStephen Warren            Nothing. An exception is raised if the validation fails.
426e8debf39SStephen Warren        """
427d201506cSStephen Warren
428d201506cSStephen Warren        assert(self.u_boot_version_string in text)
429d201506cSStephen Warren
430d201506cSStephen Warren    def disable_check(self, check_type):
431e8debf39SStephen Warren        """Temporarily disable an error check of U-Boot's output.
432d201506cSStephen Warren
433d201506cSStephen Warren        Create a new context manager (for use with the "with" statement) which
434d201506cSStephen Warren        temporarily disables a particular console output error check.
435d201506cSStephen Warren
436d201506cSStephen Warren        Args:
437d201506cSStephen Warren            check_type: The type of error-check to disable. Valid values may
438d201506cSStephen Warren            be found in self.disable_check_count above.
439d201506cSStephen Warren
440d201506cSStephen Warren        Returns:
441d201506cSStephen Warren            A context manager object.
442e8debf39SStephen Warren        """
443d201506cSStephen Warren
444d201506cSStephen Warren        return ConsoleDisableCheck(self, check_type)
44587861c19SMichal Simek
44687861c19SMichal Simek    def temporary_timeout(self, timeout):
44787861c19SMichal Simek        """Temporarily set up different timeout for commands.
44887861c19SMichal Simek
44987861c19SMichal Simek        Create a new context manager (for use with the "with" statement) which
45087861c19SMichal Simek        temporarily change timeout.
45187861c19SMichal Simek
45287861c19SMichal Simek        Args:
45387861c19SMichal Simek            timeout: Time in milliseconds.
45487861c19SMichal Simek
45587861c19SMichal Simek        Returns:
45687861c19SMichal Simek            A context manager object.
45787861c19SMichal Simek        """
45887861c19SMichal Simek
45987861c19SMichal Simek        return ConsoleSetupTimeout(self, timeout)
460