1*4882a593Smuzhiyun# Copyright (c) 2015 Stephen Warren 2*4882a593Smuzhiyun# Copyright (c) 2015-2016, NVIDIA CORPORATION. All rights reserved. 3*4882a593Smuzhiyun# 4*4882a593Smuzhiyun# SPDX-License-Identifier: GPL-2.0 5*4882a593Smuzhiyun 6*4882a593Smuzhiyun# Common logic to interact with U-Boot via the console. This class provides 7*4882a593Smuzhiyun# the interface that tests use to execute U-Boot shell commands and wait for 8*4882a593Smuzhiyun# their results. Sub-classes exist to perform board-type-specific setup 9*4882a593Smuzhiyun# operations, such as spawning a sub-process for Sandbox, or attaching to the 10*4882a593Smuzhiyun# serial console of real hardware. 11*4882a593Smuzhiyun 12*4882a593Smuzhiyunimport multiplexed_log 13*4882a593Smuzhiyunimport os 14*4882a593Smuzhiyunimport pytest 15*4882a593Smuzhiyunimport re 16*4882a593Smuzhiyunimport sys 17*4882a593Smuzhiyunimport u_boot_spawn 18*4882a593Smuzhiyun 19*4882a593Smuzhiyun# Regexes for text we expect U-Boot to send to the console. 20*4882a593Smuzhiyunpattern_u_boot_spl_signon = re.compile('(U-Boot SPL \\d{4}\\.\\d{2}[^\r\n]*\\))') 21*4882a593Smuzhiyunpattern_u_boot_main_signon = re.compile('(U-Boot \\d{4}\\.\\d{2}[^\r\n]*\\))') 22*4882a593Smuzhiyunpattern_stop_autoboot_prompt = re.compile('Hit any key to stop autoboot: ') 23*4882a593Smuzhiyunpattern_unknown_command = re.compile('Unknown command \'.*\' - try \'help\'') 24*4882a593Smuzhiyunpattern_error_notification = re.compile('## Error: ') 25*4882a593Smuzhiyunpattern_error_please_reset = re.compile('### ERROR ### Please RESET the board ###') 26*4882a593Smuzhiyun 27*4882a593SmuzhiyunPAT_ID = 0 28*4882a593SmuzhiyunPAT_RE = 1 29*4882a593Smuzhiyun 30*4882a593Smuzhiyunbad_pattern_defs = ( 31*4882a593Smuzhiyun ('spl_signon', pattern_u_boot_spl_signon), 32*4882a593Smuzhiyun ('main_signon', pattern_u_boot_main_signon), 33*4882a593Smuzhiyun ('stop_autoboot_prompt', pattern_stop_autoboot_prompt), 34*4882a593Smuzhiyun ('unknown_command', pattern_unknown_command), 35*4882a593Smuzhiyun ('error_notification', pattern_error_notification), 36*4882a593Smuzhiyun ('error_please_reset', pattern_error_please_reset), 37*4882a593Smuzhiyun) 38*4882a593Smuzhiyun 39*4882a593Smuzhiyunclass ConsoleDisableCheck(object): 40*4882a593Smuzhiyun """Context manager (for Python's with statement) that temporarily disables 41*4882a593Smuzhiyun the specified console output error check. This is useful when deliberately 42*4882a593Smuzhiyun executing a command that is known to trigger one of the error checks, in 43*4882a593Smuzhiyun order to test that the error condition is actually raised. This class is 44*4882a593Smuzhiyun used internally by ConsoleBase::disable_check(); it is not intended for 45*4882a593Smuzhiyun direct usage.""" 46*4882a593Smuzhiyun 47*4882a593Smuzhiyun def __init__(self, console, check_type): 48*4882a593Smuzhiyun self.console = console 49*4882a593Smuzhiyun self.check_type = check_type 50*4882a593Smuzhiyun 51*4882a593Smuzhiyun def __enter__(self): 52*4882a593Smuzhiyun self.console.disable_check_count[self.check_type] += 1 53*4882a593Smuzhiyun self.console.eval_bad_patterns() 54*4882a593Smuzhiyun 55*4882a593Smuzhiyun def __exit__(self, extype, value, traceback): 56*4882a593Smuzhiyun self.console.disable_check_count[self.check_type] -= 1 57*4882a593Smuzhiyun self.console.eval_bad_patterns() 58*4882a593Smuzhiyun 59*4882a593Smuzhiyunclass ConsoleSetupTimeout(object): 60*4882a593Smuzhiyun """Context manager (for Python's with statement) that temporarily sets up 61*4882a593Smuzhiyun timeout for specific command. This is useful when execution time is greater 62*4882a593Smuzhiyun then default 30s.""" 63*4882a593Smuzhiyun 64*4882a593Smuzhiyun def __init__(self, console, timeout): 65*4882a593Smuzhiyun self.p = console.p 66*4882a593Smuzhiyun self.orig_timeout = self.p.timeout 67*4882a593Smuzhiyun self.p.timeout = timeout 68*4882a593Smuzhiyun 69*4882a593Smuzhiyun def __enter__(self): 70*4882a593Smuzhiyun return self 71*4882a593Smuzhiyun 72*4882a593Smuzhiyun def __exit__(self, extype, value, traceback): 73*4882a593Smuzhiyun self.p.timeout = self.orig_timeout 74*4882a593Smuzhiyun 75*4882a593Smuzhiyunclass ConsoleBase(object): 76*4882a593Smuzhiyun """The interface through which test functions interact with the U-Boot 77*4882a593Smuzhiyun console. This primarily involves executing shell commands, capturing their 78*4882a593Smuzhiyun results, and checking for common error conditions. Some common utilities 79*4882a593Smuzhiyun are also provided too.""" 80*4882a593Smuzhiyun 81*4882a593Smuzhiyun def __init__(self, log, config, max_fifo_fill): 82*4882a593Smuzhiyun """Initialize a U-Boot console connection. 83*4882a593Smuzhiyun 84*4882a593Smuzhiyun Can only usefully be called by sub-classes. 85*4882a593Smuzhiyun 86*4882a593Smuzhiyun Args: 87*4882a593Smuzhiyun log: A mulptiplex_log.Logfile object, to which the U-Boot output 88*4882a593Smuzhiyun will be logged. 89*4882a593Smuzhiyun config: A configuration data structure, as built by conftest.py. 90*4882a593Smuzhiyun max_fifo_fill: The maximum number of characters to send to U-Boot 91*4882a593Smuzhiyun command-line before waiting for U-Boot to echo the characters 92*4882a593Smuzhiyun back. For UART-based HW without HW flow control, this value 93*4882a593Smuzhiyun should be set less than the UART RX FIFO size to avoid 94*4882a593Smuzhiyun overflow, assuming that U-Boot can't keep up with full-rate 95*4882a593Smuzhiyun traffic at the baud rate. 96*4882a593Smuzhiyun 97*4882a593Smuzhiyun Returns: 98*4882a593Smuzhiyun Nothing. 99*4882a593Smuzhiyun """ 100*4882a593Smuzhiyun 101*4882a593Smuzhiyun self.log = log 102*4882a593Smuzhiyun self.config = config 103*4882a593Smuzhiyun self.max_fifo_fill = max_fifo_fill 104*4882a593Smuzhiyun 105*4882a593Smuzhiyun self.logstream = self.log.get_stream('console', sys.stdout) 106*4882a593Smuzhiyun 107*4882a593Smuzhiyun # Array slice removes leading/trailing quotes 108*4882a593Smuzhiyun self.prompt = self.config.buildconfig['config_sys_prompt'][1:-1] 109*4882a593Smuzhiyun self.prompt_compiled = re.compile('^' + re.escape(self.prompt), re.MULTILINE) 110*4882a593Smuzhiyun self.p = None 111*4882a593Smuzhiyun self.disable_check_count = {pat[PAT_ID]: 0 for pat in bad_pattern_defs} 112*4882a593Smuzhiyun self.eval_bad_patterns() 113*4882a593Smuzhiyun 114*4882a593Smuzhiyun self.at_prompt = False 115*4882a593Smuzhiyun self.at_prompt_logevt = None 116*4882a593Smuzhiyun 117*4882a593Smuzhiyun def eval_bad_patterns(self): 118*4882a593Smuzhiyun self.bad_patterns = [pat[PAT_RE] for pat in bad_pattern_defs \ 119*4882a593Smuzhiyun if self.disable_check_count[pat[PAT_ID]] == 0] 120*4882a593Smuzhiyun self.bad_pattern_ids = [pat[PAT_ID] for pat in bad_pattern_defs \ 121*4882a593Smuzhiyun if self.disable_check_count[pat[PAT_ID]] == 0] 122*4882a593Smuzhiyun 123*4882a593Smuzhiyun def close(self): 124*4882a593Smuzhiyun """Terminate the connection to the U-Boot console. 125*4882a593Smuzhiyun 126*4882a593Smuzhiyun This function is only useful once all interaction with U-Boot is 127*4882a593Smuzhiyun complete. Once this function is called, data cannot be sent to or 128*4882a593Smuzhiyun received from U-Boot. 129*4882a593Smuzhiyun 130*4882a593Smuzhiyun Args: 131*4882a593Smuzhiyun None. 132*4882a593Smuzhiyun 133*4882a593Smuzhiyun Returns: 134*4882a593Smuzhiyun Nothing. 135*4882a593Smuzhiyun """ 136*4882a593Smuzhiyun 137*4882a593Smuzhiyun if self.p: 138*4882a593Smuzhiyun self.p.close() 139*4882a593Smuzhiyun self.logstream.close() 140*4882a593Smuzhiyun 141*4882a593Smuzhiyun def run_command(self, cmd, wait_for_echo=True, send_nl=True, 142*4882a593Smuzhiyun wait_for_prompt=True): 143*4882a593Smuzhiyun """Execute a command via the U-Boot console. 144*4882a593Smuzhiyun 145*4882a593Smuzhiyun The command is always sent to U-Boot. 146*4882a593Smuzhiyun 147*4882a593Smuzhiyun U-Boot echoes any command back to its output, and this function 148*4882a593Smuzhiyun typically waits for that to occur. The wait can be disabled by setting 149*4882a593Smuzhiyun wait_for_echo=False, which is useful e.g. when sending CTRL-C to 150*4882a593Smuzhiyun interrupt a long-running command such as "ums". 151*4882a593Smuzhiyun 152*4882a593Smuzhiyun Command execution is typically triggered by sending a newline 153*4882a593Smuzhiyun character. This can be disabled by setting send_nl=False, which is 154*4882a593Smuzhiyun also useful when sending CTRL-C. 155*4882a593Smuzhiyun 156*4882a593Smuzhiyun This function typically waits for the command to finish executing, and 157*4882a593Smuzhiyun returns the console output that it generated. This can be disabled by 158*4882a593Smuzhiyun setting wait_for_prompt=False, which is useful when invoking a long- 159*4882a593Smuzhiyun running command such as "ums". 160*4882a593Smuzhiyun 161*4882a593Smuzhiyun Args: 162*4882a593Smuzhiyun cmd: The command to send. 163*4882a593Smuzhiyun wait_for_echo: Boolean indicating whether to wait for U-Boot to 164*4882a593Smuzhiyun echo the command text back to its output. 165*4882a593Smuzhiyun send_nl: Boolean indicating whether to send a newline character 166*4882a593Smuzhiyun after the command string. 167*4882a593Smuzhiyun wait_for_prompt: Boolean indicating whether to wait for the 168*4882a593Smuzhiyun command prompt to be sent by U-Boot. This typically occurs 169*4882a593Smuzhiyun immediately after the command has been executed. 170*4882a593Smuzhiyun 171*4882a593Smuzhiyun Returns: 172*4882a593Smuzhiyun If wait_for_prompt == False: 173*4882a593Smuzhiyun Nothing. 174*4882a593Smuzhiyun Else: 175*4882a593Smuzhiyun The output from U-Boot during command execution. In other 176*4882a593Smuzhiyun words, the text U-Boot emitted between the point it echod the 177*4882a593Smuzhiyun command string and emitted the subsequent command prompts. 178*4882a593Smuzhiyun """ 179*4882a593Smuzhiyun 180*4882a593Smuzhiyun if self.at_prompt and \ 181*4882a593Smuzhiyun self.at_prompt_logevt != self.logstream.logfile.cur_evt: 182*4882a593Smuzhiyun self.logstream.write(self.prompt, implicit=True) 183*4882a593Smuzhiyun 184*4882a593Smuzhiyun try: 185*4882a593Smuzhiyun self.at_prompt = False 186*4882a593Smuzhiyun if send_nl: 187*4882a593Smuzhiyun cmd += '\n' 188*4882a593Smuzhiyun while cmd: 189*4882a593Smuzhiyun # Limit max outstanding data, so UART FIFOs don't overflow 190*4882a593Smuzhiyun chunk = cmd[:self.max_fifo_fill] 191*4882a593Smuzhiyun cmd = cmd[self.max_fifo_fill:] 192*4882a593Smuzhiyun self.p.send(chunk) 193*4882a593Smuzhiyun if not wait_for_echo: 194*4882a593Smuzhiyun continue 195*4882a593Smuzhiyun chunk = re.escape(chunk) 196*4882a593Smuzhiyun chunk = chunk.replace('\\\n', '[\r\n]') 197*4882a593Smuzhiyun m = self.p.expect([chunk] + self.bad_patterns) 198*4882a593Smuzhiyun if m != 0: 199*4882a593Smuzhiyun self.at_prompt = False 200*4882a593Smuzhiyun raise Exception('Bad pattern found on console: ' + 201*4882a593Smuzhiyun self.bad_pattern_ids[m - 1]) 202*4882a593Smuzhiyun if not wait_for_prompt: 203*4882a593Smuzhiyun return 204*4882a593Smuzhiyun m = self.p.expect([self.prompt_compiled] + self.bad_patterns) 205*4882a593Smuzhiyun if m != 0: 206*4882a593Smuzhiyun self.at_prompt = False 207*4882a593Smuzhiyun raise Exception('Bad pattern found on console: ' + 208*4882a593Smuzhiyun self.bad_pattern_ids[m - 1]) 209*4882a593Smuzhiyun self.at_prompt = True 210*4882a593Smuzhiyun self.at_prompt_logevt = self.logstream.logfile.cur_evt 211*4882a593Smuzhiyun # Only strip \r\n; space/TAB might be significant if testing 212*4882a593Smuzhiyun # indentation. 213*4882a593Smuzhiyun return self.p.before.strip('\r\n') 214*4882a593Smuzhiyun except Exception as ex: 215*4882a593Smuzhiyun self.log.error(str(ex)) 216*4882a593Smuzhiyun self.cleanup_spawn() 217*4882a593Smuzhiyun raise 218*4882a593Smuzhiyun finally: 219*4882a593Smuzhiyun self.log.timestamp() 220*4882a593Smuzhiyun 221*4882a593Smuzhiyun def run_command_list(self, cmds): 222*4882a593Smuzhiyun """Run a list of commands. 223*4882a593Smuzhiyun 224*4882a593Smuzhiyun This is a helper function to call run_command() with default arguments 225*4882a593Smuzhiyun for each command in a list. 226*4882a593Smuzhiyun 227*4882a593Smuzhiyun Args: 228*4882a593Smuzhiyun cmd: List of commands (each a string). 229*4882a593Smuzhiyun Returns: 230*4882a593Smuzhiyun A list of output strings from each command, one element for each 231*4882a593Smuzhiyun command. 232*4882a593Smuzhiyun """ 233*4882a593Smuzhiyun output = [] 234*4882a593Smuzhiyun for cmd in cmds: 235*4882a593Smuzhiyun output.append(self.run_command(cmd)) 236*4882a593Smuzhiyun return output 237*4882a593Smuzhiyun 238*4882a593Smuzhiyun def ctrlc(self): 239*4882a593Smuzhiyun """Send a CTRL-C character to U-Boot. 240*4882a593Smuzhiyun 241*4882a593Smuzhiyun This is useful in order to stop execution of long-running synchronous 242*4882a593Smuzhiyun commands such as "ums". 243*4882a593Smuzhiyun 244*4882a593Smuzhiyun Args: 245*4882a593Smuzhiyun None. 246*4882a593Smuzhiyun 247*4882a593Smuzhiyun Returns: 248*4882a593Smuzhiyun Nothing. 249*4882a593Smuzhiyun """ 250*4882a593Smuzhiyun 251*4882a593Smuzhiyun self.log.action('Sending Ctrl-C') 252*4882a593Smuzhiyun self.run_command(chr(3), wait_for_echo=False, send_nl=False) 253*4882a593Smuzhiyun 254*4882a593Smuzhiyun def wait_for(self, text): 255*4882a593Smuzhiyun """Wait for a pattern to be emitted by U-Boot. 256*4882a593Smuzhiyun 257*4882a593Smuzhiyun This is useful when a long-running command such as "dfu" is executing, 258*4882a593Smuzhiyun and it periodically emits some text that should show up at a specific 259*4882a593Smuzhiyun location in the log file. 260*4882a593Smuzhiyun 261*4882a593Smuzhiyun Args: 262*4882a593Smuzhiyun text: The text to wait for; either a string (containing raw text, 263*4882a593Smuzhiyun not a regular expression) or an re object. 264*4882a593Smuzhiyun 265*4882a593Smuzhiyun Returns: 266*4882a593Smuzhiyun Nothing. 267*4882a593Smuzhiyun """ 268*4882a593Smuzhiyun 269*4882a593Smuzhiyun if type(text) == type(''): 270*4882a593Smuzhiyun text = re.escape(text) 271*4882a593Smuzhiyun m = self.p.expect([text] + self.bad_patterns) 272*4882a593Smuzhiyun if m != 0: 273*4882a593Smuzhiyun raise Exception('Bad pattern found on console: ' + 274*4882a593Smuzhiyun self.bad_pattern_ids[m - 1]) 275*4882a593Smuzhiyun 276*4882a593Smuzhiyun def drain_console(self): 277*4882a593Smuzhiyun """Read from and log the U-Boot console for a short time. 278*4882a593Smuzhiyun 279*4882a593Smuzhiyun U-Boot's console output is only logged when the test code actively 280*4882a593Smuzhiyun waits for U-Boot to emit specific data. There are cases where tests 281*4882a593Smuzhiyun can fail without doing this. For example, if a test asks U-Boot to 282*4882a593Smuzhiyun enable USB device mode, then polls until a host-side device node 283*4882a593Smuzhiyun exists. In such a case, it is useful to log U-Boot's console output 284*4882a593Smuzhiyun in case U-Boot printed clues as to why the host-side even did not 285*4882a593Smuzhiyun occur. This function will do that. 286*4882a593Smuzhiyun 287*4882a593Smuzhiyun Args: 288*4882a593Smuzhiyun None. 289*4882a593Smuzhiyun 290*4882a593Smuzhiyun Returns: 291*4882a593Smuzhiyun Nothing. 292*4882a593Smuzhiyun """ 293*4882a593Smuzhiyun 294*4882a593Smuzhiyun # If we are already not connected to U-Boot, there's nothing to drain. 295*4882a593Smuzhiyun # This should only happen when a previous call to run_command() or 296*4882a593Smuzhiyun # wait_for() failed (and hence the output has already been logged), or 297*4882a593Smuzhiyun # the system is shutting down. 298*4882a593Smuzhiyun if not self.p: 299*4882a593Smuzhiyun return 300*4882a593Smuzhiyun 301*4882a593Smuzhiyun orig_timeout = self.p.timeout 302*4882a593Smuzhiyun try: 303*4882a593Smuzhiyun # Drain the log for a relatively short time. 304*4882a593Smuzhiyun self.p.timeout = 1000 305*4882a593Smuzhiyun # Wait for something U-Boot will likely never send. This will 306*4882a593Smuzhiyun # cause the console output to be read and logged. 307*4882a593Smuzhiyun self.p.expect(['This should never match U-Boot output']) 308*4882a593Smuzhiyun except u_boot_spawn.Timeout: 309*4882a593Smuzhiyun pass 310*4882a593Smuzhiyun finally: 311*4882a593Smuzhiyun self.p.timeout = orig_timeout 312*4882a593Smuzhiyun 313*4882a593Smuzhiyun def ensure_spawned(self): 314*4882a593Smuzhiyun """Ensure a connection to a correctly running U-Boot instance. 315*4882a593Smuzhiyun 316*4882a593Smuzhiyun This may require spawning a new Sandbox process or resetting target 317*4882a593Smuzhiyun hardware, as defined by the implementation sub-class. 318*4882a593Smuzhiyun 319*4882a593Smuzhiyun This is an internal function and should not be called directly. 320*4882a593Smuzhiyun 321*4882a593Smuzhiyun Args: 322*4882a593Smuzhiyun None. 323*4882a593Smuzhiyun 324*4882a593Smuzhiyun Returns: 325*4882a593Smuzhiyun Nothing. 326*4882a593Smuzhiyun """ 327*4882a593Smuzhiyun 328*4882a593Smuzhiyun if self.p: 329*4882a593Smuzhiyun return 330*4882a593Smuzhiyun try: 331*4882a593Smuzhiyun self.log.start_section('Starting U-Boot') 332*4882a593Smuzhiyun self.at_prompt = False 333*4882a593Smuzhiyun self.p = self.get_spawn() 334*4882a593Smuzhiyun # Real targets can take a long time to scroll large amounts of 335*4882a593Smuzhiyun # text if LCD is enabled. This value may need tweaking in the 336*4882a593Smuzhiyun # future, possibly per-test to be optimal. This works for 'help' 337*4882a593Smuzhiyun # on board 'seaboard'. 338*4882a593Smuzhiyun if not self.config.gdbserver: 339*4882a593Smuzhiyun self.p.timeout = 30000 340*4882a593Smuzhiyun self.p.logfile_read = self.logstream 341*4882a593Smuzhiyun bcfg = self.config.buildconfig 342*4882a593Smuzhiyun config_spl = bcfg.get('config_spl', 'n') == 'y' 343*4882a593Smuzhiyun config_spl_serial_support = bcfg.get('config_spl_serial_support', 344*4882a593Smuzhiyun 'n') == 'y' 345*4882a593Smuzhiyun env_spl_skipped = self.config.env.get('env__spl_skipped', 346*4882a593Smuzhiyun False) 347*4882a593Smuzhiyun if config_spl and config_spl_serial_support and not env_spl_skipped: 348*4882a593Smuzhiyun m = self.p.expect([pattern_u_boot_spl_signon] + 349*4882a593Smuzhiyun self.bad_patterns) 350*4882a593Smuzhiyun if m != 0: 351*4882a593Smuzhiyun raise Exception('Bad pattern found on SPL console: ' + 352*4882a593Smuzhiyun self.bad_pattern_ids[m - 1]) 353*4882a593Smuzhiyun m = self.p.expect([pattern_u_boot_main_signon] + self.bad_patterns) 354*4882a593Smuzhiyun if m != 0: 355*4882a593Smuzhiyun raise Exception('Bad pattern found on console: ' + 356*4882a593Smuzhiyun self.bad_pattern_ids[m - 1]) 357*4882a593Smuzhiyun self.u_boot_version_string = self.p.after 358*4882a593Smuzhiyun while True: 359*4882a593Smuzhiyun m = self.p.expect([self.prompt_compiled, 360*4882a593Smuzhiyun pattern_stop_autoboot_prompt] + self.bad_patterns) 361*4882a593Smuzhiyun if m == 0: 362*4882a593Smuzhiyun break 363*4882a593Smuzhiyun if m == 1: 364*4882a593Smuzhiyun self.p.send(' ') 365*4882a593Smuzhiyun continue 366*4882a593Smuzhiyun raise Exception('Bad pattern found on console: ' + 367*4882a593Smuzhiyun self.bad_pattern_ids[m - 2]) 368*4882a593Smuzhiyun self.at_prompt = True 369*4882a593Smuzhiyun self.at_prompt_logevt = self.logstream.logfile.cur_evt 370*4882a593Smuzhiyun except Exception as ex: 371*4882a593Smuzhiyun self.log.error(str(ex)) 372*4882a593Smuzhiyun self.cleanup_spawn() 373*4882a593Smuzhiyun raise 374*4882a593Smuzhiyun finally: 375*4882a593Smuzhiyun self.log.timestamp() 376*4882a593Smuzhiyun self.log.end_section('Starting U-Boot') 377*4882a593Smuzhiyun 378*4882a593Smuzhiyun def cleanup_spawn(self): 379*4882a593Smuzhiyun """Shut down all interaction with the U-Boot instance. 380*4882a593Smuzhiyun 381*4882a593Smuzhiyun This is used when an error is detected prior to re-establishing a 382*4882a593Smuzhiyun connection with a fresh U-Boot instance. 383*4882a593Smuzhiyun 384*4882a593Smuzhiyun This is an internal function and should not be called directly. 385*4882a593Smuzhiyun 386*4882a593Smuzhiyun Args: 387*4882a593Smuzhiyun None. 388*4882a593Smuzhiyun 389*4882a593Smuzhiyun Returns: 390*4882a593Smuzhiyun Nothing. 391*4882a593Smuzhiyun """ 392*4882a593Smuzhiyun 393*4882a593Smuzhiyun try: 394*4882a593Smuzhiyun if self.p: 395*4882a593Smuzhiyun self.p.close() 396*4882a593Smuzhiyun except: 397*4882a593Smuzhiyun pass 398*4882a593Smuzhiyun self.p = None 399*4882a593Smuzhiyun 400*4882a593Smuzhiyun def restart_uboot(self): 401*4882a593Smuzhiyun """Shut down and restart U-Boot.""" 402*4882a593Smuzhiyun self.cleanup_spawn() 403*4882a593Smuzhiyun self.ensure_spawned() 404*4882a593Smuzhiyun 405*4882a593Smuzhiyun def get_spawn_output(self): 406*4882a593Smuzhiyun """Return the start-up output from U-Boot 407*4882a593Smuzhiyun 408*4882a593Smuzhiyun Returns: 409*4882a593Smuzhiyun The output produced by ensure_spawed(), as a string. 410*4882a593Smuzhiyun """ 411*4882a593Smuzhiyun if self.p: 412*4882a593Smuzhiyun return self.p.get_expect_output() 413*4882a593Smuzhiyun return None 414*4882a593Smuzhiyun 415*4882a593Smuzhiyun def validate_version_string_in_text(self, text): 416*4882a593Smuzhiyun """Assert that a command's output includes the U-Boot signon message. 417*4882a593Smuzhiyun 418*4882a593Smuzhiyun This is primarily useful for validating the "version" command without 419*4882a593Smuzhiyun duplicating the signon text regex in a test function. 420*4882a593Smuzhiyun 421*4882a593Smuzhiyun Args: 422*4882a593Smuzhiyun text: The command output text to check. 423*4882a593Smuzhiyun 424*4882a593Smuzhiyun Returns: 425*4882a593Smuzhiyun Nothing. An exception is raised if the validation fails. 426*4882a593Smuzhiyun """ 427*4882a593Smuzhiyun 428*4882a593Smuzhiyun assert(self.u_boot_version_string in text) 429*4882a593Smuzhiyun 430*4882a593Smuzhiyun def disable_check(self, check_type): 431*4882a593Smuzhiyun """Temporarily disable an error check of U-Boot's output. 432*4882a593Smuzhiyun 433*4882a593Smuzhiyun Create a new context manager (for use with the "with" statement) which 434*4882a593Smuzhiyun temporarily disables a particular console output error check. 435*4882a593Smuzhiyun 436*4882a593Smuzhiyun Args: 437*4882a593Smuzhiyun check_type: The type of error-check to disable. Valid values may 438*4882a593Smuzhiyun be found in self.disable_check_count above. 439*4882a593Smuzhiyun 440*4882a593Smuzhiyun Returns: 441*4882a593Smuzhiyun A context manager object. 442*4882a593Smuzhiyun """ 443*4882a593Smuzhiyun 444*4882a593Smuzhiyun return ConsoleDisableCheck(self, check_type) 445*4882a593Smuzhiyun 446*4882a593Smuzhiyun def temporary_timeout(self, timeout): 447*4882a593Smuzhiyun """Temporarily set up different timeout for commands. 448*4882a593Smuzhiyun 449*4882a593Smuzhiyun Create a new context manager (for use with the "with" statement) which 450*4882a593Smuzhiyun temporarily change timeout. 451*4882a593Smuzhiyun 452*4882a593Smuzhiyun Args: 453*4882a593Smuzhiyun timeout: Time in milliseconds. 454*4882a593Smuzhiyun 455*4882a593Smuzhiyun Returns: 456*4882a593Smuzhiyun A context manager object. 457*4882a593Smuzhiyun """ 458*4882a593Smuzhiyun 459*4882a593Smuzhiyun return ConsoleSetupTimeout(self, timeout) 460