blob: ba5ccf9406bc6e26f380b6460d4bc69f96e561cb [file] [log] [blame]
J. Richard Barnette384056b2012-04-16 11:04:46 -07001# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Craig Harrison2b6c6fc2011-06-23 10:34:02 -07002# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4#
5# Expects to be run in an environment with sudo and no interactive password
6# prompt, such as within the Chromium OS development chroot.
7
Congbin Guoa1f9cba2018-07-03 11:36:59 -07008import ast
9import logging
Vadim Bendeburyb80ba592012-12-07 15:02:34 -080010import os
Congbin Guoa1f9cba2018-07-03 11:36:59 -070011import re
12import time
13import xmlrpclib
Vadim Bendeburyb80ba592012-12-07 15:02:34 -080014
Simran Basi741b5d42012-05-18 11:27:15 -070015from autotest_lib.client.common_lib import error
Ricky Liangc31aab32014-07-03 16:23:29 +080016from autotest_lib.server.cros.servo import firmware_programmer
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070017
Kevin Chenga22c4a82016-10-07 14:13:25 -070018# Time to wait when probing for a usb device, it takes on avg 17 seconds
19# to do a full probe.
20_USB_PROBE_TIMEOUT = 40
21
J. Richard Barnette41320ee2013-03-11 13:00:13 -070022
J. Richard Barnette0c9c5882014-06-11 15:27:05 -070023class _PowerStateController(object):
24
25 """Class to provide board-specific power operations.
26
27 This class is responsible for "power on" and "power off"
28 operations that can operate without making assumptions in
29 advance about board state. It offers an interface that
30 abstracts out the different sequences required for different
31 board types.
32
33 """
34
35 # Constants acceptable to be passed for the `rec_mode` parameter
36 # to power_on().
37 #
38 # REC_ON: Boot the DUT in recovery mode, i.e. boot from USB or
39 # SD card.
40 # REC_OFF: Boot in normal mode, i.e. boot from internal storage.
41
42 REC_ON = 'rec'
43 REC_OFF = 'on'
Shelley Chen65938622018-05-16 07:45:54 -070044 REC_ON_FORCE_MRC = 'rec_force_mrc'
J. Richard Barnette0c9c5882014-06-11 15:27:05 -070045
46 # Delay in seconds needed between asserting and de-asserting
47 # warm reset.
48 _RESET_HOLD_TIME = 0.5
49
50 def __init__(self, servo):
51 """Initialize the power state control.
52
53 @param servo Servo object providing the underlying `set` and `get`
54 methods for the target controls.
55
56 """
57 self._servo = servo
58
59 def reset(self):
60 """Force the DUT to reset.
61
62 The DUT is guaranteed to be on at the end of this call,
63 regardless of its previous state, provided that there is
64 working OS software. This also guarantees that the EC has
65 been restarted.
66
67 """
68 self._servo.set_nocheck('power_state', 'reset')
69
70 def warm_reset(self):
71 """Apply warm reset to the DUT.
72
73 This asserts, then de-asserts the 'warm_reset' signal.
74 Generally, this causes the board to restart.
75
76 """
77 self._servo.set_get_all(['warm_reset:on',
78 'sleep:%.4f' % self._RESET_HOLD_TIME,
79 'warm_reset:off'])
80
J. Richard Barnette0c9c5882014-06-11 15:27:05 -070081 def power_off(self):
82 """Force the DUT to power off.
83
84 The DUT is guaranteed to be off at the end of this call,
85 regardless of its previous state, provided that there is
86 working EC and boot firmware. There is no requirement for
87 working OS software.
88
89 """
90 self._servo.set_nocheck('power_state', 'off')
91
92 def power_on(self, rec_mode=REC_OFF):
93 """Force the DUT to power on.
94
95 Prior to calling this function, the DUT must be powered off,
96 e.g. with a call to `power_off()`.
97
98 At power on, recovery mode is set as specified by the
99 corresponding argument. When booting with recovery mode on, it
100 is the caller's responsibility to unplug/plug in a bootable
101 external storage device.
102
103 If the DUT requires a delay after powering on but before
104 processing inputs such as USB stick insertion, the delay is
105 handled by this method; the caller is not responsible for such
106 delays.
107
108 @param rec_mode Setting of recovery mode to be applied at
109 power on. default: REC_OFF aka 'off'
110
111 """
112 self._servo.set_nocheck('power_state', rec_mode)
113
114
Congbin Guoa1f9cba2018-07-03 11:36:59 -0700115class _Uart(object):
116 """Class to capture CPU/EC UART streams."""
117 def __init__(self, servo):
118 self._servo = servo
119 self._streams = []
120
121 def start_capture(self):
122 """Start capturing Uart streams."""
123 logging.debug('Start capturing CPU/EC UART.')
124 self._servo.set('cpu_uart_capture', 'on')
125 self._streams.append(('cpu_uart_stream', 'cpu_uart.log'))
126 try:
127 self._servo.set('ec_uart_capture', 'on')
128 self._streams.append(('ec_uart_stream', 'ec_uart.log'))
129 except error.TestFail as err:
130 if 'No control named' in str(err):
131 logging.debug('The servod is too old that ec_uart_capture not '
132 'supported.')
133
134 def dump(self, output_dir):
135 """Dump UART streams to log files accordingly.
136
137 @param output_dir: A string of output directory name.
138 """
139 for stream, logfile in self._streams:
140 logfile_fullname = os.path.join(output_dir, logfile)
141 try:
142 content = self._servo.get(stream)
143 except Exception as err:
144 logging.warn('Failed to get UART log for %s: %s', stream, err)
145 continue
146
147 # The UART stream may contain non-printable characters, and servo
148 # returns it in string representation. We use `ast.leteral_eval`
149 # to revert it back.
150 with open(logfile_fullname, 'a') as fd:
151 fd.write(ast.literal_eval(content))
152
153 def stop_capture(self):
154 """Stop capturing UART streams."""
155 logging.debug('Stop capturing CPU/EC UART.')
156 for uart in ('cpu_uart_capture', 'ec_uart_capture'):
157 try:
158 self._servo.set(uart, 'off')
159 except error.TestFail as err:
160 if 'No control named' in str(err):
161 logging.debug('The servod is too old that %s not '
162 'supported.', uart)
163 except Exception as err:
164 logging.warn('Failed to stop UART logging for %s: %s', uart,
165 err)
166
167
J. Richard Barnette384056b2012-04-16 11:04:46 -0700168class Servo(object):
J. Richard Barnette41320ee2013-03-11 13:00:13 -0700169
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700170 """Manages control of a Servo board.
171
172 Servo is a board developed by hardware group to aide in the debug and
173 control of various partner devices. Servo's features include the simulation
174 of pressing the power button, closing the lid, and pressing Ctrl-d. This
175 class manages setting up and communicating with a servo demon (servod)
176 process. It provides both high-level functions for common servo tasks and
177 low-level functions for directly setting and reading gpios.
J. Richard Barnette41320ee2013-03-11 13:00:13 -0700178
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700179 """
180
Chrome Bot9a1137d2011-07-19 14:35:00 -0700181 # Power button press delays in seconds.
J. Richard Barnetted2e4cbd2012-06-29 12:18:40 -0700182 #
J. Richard Barnette5383f072012-07-26 17:35:40 -0700183 # The EC specification says that 8.0 seconds should be enough
184 # for the long power press. However, some platforms need a bit
185 # more time. Empirical testing has found these requirements:
186 # Alex: 8.2 seconds
187 # ZGB: 8.5 seconds
188 # The actual value is set to the largest known necessary value.
189 #
190 # TODO(jrbarnette) Being generous is the right thing to do for
191 # existing platforms, but if this code is to be used for
192 # qualification of new hardware, we should be less generous.
Chrome Bot9a1137d2011-07-19 14:35:00 -0700193 SHORT_DELAY = 0.1
J. Richard Barnette5383f072012-07-26 17:35:40 -0700194
Todd Broch31c82502011-08-29 08:14:39 -0700195 # Maximum number of times to re-read power button on release.
Todd Brochcf7c6652012-02-24 13:03:59 -0800196 GET_RETRY_MAX = 10
Chrome Bot9a1137d2011-07-19 14:35:00 -0700197
J. Richard Barnette5383f072012-07-26 17:35:40 -0700198 # Delays to deal with DUT state transitions.
Chrome Bot9a1137d2011-07-19 14:35:00 -0700199 SLEEP_DELAY = 6
200 BOOT_DELAY = 10
J. Richard Barnette41320ee2013-03-11 13:00:13 -0700201
J. Richard Barnette41320ee2013-03-11 13:00:13 -0700202 # Default minimum time interval between 'press' and 'release'
203 # keyboard events.
Vic Yang0aca1c22012-11-19 18:33:56 -0800204 SERVO_KEY_PRESS_DELAY = 0.1
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700205
Tom Wai-Hong Tam93b5c092015-05-14 02:50:43 +0800206 # Time to toggle recovery switch on and off.
207 REC_TOGGLE_DELAY = 0.1
208
Tom Wai-Hong Tamf9ded092015-05-20 05:37:22 +0800209 # Time to toggle development switch on and off.
210 DEV_TOGGLE_DELAY = 0.1
211
Jon Salzc88e5b62011-11-30 14:38:54 +0800212 # Time between an usb disk plugged-in and detected in the system.
213 USB_DETECTION_DELAY = 10
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800214 # Time to keep USB power off before and after USB mux direction is changed
215 USB_POWEROFF_DELAY = 2
Jon Salzc88e5b62011-11-30 14:38:54 +0800216
Simran Basib7850bb2013-07-24 12:33:42 -0700217 # Time to wait before timing out on servo initialization.
218 INIT_TIMEOUT_SECS = 10
Simran Basi59331342013-07-12 12:06:29 -0700219
J. Richard Barnette67ccb872012-04-19 16:34:56 -0700220
Ricky Liang0dd379c2014-04-23 16:29:08 +0800221 def __init__(self, servo_host, servo_serial=None):
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700222 """Sets up the servo communication infrastructure.
223
Fang Deng5d518f42013-08-02 14:04:32 -0700224 @param servo_host: A ServoHost object representing
225 the host running servod.
Ricky Liang0dd379c2014-04-23 16:29:08 +0800226 @param servo_serial: Serial number of the servo board.
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700227 """
Fang Deng5d518f42013-08-02 14:04:32 -0700228 # TODO(fdeng): crbug.com/298379
229 # We should move servo_host object out of servo object
230 # to minimize the dependencies on the rest of Autotest.
231 self._servo_host = servo_host
Ricky Liang0dd379c2014-04-23 16:29:08 +0800232 self._servo_serial = servo_serial
Richard Barnette180efe62016-12-02 23:20:44 +0000233 self._server = servo_host.get_servod_server_proxy()
J. Richard Barnette0c9c5882014-06-11 15:27:05 -0700234 self._power_state = _PowerStateController(self)
Congbin Guoa1f9cba2018-07-03 11:36:59 -0700235 self._uart = _Uart(self)
Fang Dengafb88142013-05-30 17:44:31 -0700236 self._usb_state = None
J. Richard Barnette8f19b392014-08-11 14:05:39 -0700237 self._programmer = None
Yusuf Mohsinally6c078ae2013-11-21 11:06:42 -0800238
Gediminas Ramanauskasba352ad2012-11-09 09:43:32 -0800239
Ricky Liang0dd379c2014-04-23 16:29:08 +0800240 @property
241 def servo_serial(self):
242 """Returns the serial number of the servo board."""
243 return self._servo_serial
244
245
Tom Wai-Hong Tam22ee0e52013-04-03 13:36:39 +0800246 def get_power_state_controller(self):
J. Richard Barnette75136b32013-03-26 13:38:44 -0700247 """Return the power state controller for this Servo.
248
249 The power state controller provides board-independent
250 interfaces for reset, power-on, power-off operations.
251
252 """
253 return self._power_state
254
Fang Deng5d518f42013-08-02 14:04:32 -0700255
J. Richard Barnetteb6133972012-07-19 17:13:55 -0700256 def initialize_dut(self, cold_reset=False):
257 """Initializes a dut for testing purposes.
258
259 This sets various servo signals back to default values
260 appropriate for the target board. By default, if the DUT
261 is already on, it stays on. If the DUT is powered off
262 before initialization, its state afterward is unspecified.
263
J. Richard Barnetteb6133972012-07-19 17:13:55 -0700264 Rationale: Basic initialization of servo sets the lid open,
265 when there is a lid. This operation won't affect powered on
266 units; however, setting the lid open may power on a unit
J. Richard Barnette75136b32013-03-26 13:38:44 -0700267 that's off, depending on the board type and previous state
268 of the device.
269
J. Richard Barnette4b6af0d2014-06-05 09:57:20 -0700270 If `cold_reset` is a true value, the DUT and its EC will be
271 reset, and the DUT rebooted in normal mode.
J. Richard Barnetteb6133972012-07-19 17:13:55 -0700272
273 @param cold_reset If True, cold reset the device after
274 initialization.
275 """
276 self._server.hwinit()
J. Richard Barnette8f19b392014-08-11 14:05:39 -0700277 self.set('usb_mux_oe1', 'on')
J. Richard Barnettecdd1edf2015-07-24 11:39:46 -0700278 self._usb_state = None
J. Richard Barnette8f19b392014-08-11 14:05:39 -0700279 self.switch_usbkey('off')
Congbin Guoa1f9cba2018-07-03 11:36:59 -0700280 self._uart.start_capture()
J. Richard Barnetteb6133972012-07-19 17:13:55 -0700281 if cold_reset:
J. Richard Barnette4b6af0d2014-06-05 09:57:20 -0700282 self._power_state.reset()
J. Richard Barnette1777f5d2014-09-03 15:18:19 -0700283 logging.debug('Servo initialized, version is %s',
284 self._server.get_version())
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700285
286
Tom Wai-Hong Tam1c86c7a2012-10-22 10:08:24 +0800287 def is_localhost(self):
288 """Is the servod hosted locally?
289
290 Returns:
291 True if local hosted; otherwise, False.
292 """
Fang Deng5d518f42013-08-02 14:04:32 -0700293 return self._servo_host.is_localhost()
Tom Wai-Hong Tam1c86c7a2012-10-22 10:08:24 +0800294
295
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700296 def power_long_press(self):
Chrome Bot9a1137d2011-07-19 14:35:00 -0700297 """Simulate a long power button press."""
J. Richard Barnettef12bff22012-07-18 14:41:06 -0700298 # After a long power press, the EC may ignore the next power
299 # button press (at least on Alex). To guarantee that this
300 # won't happen, we need to allow the EC one second to
301 # collect itself.
Yusuf Mohsinally103441a2014-01-14 15:25:44 -0800302 self._server.power_long_press()
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700303
304
305 def power_normal_press(self):
Chrome Bot9a1137d2011-07-19 14:35:00 -0700306 """Simulate a normal power button press."""
Yusuf Mohsinally103441a2014-01-14 15:25:44 -0800307 self._server.power_normal_press()
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700308
309
310 def power_short_press(self):
Chrome Bot9a1137d2011-07-19 14:35:00 -0700311 """Simulate a short power button press."""
Yusuf Mohsinally103441a2014-01-14 15:25:44 -0800312 self._server.power_short_press()
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700313
314
Yusuf Mohsinally103441a2014-01-14 15:25:44 -0800315 def power_key(self, press_secs=''):
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700316 """Simulate a power button press.
317
Yusuf Mohsinally103441a2014-01-14 15:25:44 -0800318 @param press_secs : Str. Time to press key.
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700319 """
Yusuf Mohsinally103441a2014-01-14 15:25:44 -0800320 self._server.power_key(press_secs)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700321
322
323 def lid_open(self):
Yuli Huang7b82dcf2015-05-13 17:58:52 +0800324 """Simulate opening the lid and raise exception if all attempts fail"""
325 self.set('lid_open', 'yes')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700326
327
328 def lid_close(self):
Yuli Huang7b82dcf2015-05-13 17:58:52 +0800329 """Simulate closing the lid and raise exception if all attempts fail
Craig Harrison48997262011-06-27 14:31:10 -0700330
331 Waits 6 seconds to ensure the device is fully asleep before returning.
332 """
Yuli Huang7b82dcf2015-05-13 17:58:52 +0800333 self.set('lid_open', 'no')
Chrome Bot9a1137d2011-07-19 14:35:00 -0700334 time.sleep(Servo.SLEEP_DELAY)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700335
Shelley Chenc26575a2015-09-18 10:56:16 -0700336 def volume_up(self, timeout=300):
Kevin Chenge448a8b2016-09-09 10:18:11 -0700337 """Simulate pushing the volume down button.
338
339 @param timeout: Timeout for setting the volume.
340 """
Shelley Chenc26575a2015-09-18 10:56:16 -0700341 self.set_get_all(['volume_up:yes',
342 'sleep:%.4f' % self.SERVO_KEY_PRESS_DELAY,
343 'volume_up:no'])
344 # we need to wait for commands to take effect before moving on
345 time_left = float(timeout)
346 while time_left > 0.0:
347 value = self.get('volume_up')
348 if value == 'no':
349 return
350 time.sleep(self.SHORT_DELAY)
351 time_left = time_left - self.SHORT_DELAY
352 raise error.TestFail("Failed setting volume_up to no")
353
354 def volume_down(self, timeout=300):
Kevin Chenge448a8b2016-09-09 10:18:11 -0700355 """Simulate pushing the volume down button.
356
357 @param timeout: Timeout for setting the volume.
358 """
Shelley Chenc26575a2015-09-18 10:56:16 -0700359 self.set_get_all(['volume_down:yes',
360 'sleep:%.4f' % self.SERVO_KEY_PRESS_DELAY,
361 'volume_down:no'])
362 # we need to wait for commands to take effect before moving on
363 time_left = float(timeout)
364 while time_left > 0.0:
365 value = self.get('volume_down')
366 if value == 'no':
367 return
368 time.sleep(self.SHORT_DELAY)
369 time_left = time_left - self.SHORT_DELAY
370 raise error.TestFail("Failed setting volume_down to no")
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700371
Yusuf Mohsinally103441a2014-01-14 15:25:44 -0800372 def ctrl_d(self, press_secs=''):
373 """Simulate Ctrl-d simultaneous button presses.
Gediminas Ramanauskasba352ad2012-11-09 09:43:32 -0800374
Yusuf Mohsinally103441a2014-01-14 15:25:44 -0800375 @param press_secs : Str. Time to press key.
Gediminas Ramanauskasba352ad2012-11-09 09:43:32 -0800376 """
Yusuf Mohsinally103441a2014-01-14 15:25:44 -0800377 self._server.ctrl_d(press_secs)
Gediminas Ramanauskas9da80f22012-11-14 12:59:43 -0800378
Gediminas Ramanauskasba352ad2012-11-09 09:43:32 -0800379
Yusuf Mohsinally103441a2014-01-14 15:25:44 -0800380 def ctrl_u(self):
381 """Simulate Ctrl-u simultaneous button presses.
382
383 @param press_secs : Str. Time to press key.
384 """
385 self._server.ctrl_u()
Todd Broch9dfc3a82011-11-01 08:09:28 -0700386
387
Yusuf Mohsinally103441a2014-01-14 15:25:44 -0800388 def ctrl_enter(self, press_secs=''):
389 """Simulate Ctrl-enter simultaneous button presses.
390
391 @param press_secs : Str. Time to press key.
392 """
393 self._server.ctrl_enter(press_secs)
Gediminas Ramanauskas3297d4f2012-09-10 15:30:10 -0700394
395
Yusuf Mohsinally103441a2014-01-14 15:25:44 -0800396 def d_key(self, press_secs=''):
397 """Simulate Enter key button press.
398
399 @param press_secs : Str. Time to press key.
400 """
401 self._server.d_key(press_secs)
Todd Broch9dfc3a82011-11-01 08:09:28 -0700402
403
Yusuf Mohsinally103441a2014-01-14 15:25:44 -0800404 def ctrl_key(self, press_secs=''):
405 """Simulate Enter key button press.
406
407 @param press_secs : Str. Time to press key.
408 """
409 self._server.ctrl_key(press_secs)
Todd Broch9753bd42012-03-21 10:15:08 -0700410
411
Yusuf Mohsinally103441a2014-01-14 15:25:44 -0800412 def enter_key(self, press_secs=''):
413 """Simulate Enter key button press.
414
415 @param press_secs : Str. Time to press key.
416 """
417 self._server.enter_key(press_secs)
Todd Broch9dfc3a82011-11-01 08:09:28 -0700418
419
Yusuf Mohsinally103441a2014-01-14 15:25:44 -0800420 def refresh_key(self, press_secs=''):
421 """Simulate Refresh key (F3) button press.
422
423 @param press_secs : Str. Time to press key.
424 """
425 self._server.refresh_key(press_secs)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700426
427
Yusuf Mohsinally103441a2014-01-14 15:25:44 -0800428 def ctrl_refresh_key(self, press_secs=''):
Tom Wai-Hong Tam9e61e662012-08-01 15:10:07 +0800429 """Simulate Ctrl and Refresh (F3) simultaneous press.
430
431 This key combination is an alternative of Space key.
Yusuf Mohsinally103441a2014-01-14 15:25:44 -0800432
433 @param press_secs : Str. Time to press key.
Tom Wai-Hong Tam9e61e662012-08-01 15:10:07 +0800434 """
Yusuf Mohsinally103441a2014-01-14 15:25:44 -0800435 self._server.ctrl_refresh_key(press_secs)
Tom Wai-Hong Tam9e61e662012-08-01 15:10:07 +0800436
437
Yusuf Mohsinally103441a2014-01-14 15:25:44 -0800438 def imaginary_key(self, press_secs=''):
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700439 """Simulate imaginary key button press.
440
441 Maps to a key that doesn't physically exist.
Yusuf Mohsinally103441a2014-01-14 15:25:44 -0800442
443 @param press_secs : Str. Time to press key.
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700444 """
Yusuf Mohsinally103441a2014-01-14 15:25:44 -0800445 self._server.imaginary_key(press_secs)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700446
447
Vincent Palatine7dc9282016-07-14 11:31:58 +0200448 def sysrq_x(self, press_secs=''):
449 """Simulate Alt VolumeUp X simulataneous press.
450
451 This key combination is the kernel system request (sysrq) X.
452
453 @param press_secs : Str. Time to press key.
454 """
455 self._server.sysrq_x(press_secs)
456
457
Tom Wai-Hong Tam93b5c092015-05-14 02:50:43 +0800458 def toggle_recovery_switch(self):
459 """Toggle recovery switch on and off."""
460 self.enable_recovery_mode()
461 time.sleep(self.REC_TOGGLE_DELAY)
462 self.disable_recovery_mode()
463
464
Craig Harrison6b36b122011-06-28 17:58:43 -0700465 def enable_recovery_mode(self):
466 """Enable recovery mode on device."""
467 self.set('rec_mode', 'on')
468
469
470 def disable_recovery_mode(self):
471 """Disable recovery mode on device."""
472 self.set('rec_mode', 'off')
473
474
Tom Wai-Hong Tamf9ded092015-05-20 05:37:22 +0800475 def toggle_development_switch(self):
476 """Toggle development switch on and off."""
477 self.enable_development_mode()
478 time.sleep(self.DEV_TOGGLE_DELAY)
479 self.disable_development_mode()
480
481
Craig Harrison6b36b122011-06-28 17:58:43 -0700482 def enable_development_mode(self):
483 """Enable development mode on device."""
484 self.set('dev_mode', 'on')
485
486
487 def disable_development_mode(self):
488 """Disable development mode on device."""
489 self.set('dev_mode', 'off')
490
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700491 def boot_devmode(self):
492 """Boot a dev-mode device that is powered off."""
Tom Wai-Hong Tam23869102012-01-17 15:41:30 +0800493 self.power_short_press()
Craig Harrison48997262011-06-27 14:31:10 -0700494 self.pass_devmode()
495
496
497 def pass_devmode(self):
498 """Pass through boot screens in dev-mode."""
Chrome Bot9a1137d2011-07-19 14:35:00 -0700499 time.sleep(Servo.BOOT_DELAY)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700500 self.ctrl_d()
Chrome Bot9a1137d2011-07-19 14:35:00 -0700501 time.sleep(Servo.BOOT_DELAY)
Craig Harrison48997262011-06-27 14:31:10 -0700502
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700503
Yusuf Mohsinally6c078ae2013-11-21 11:06:42 -0800504 def get_board(self):
Wai-Hong Tam0f904002017-09-19 15:52:22 -0700505 """Get the board connected to servod."""
Yusuf Mohsinally6c078ae2013-11-21 11:06:42 -0800506 return self._server.get_board()
507
508
Wai-Hong Tam0f904002017-09-19 15:52:22 -0700509 def get_base_board(self):
510 """Get the board of the base connected to servod."""
Wai-Hong Tam7f6169e2017-09-29 09:23:48 -0700511 try:
512 return self._server.get_base_board()
513 except xmlrpclib.Fault as e:
514 # TODO(waihong): Remove the following compatibility check when
515 # the new versions of hdctools are deployed.
516 if 'not supported' in str(e):
517 logging.warning('The servod is too old that get_base_board '
518 'not supported.')
519 return ''
520 raise
Wai-Hong Tam0f904002017-09-19 15:52:22 -0700521
522
Wai-Hong Tamcc399ee2017-12-08 12:43:28 -0800523 def get_ec_active_copy(self):
524 """Get the active copy of the EC image."""
525 return self.get('ec_active_copy')
526
527
Todd Brochefe72cb2012-07-11 19:58:53 -0700528 def _get_xmlrpclib_exception(self, xmlexc):
529 """Get meaningful exception string from xmlrpc.
530
531 Args:
532 xmlexc: xmlrpclib.Fault object
533
534 xmlrpclib.Fault.faultString has the following format:
535
536 <type 'exception type'>:'actual error message'
537
538 Parse and return the real exception from the servod side instead of the
539 less meaningful one like,
540 <Fault 1: "<type 'exceptions.AttributeError'>:'tca6416' object has no
541 attribute 'hw_driver'">
542
543 Returns:
544 string of underlying exception raised in servod.
545 """
546 return re.sub('^.*>:', '', xmlexc.faultString)
547
548
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700549 def get(self, gpio_name):
J. Richard Barnettecdd1edf2015-07-24 11:39:46 -0700550 """Get the value of a gpio from Servod.
551
552 @param gpio_name Name of the gpio.
553 """
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700554 assert gpio_name
Todd Brochefe72cb2012-07-11 19:58:53 -0700555 try:
Simran Basi1cbc5f22013-07-17 14:23:58 -0700556 return self._server.get(gpio_name)
Todd Brochefe72cb2012-07-11 19:58:53 -0700557 except xmlrpclib.Fault as e:
558 err_msg = "Getting '%s' :: %s" % \
559 (gpio_name, self._get_xmlrpclib_exception(e))
560 raise error.TestFail(err_msg)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700561
562
563 def set(self, gpio_name, gpio_value):
J. Richard Barnettecdd1edf2015-07-24 11:39:46 -0700564 """Set and check the value of a gpio using Servod.
565
566 @param gpio_name Name of the gpio.
567 @param gpio_value New setting for the gpio.
568 """
Chrome Bot9a1137d2011-07-19 14:35:00 -0700569 self.set_nocheck(gpio_name, gpio_value)
Todd Brochcf7c6652012-02-24 13:03:59 -0800570 retry_count = Servo.GET_RETRY_MAX
571 while gpio_value != self.get(gpio_name) and retry_count:
Ilja H. Friedel04be2bd2014-05-07 21:29:59 -0700572 logging.warning("%s != %s, retry %d", gpio_name, gpio_value,
Todd Brochcf7c6652012-02-24 13:03:59 -0800573 retry_count)
574 retry_count -= 1
575 time.sleep(Servo.SHORT_DELAY)
576 if not retry_count:
577 assert gpio_value == self.get(gpio_name), \
578 'Servo failed to set %s to %s' % (gpio_name, gpio_value)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700579
580
581 def set_nocheck(self, gpio_name, gpio_value):
J. Richard Barnettecdd1edf2015-07-24 11:39:46 -0700582 """Set the value of a gpio using Servod.
583
584 @param gpio_name Name of the gpio.
585 @param gpio_value New setting for the gpio.
586 """
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700587 assert gpio_name and gpio_value
Mary Ruthven2f72e2a2018-05-01 17:12:58 -0700588 logging.info('Setting %s to %r', gpio_name, gpio_value)
Todd Brochefe72cb2012-07-11 19:58:53 -0700589 try:
Simran Basi1cbc5f22013-07-17 14:23:58 -0700590 self._server.set(gpio_name, gpio_value)
Todd Brochefe72cb2012-07-11 19:58:53 -0700591 except xmlrpclib.Fault as e:
Mary Ruthven73d3a352018-05-10 15:35:20 -0700592 err_msg = "Setting '%s' to %r :: %s" % \
Todd Brochefe72cb2012-07-11 19:58:53 -0700593 (gpio_name, gpio_value, self._get_xmlrpclib_exception(e))
594 raise error.TestFail(err_msg)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700595
596
Tom Wai-Hong Tam92569bb2013-03-26 14:25:10 +0800597 def set_get_all(self, controls):
598 """Set &| get one or more control values.
599
600 @param controls: list of strings, controls to set &| get.
601
602 @raise: error.TestError in case error occurs setting/getting values.
603 """
604 rv = []
605 try:
Vic Yangcad9acb2013-05-21 14:02:05 +0800606 logging.info('Set/get all: %s', str(controls))
Tom Wai-Hong Tam92569bb2013-03-26 14:25:10 +0800607 rv = self._server.set_get_all(controls)
608 except xmlrpclib.Fault as e:
609 # TODO(waihong): Remove the following backward compatibility when
610 # the new versions of hdctools are deployed.
611 if 'not supported' in str(e):
612 logging.warning('The servod is too old that set_get_all '
613 'not supported. Use set and get instead.')
614 for control in controls:
615 if ':' in control:
616 (name, value) = control.split(':')
617 if name == 'sleep':
618 time.sleep(float(value))
619 else:
620 self.set_nocheck(name, value)
621 rv.append(True)
622 else:
623 rv.append(self.get(name))
624 else:
625 err_msg = "Problem with '%s' :: %s" % \
626 (controls, self._get_xmlrpclib_exception(e))
627 raise error.TestFail(err_msg)
628 return rv
629
630
Jon Salzc88e5b62011-11-30 14:38:54 +0800631 # TODO(waihong) It may fail if multiple servo's are connected to the same
632 # host. Should look for a better way, like the USB serial name, to identify
633 # the USB device.
Simran Basi741b5d42012-05-18 11:27:15 -0700634 # TODO(sbasi) Remove this code from autoserv once firmware tests have been
635 # updated.
Kevin Chenga22c4a82016-10-07 14:13:25 -0700636 def probe_host_usb_dev(self, timeout=_USB_PROBE_TIMEOUT):
Jon Salzc88e5b62011-11-30 14:38:54 +0800637 """Probe the USB disk device plugged-in the servo from the host side.
638
Kevin Chengeb06fe72016-08-22 15:26:32 -0700639 It uses servod to discover if there is a usb device attached to it.
Jon Salzc88e5b62011-11-30 14:38:54 +0800640
Kevin Chenga22c4a82016-10-07 14:13:25 -0700641 @param timeout The timeout period when probing for the usb host device.
642
643 @return: String of USB disk path (e.g. '/dev/sdb') or None.
Jon Salzc88e5b62011-11-30 14:38:54 +0800644 """
Ruben Rodriguez Buchillon9a4bfc32018-10-16 20:46:25 +0800645 # Set up Servo's usb mux.
646 self.switch_usbkey('host')
Kevin Chenga22c4a82016-10-07 14:13:25 -0700647 return self._server.probe_host_usb_dev(timeout) or None
Jon Salzc88e5b62011-11-30 14:38:54 +0800648
649
Mike Truty49153d82012-08-21 22:27:30 -0500650 def image_to_servo_usb(self, image_path=None,
651 make_image_noninteractive=False):
652 """Install an image to the USB key plugged into the servo.
653
654 This method may copy any image to the servo USB key including a
655 recovery image or a test image. These images are frequently used
656 for test purposes such as restoring a corrupted image or conducting
657 an upgrade of ec/fw/kernel as part of a test of a specific image part.
658
J. Richard Barnettecdd1edf2015-07-24 11:39:46 -0700659 @param image_path Path on the host to the recovery image.
660 @param make_image_noninteractive Make the recovery image
661 noninteractive, therefore the DUT
662 will reboot automatically after
663 installation.
Mike Truty49153d82012-08-21 22:27:30 -0500664 """
J. Richard Barnette41320ee2013-03-11 13:00:13 -0700665 # We're about to start plugging/unplugging the USB key. We
666 # don't know the state of the DUT, or what it might choose
667 # to do to the device after hotplug. To avoid surprises,
668 # force the DUT to be off.
669 self._server.hwinit()
670 self._power_state.power_off()
Mike Truty49153d82012-08-21 22:27:30 -0500671
672 # Set up Servo's usb mux.
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800673 self.switch_usbkey('host')
Mike Truty49153d82012-08-21 22:27:30 -0500674 if image_path:
Tom Wai-Hong Tam42f136d2012-10-26 11:11:23 +0800675 logging.info('Searching for usb device and copying image to it. '
676 'Please wait a few minutes...')
Mike Truty49153d82012-08-21 22:27:30 -0500677 if not self._server.download_image_to_usb(image_path):
678 logging.error('Failed to transfer requested image to USB. '
679 'Please take a look at Servo Logs.')
680 raise error.AutotestError('Download image to usb failed.')
681 if make_image_noninteractive:
682 logging.info('Making image noninteractive')
683 if not self._server.make_image_noninteractive():
684 logging.error('Failed to make image noninteractive. '
685 'Please take a look at Servo Logs.')
686
Kalin Stoyanovb3c11f32018-05-11 09:02:00 -0700687 def boot_in_recovery_mode(self):
688 """Boot host DUT in recovery mode."""
689 self._power_state.power_on(rec_mode=self._power_state.REC_ON)
690 self.switch_usbkey('dut')
691
Mike Truty49153d82012-08-21 22:27:30 -0500692
Simran Basi741b5d42012-05-18 11:27:15 -0700693 def install_recovery_image(self, image_path=None,
J. Richard Barnetteb6de7e32013-02-14 13:28:04 -0800694 make_image_noninteractive=False):
Dan Shic67f1332016-04-06 12:38:06 -0700695 """Install the recovery image specified by the path onto the DUT.
Jon Salzc88e5b62011-11-30 14:38:54 +0800696
697 This method uses google recovery mode to install a recovery image
698 onto a DUT through the use of a USB stick that is mounted on a servo
Tom Wai-Hong Tama07115e2012-01-09 12:27:01 +0800699 board specified by the usb_dev. If no image path is specified
Jon Salzc88e5b62011-11-30 14:38:54 +0800700 we use the recovery image already on the usb image.
701
Dan Shic67f1332016-04-06 12:38:06 -0700702 @param image_path: Path on the host to the recovery image.
703 @param make_image_noninteractive: Make the recovery image
704 noninteractive, therefore the DUT will reboot automatically
705 after installation.
Jon Salzc88e5b62011-11-30 14:38:54 +0800706 """
Mike Truty49153d82012-08-21 22:27:30 -0500707 self.image_to_servo_usb(image_path, make_image_noninteractive)
Kalin Stoyanovb3c11f32018-05-11 09:02:00 -0700708 self.boot_in_recovery_mode()
Jon Salzc88e5b62011-11-30 14:38:54 +0800709
710
Vadim Bendeburyb80ba592012-12-07 15:02:34 -0800711 def _scp_image(self, image_path):
712 """Copy image to the servo host.
713
714 When programming a firmware image on the DUT, the image must be
715 located on the host to which the servo device is connected. Sometimes
716 servo is controlled by a remote host, in this case the image needs to
717 be transferred to the remote host.
718
719 @param image_path: a string, name of the firmware image file to be
720 transferred.
721 @return: a string, full path name of the copied file on the remote.
722 """
723
724 dest_path = os.path.join('/tmp', os.path.basename(image_path))
Fang Deng5d518f42013-08-02 14:04:32 -0700725 self._servo_host.send_file(image_path, dest_path)
Vadim Bendeburyb80ba592012-12-07 15:02:34 -0800726 return dest_path
727
728
Dan Shifecdaf42015-07-28 10:17:26 -0700729 def system(self, command, timeout=3600):
J. Richard Barnettecdd1edf2015-07-24 11:39:46 -0700730 """Execute the passed in command on the servod host.
731
732 @param command Command to be executed.
Dan Shifecdaf42015-07-28 10:17:26 -0700733 @param timeout Maximum number of seconds of runtime allowed. Default to
734 1 hour.
J. Richard Barnettecdd1edf2015-07-24 11:39:46 -0700735 """
Vadim Bendebury89ec24e2012-12-17 12:54:18 -0800736 logging.info('Will execute on servo host: %s', command)
Fang Deng5d518f42013-08-02 14:04:32 -0700737 self._servo_host.run(command, timeout=timeout)
Vadim Bendebury89ec24e2012-12-17 12:54:18 -0800738
739
Dan Shifecdaf42015-07-28 10:17:26 -0700740 def system_output(self, command, timeout=3600,
Vadim Bendebury89ec24e2012-12-17 12:54:18 -0800741 ignore_status=False, args=()):
742 """Execute the passed in command on the servod host, return stdout.
743
J. Richard Barnettecdd1edf2015-07-24 11:39:46 -0700744 @param command a string, the command to execute
745 @param timeout an int, max number of seconds to wait til command
Dan Shifecdaf42015-07-28 10:17:26 -0700746 execution completes. Default to 1 hour.
J. Richard Barnettecdd1edf2015-07-24 11:39:46 -0700747 @param ignore_status a Boolean, if true - ignore command's nonzero exit
Vadim Bendebury89ec24e2012-12-17 12:54:18 -0800748 status, otherwise an exception will be thrown
J. Richard Barnettecdd1edf2015-07-24 11:39:46 -0700749 @param args a tuple of strings, each becoming a separate command line
Vadim Bendebury89ec24e2012-12-17 12:54:18 -0800750 parameter for the command
J. Richard Barnettecdd1edf2015-07-24 11:39:46 -0700751 @return command's stdout as a string.
Vadim Bendebury89ec24e2012-12-17 12:54:18 -0800752 """
Fang Deng5d518f42013-08-02 14:04:32 -0700753 return self._servo_host.run(command, timeout=timeout,
754 ignore_status=ignore_status,
755 args=args).stdout.strip()
Vadim Bendeburyb80ba592012-12-07 15:02:34 -0800756
757
Dan Shia5fef052015-05-18 23:28:47 -0700758 def get_servo_version(self):
759 """Get the version of the servo, e.g., servo_v2 or servo_v3.
760
761 @return: The version of the servo.
762
763 """
764 return self._server.get_version()
765
766
Tom Wai-Hong Tam4ac78982016-01-08 02:34:37 +0800767 def _initialize_programmer(self, rw_only=False):
768 """Initialize the firmware programmer.
769
770 @param rw_only: True to initialize a programmer which only
771 programs the RW portions.
772 """
J. Richard Barnette8f19b392014-08-11 14:05:39 -0700773 if self._programmer:
774 return
775 # Initialize firmware programmer
Dan Shia5fef052015-05-18 23:28:47 -0700776 servo_version = self.get_servo_version()
Dan Shi9cb0eec2014-06-03 09:04:50 -0700777 if servo_version.startswith('servo_v2'):
J. Richard Barnette8f19b392014-08-11 14:05:39 -0700778 self._programmer = firmware_programmer.ProgrammerV2(self)
Wai-Hong Tamc36c4d22016-09-09 10:39:45 -0700779 self._programmer_rw = firmware_programmer.ProgrammerV2RwOnly(self)
Kevin Chengdf2e29f2016-09-09 02:31:22 -0700780 # Both servo v3 and v4 use the same programming methods so just leverage
781 # ProgrammerV3 for servo v4 as well.
782 elif (servo_version.startswith('servo_v3') or
783 servo_version.startswith('servo_v4')):
Dan Shia5fef052015-05-18 23:28:47 -0700784 self._programmer = firmware_programmer.ProgrammerV3(self)
Tom Wai-Hong Tam4ac78982016-01-08 02:34:37 +0800785 self._programmer_rw = firmware_programmer.ProgrammerV3RwOnly(self)
J. Richard Barnette8f19b392014-08-11 14:05:39 -0700786 else:
787 raise error.TestError(
788 'No firmware programmer for servo version: %s' %
789 servo_version)
790
791
Tom Wai-Hong Tam4ac78982016-01-08 02:34:37 +0800792 def program_bios(self, image, rw_only=False):
Yusuf Mohsinally6c078ae2013-11-21 11:06:42 -0800793 """Program bios on DUT with given image.
Vadim Bendebury1a7ec632013-02-17 16:22:09 -0800794
Yusuf Mohsinally6c078ae2013-11-21 11:06:42 -0800795 @param image: a string, file name of the BIOS image to program
796 on the DUT.
Tom Wai-Hong Tam4ac78982016-01-08 02:34:37 +0800797 @param rw_only: True to only program the RW portion of BIOS.
Yusuf Mohsinally6c078ae2013-11-21 11:06:42 -0800798
Vadim Bendebury1a7ec632013-02-17 16:22:09 -0800799 """
J. Richard Barnette8f19b392014-08-11 14:05:39 -0700800 self._initialize_programmer()
Ricky Liangc31aab32014-07-03 16:23:29 +0800801 if not self.is_localhost():
802 image = self._scp_image(image)
Tom Wai-Hong Tam4ac78982016-01-08 02:34:37 +0800803 if rw_only:
804 self._programmer_rw.program_bios(image)
805 else:
806 self._programmer.program_bios(image)
Vadim Bendeburyb80ba592012-12-07 15:02:34 -0800807
808
Tom Wai-Hong Tam4ac78982016-01-08 02:34:37 +0800809 def program_ec(self, image, rw_only=False):
Yusuf Mohsinally6c078ae2013-11-21 11:06:42 -0800810 """Program ec on DUT with given image.
Vadim Bendebury1a7ec632013-02-17 16:22:09 -0800811
Yusuf Mohsinally6c078ae2013-11-21 11:06:42 -0800812 @param image: a string, file name of the EC image to program
813 on the DUT.
Tom Wai-Hong Tam4ac78982016-01-08 02:34:37 +0800814 @param rw_only: True to only program the RW portion of EC.
Vadim Bendebury1a7ec632013-02-17 16:22:09 -0800815
Vadim Bendebury1a7ec632013-02-17 16:22:09 -0800816 """
J. Richard Barnette8f19b392014-08-11 14:05:39 -0700817 self._initialize_programmer()
Ricky Liangc31aab32014-07-03 16:23:29 +0800818 if not self.is_localhost():
819 image = self._scp_image(image)
Tom Wai-Hong Tam4ac78982016-01-08 02:34:37 +0800820 if rw_only:
821 self._programmer_rw.program_ec(image)
822 else:
823 self._programmer.program_ec(image)
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800824
Fang Dengafb88142013-05-30 17:44:31 -0700825
826 def _switch_usbkey_power(self, power_state, detection_delay=False):
827 """Switch usbkey power.
828
829 This function switches usbkey power by setting the value of
830 'prtctl4_pwren'. If the power is already in the
831 requested state, this function simply returns.
832
833 @param power_state: A string, 'on' or 'off'.
834 @param detection_delay: A boolean value, if True, sleep
835 for |USB_DETECTION_DELAY| after switching
836 the power on.
837 """
Kevin Chenga22c4a82016-10-07 14:13:25 -0700838 # TODO(kevcheng): Forgive me for this terrible hack. This is just to
839 # handle beaglebones that haven't yet updated and have the
840 # safe_switch_usbkey_power RPC. I'll remove this once all beaglebones
841 # have been updated and also think about a better way to handle
842 # situations like this.
843 try:
844 self._server.safe_switch_usbkey_power(power_state)
845 except Exception:
846 self.set('prtctl4_pwren', power_state)
Fang Dengafb88142013-05-30 17:44:31 -0700847 if power_state == 'off':
848 time.sleep(self.USB_POWEROFF_DELAY)
849 elif detection_delay:
850 time.sleep(self.USB_DETECTION_DELAY)
851
852
853 def switch_usbkey(self, usb_state):
854 """Connect USB flash stick to either host or DUT, or turn USB port off.
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800855
856 This function switches the servo multiplexer to provide electrical
Fang Dengafb88142013-05-30 17:44:31 -0700857 connection between the USB port J3 and either host or DUT side. It
858 can also be used to turn the USB port off.
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800859
Fang Dengafb88142013-05-30 17:44:31 -0700860 Switching to 'dut' or 'host' is accompanied by powercycling
861 of the USB stick, because it sometimes gets wedged if the mux
862 is switched while the stick power is on.
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800863
Fang Dengafb88142013-05-30 17:44:31 -0700864 @param usb_state: A string, one of 'dut', 'host', or 'off'.
865 'dut' and 'host' indicate which side the
866 USB flash device is required to be connected to.
867 'off' indicates turning the USB port off.
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800868
Fang Dengafb88142013-05-30 17:44:31 -0700869 @raise: error.TestError in case the parameter is not 'dut'
870 'host', or 'off'.
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800871 """
Fang Dengafb88142013-05-30 17:44:31 -0700872 if self.get_usbkey_direction() == usb_state:
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800873 return
874
Fang Dengafb88142013-05-30 17:44:31 -0700875 if usb_state == 'off':
Dan Shia5fef052015-05-18 23:28:47 -0700876 self._switch_usbkey_power('off')
877 self._usb_state = usb_state
878 return
Fang Dengafb88142013-05-30 17:44:31 -0700879 elif usb_state == 'host':
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800880 mux_direction = 'servo_sees_usbkey'
Fang Dengafb88142013-05-30 17:44:31 -0700881 elif usb_state == 'dut':
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800882 mux_direction = 'dut_sees_usbkey'
883 else:
Fang Dengafb88142013-05-30 17:44:31 -0700884 raise error.TestError('Unknown USB state request: %s' % usb_state)
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800885
Fang Dengafb88142013-05-30 17:44:31 -0700886 self._switch_usbkey_power('off')
Kevin Chenga22c4a82016-10-07 14:13:25 -0700887 # TODO(kevcheng): Forgive me for this terrible hack. This is just to
888 # handle beaglebones that haven't yet updated and have the
889 # safe_switch_usbkey RPC. I'll remove this once all beaglebones have
890 # been updated and also think about a better way to handle situations
891 # like this.
892 try:
893 self._server.safe_switch_usbkey(mux_direction)
894 except Exception:
895 self.set('usb_mux_sel1', mux_direction)
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800896 time.sleep(self.USB_POWEROFF_DELAY)
Fang Dengafb88142013-05-30 17:44:31 -0700897 self._switch_usbkey_power('on', usb_state == 'host')
898 self._usb_state = usb_state
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800899
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800900
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800901 def get_usbkey_direction(self):
Fang Dengafb88142013-05-30 17:44:31 -0700902 """Get which side USB is connected to or 'off' if usb power is off.
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800903
Fang Dengafb88142013-05-30 17:44:31 -0700904 @return: A string, one of 'dut', 'host', or 'off'.
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800905 """
Fang Dengafb88142013-05-30 17:44:31 -0700906 if not self._usb_state:
907 if self.get('prtctl4_pwren') == 'off':
908 self._usb_state = 'off'
909 elif self.get('usb_mux_sel1').startswith('dut'):
910 self._usb_state = 'dut'
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800911 else:
Fang Dengafb88142013-05-30 17:44:31 -0700912 self._usb_state = 'host'
913 return self._usb_state
Congbin Guoa1f9cba2018-07-03 11:36:59 -0700914
915
916 def dump_uart_streams(self, output_dir):
917 """Get buffered UART streams and append to log files.
918
919 @param output_dir: A string of directory name to save log files.
920 """
921 if self._uart:
922 self._uart.dump(output_dir)
923
924
925 def close(self):
926 """Close the servo object."""
927 if self._uart:
928 self._uart.stop_capture()
929 self._uart = None