blob: 377cc0f4235643d71a2fa0e9902b9f18eb02c861 [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 """
Kevin Chenga22c4a82016-10-07 14:13:25 -0700645 return self._server.probe_host_usb_dev(timeout) or None
Jon Salzc88e5b62011-11-30 14:38:54 +0800646
647
Mike Truty49153d82012-08-21 22:27:30 -0500648 def image_to_servo_usb(self, image_path=None,
649 make_image_noninteractive=False):
650 """Install an image to the USB key plugged into the servo.
651
652 This method may copy any image to the servo USB key including a
653 recovery image or a test image. These images are frequently used
654 for test purposes such as restoring a corrupted image or conducting
655 an upgrade of ec/fw/kernel as part of a test of a specific image part.
656
J. Richard Barnettecdd1edf2015-07-24 11:39:46 -0700657 @param image_path Path on the host to the recovery image.
658 @param make_image_noninteractive Make the recovery image
659 noninteractive, therefore the DUT
660 will reboot automatically after
661 installation.
Mike Truty49153d82012-08-21 22:27:30 -0500662 """
J. Richard Barnette41320ee2013-03-11 13:00:13 -0700663 # We're about to start plugging/unplugging the USB key. We
664 # don't know the state of the DUT, or what it might choose
665 # to do to the device after hotplug. To avoid surprises,
666 # force the DUT to be off.
667 self._server.hwinit()
668 self._power_state.power_off()
Mike Truty49153d82012-08-21 22:27:30 -0500669
670 # Set up Servo's usb mux.
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800671 self.switch_usbkey('host')
Mike Truty49153d82012-08-21 22:27:30 -0500672 if image_path:
Tom Wai-Hong Tam42f136d2012-10-26 11:11:23 +0800673 logging.info('Searching for usb device and copying image to it. '
674 'Please wait a few minutes...')
Mike Truty49153d82012-08-21 22:27:30 -0500675 if not self._server.download_image_to_usb(image_path):
676 logging.error('Failed to transfer requested image to USB. '
677 'Please take a look at Servo Logs.')
678 raise error.AutotestError('Download image to usb failed.')
679 if make_image_noninteractive:
680 logging.info('Making image noninteractive')
681 if not self._server.make_image_noninteractive():
682 logging.error('Failed to make image noninteractive. '
683 'Please take a look at Servo Logs.')
684
Kalin Stoyanovb3c11f32018-05-11 09:02:00 -0700685 def boot_in_recovery_mode(self):
686 """Boot host DUT in recovery mode."""
687 self._power_state.power_on(rec_mode=self._power_state.REC_ON)
688 self.switch_usbkey('dut')
689
Mike Truty49153d82012-08-21 22:27:30 -0500690
Simran Basi741b5d42012-05-18 11:27:15 -0700691 def install_recovery_image(self, image_path=None,
J. Richard Barnetteb6de7e32013-02-14 13:28:04 -0800692 make_image_noninteractive=False):
Dan Shic67f1332016-04-06 12:38:06 -0700693 """Install the recovery image specified by the path onto the DUT.
Jon Salzc88e5b62011-11-30 14:38:54 +0800694
695 This method uses google recovery mode to install a recovery image
696 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 +0800697 board specified by the usb_dev. If no image path is specified
Jon Salzc88e5b62011-11-30 14:38:54 +0800698 we use the recovery image already on the usb image.
699
Dan Shic67f1332016-04-06 12:38:06 -0700700 @param image_path: Path on the host to the recovery image.
701 @param make_image_noninteractive: Make the recovery image
702 noninteractive, therefore the DUT will reboot automatically
703 after installation.
Jon Salzc88e5b62011-11-30 14:38:54 +0800704 """
Mike Truty49153d82012-08-21 22:27:30 -0500705 self.image_to_servo_usb(image_path, make_image_noninteractive)
Kalin Stoyanovb3c11f32018-05-11 09:02:00 -0700706 self.boot_in_recovery_mode()
Jon Salzc88e5b62011-11-30 14:38:54 +0800707
708
Vadim Bendeburyb80ba592012-12-07 15:02:34 -0800709 def _scp_image(self, image_path):
710 """Copy image to the servo host.
711
712 When programming a firmware image on the DUT, the image must be
713 located on the host to which the servo device is connected. Sometimes
714 servo is controlled by a remote host, in this case the image needs to
715 be transferred to the remote host.
716
717 @param image_path: a string, name of the firmware image file to be
718 transferred.
719 @return: a string, full path name of the copied file on the remote.
720 """
721
722 dest_path = os.path.join('/tmp', os.path.basename(image_path))
Fang Deng5d518f42013-08-02 14:04:32 -0700723 self._servo_host.send_file(image_path, dest_path)
Vadim Bendeburyb80ba592012-12-07 15:02:34 -0800724 return dest_path
725
726
Dan Shifecdaf42015-07-28 10:17:26 -0700727 def system(self, command, timeout=3600):
J. Richard Barnettecdd1edf2015-07-24 11:39:46 -0700728 """Execute the passed in command on the servod host.
729
730 @param command Command to be executed.
Dan Shifecdaf42015-07-28 10:17:26 -0700731 @param timeout Maximum number of seconds of runtime allowed. Default to
732 1 hour.
J. Richard Barnettecdd1edf2015-07-24 11:39:46 -0700733 """
Vadim Bendebury89ec24e2012-12-17 12:54:18 -0800734 logging.info('Will execute on servo host: %s', command)
Fang Deng5d518f42013-08-02 14:04:32 -0700735 self._servo_host.run(command, timeout=timeout)
Vadim Bendebury89ec24e2012-12-17 12:54:18 -0800736
737
Dan Shifecdaf42015-07-28 10:17:26 -0700738 def system_output(self, command, timeout=3600,
Vadim Bendebury89ec24e2012-12-17 12:54:18 -0800739 ignore_status=False, args=()):
740 """Execute the passed in command on the servod host, return stdout.
741
J. Richard Barnettecdd1edf2015-07-24 11:39:46 -0700742 @param command a string, the command to execute
743 @param timeout an int, max number of seconds to wait til command
Dan Shifecdaf42015-07-28 10:17:26 -0700744 execution completes. Default to 1 hour.
J. Richard Barnettecdd1edf2015-07-24 11:39:46 -0700745 @param ignore_status a Boolean, if true - ignore command's nonzero exit
Vadim Bendebury89ec24e2012-12-17 12:54:18 -0800746 status, otherwise an exception will be thrown
J. Richard Barnettecdd1edf2015-07-24 11:39:46 -0700747 @param args a tuple of strings, each becoming a separate command line
Vadim Bendebury89ec24e2012-12-17 12:54:18 -0800748 parameter for the command
J. Richard Barnettecdd1edf2015-07-24 11:39:46 -0700749 @return command's stdout as a string.
Vadim Bendebury89ec24e2012-12-17 12:54:18 -0800750 """
Fang Deng5d518f42013-08-02 14:04:32 -0700751 return self._servo_host.run(command, timeout=timeout,
752 ignore_status=ignore_status,
753 args=args).stdout.strip()
Vadim Bendeburyb80ba592012-12-07 15:02:34 -0800754
755
Dan Shia5fef052015-05-18 23:28:47 -0700756 def get_servo_version(self):
757 """Get the version of the servo, e.g., servo_v2 or servo_v3.
758
759 @return: The version of the servo.
760
761 """
762 return self._server.get_version()
763
764
Tom Wai-Hong Tam4ac78982016-01-08 02:34:37 +0800765 def _initialize_programmer(self, rw_only=False):
766 """Initialize the firmware programmer.
767
768 @param rw_only: True to initialize a programmer which only
769 programs the RW portions.
770 """
J. Richard Barnette8f19b392014-08-11 14:05:39 -0700771 if self._programmer:
772 return
773 # Initialize firmware programmer
Dan Shia5fef052015-05-18 23:28:47 -0700774 servo_version = self.get_servo_version()
Dan Shi9cb0eec2014-06-03 09:04:50 -0700775 if servo_version.startswith('servo_v2'):
J. Richard Barnette8f19b392014-08-11 14:05:39 -0700776 self._programmer = firmware_programmer.ProgrammerV2(self)
Wai-Hong Tamc36c4d22016-09-09 10:39:45 -0700777 self._programmer_rw = firmware_programmer.ProgrammerV2RwOnly(self)
Kevin Chengdf2e29f2016-09-09 02:31:22 -0700778 # Both servo v3 and v4 use the same programming methods so just leverage
779 # ProgrammerV3 for servo v4 as well.
780 elif (servo_version.startswith('servo_v3') or
781 servo_version.startswith('servo_v4')):
Dan Shia5fef052015-05-18 23:28:47 -0700782 self._programmer = firmware_programmer.ProgrammerV3(self)
Tom Wai-Hong Tam4ac78982016-01-08 02:34:37 +0800783 self._programmer_rw = firmware_programmer.ProgrammerV3RwOnly(self)
J. Richard Barnette8f19b392014-08-11 14:05:39 -0700784 else:
785 raise error.TestError(
786 'No firmware programmer for servo version: %s' %
787 servo_version)
788
789
Tom Wai-Hong Tam4ac78982016-01-08 02:34:37 +0800790 def program_bios(self, image, rw_only=False):
Yusuf Mohsinally6c078ae2013-11-21 11:06:42 -0800791 """Program bios on DUT with given image.
Vadim Bendebury1a7ec632013-02-17 16:22:09 -0800792
Yusuf Mohsinally6c078ae2013-11-21 11:06:42 -0800793 @param image: a string, file name of the BIOS image to program
794 on the DUT.
Tom Wai-Hong Tam4ac78982016-01-08 02:34:37 +0800795 @param rw_only: True to only program the RW portion of BIOS.
Yusuf Mohsinally6c078ae2013-11-21 11:06:42 -0800796
Vadim Bendebury1a7ec632013-02-17 16:22:09 -0800797 """
J. Richard Barnette8f19b392014-08-11 14:05:39 -0700798 self._initialize_programmer()
Ricky Liangc31aab32014-07-03 16:23:29 +0800799 if not self.is_localhost():
800 image = self._scp_image(image)
Tom Wai-Hong Tam4ac78982016-01-08 02:34:37 +0800801 if rw_only:
802 self._programmer_rw.program_bios(image)
803 else:
804 self._programmer.program_bios(image)
Vadim Bendeburyb80ba592012-12-07 15:02:34 -0800805
806
Tom Wai-Hong Tam4ac78982016-01-08 02:34:37 +0800807 def program_ec(self, image, rw_only=False):
Yusuf Mohsinally6c078ae2013-11-21 11:06:42 -0800808 """Program ec on DUT with given image.
Vadim Bendebury1a7ec632013-02-17 16:22:09 -0800809
Yusuf Mohsinally6c078ae2013-11-21 11:06:42 -0800810 @param image: a string, file name of the EC image to program
811 on the DUT.
Tom Wai-Hong Tam4ac78982016-01-08 02:34:37 +0800812 @param rw_only: True to only program the RW portion of EC.
Vadim Bendebury1a7ec632013-02-17 16:22:09 -0800813
Vadim Bendebury1a7ec632013-02-17 16:22:09 -0800814 """
J. Richard Barnette8f19b392014-08-11 14:05:39 -0700815 self._initialize_programmer()
Ricky Liangc31aab32014-07-03 16:23:29 +0800816 if not self.is_localhost():
817 image = self._scp_image(image)
Tom Wai-Hong Tam4ac78982016-01-08 02:34:37 +0800818 if rw_only:
819 self._programmer_rw.program_ec(image)
820 else:
821 self._programmer.program_ec(image)
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800822
Fang Dengafb88142013-05-30 17:44:31 -0700823
824 def _switch_usbkey_power(self, power_state, detection_delay=False):
825 """Switch usbkey power.
826
827 This function switches usbkey power by setting the value of
828 'prtctl4_pwren'. If the power is already in the
829 requested state, this function simply returns.
830
831 @param power_state: A string, 'on' or 'off'.
832 @param detection_delay: A boolean value, if True, sleep
833 for |USB_DETECTION_DELAY| after switching
834 the power on.
835 """
Kevin Chenga22c4a82016-10-07 14:13:25 -0700836 # TODO(kevcheng): Forgive me for this terrible hack. This is just to
837 # handle beaglebones that haven't yet updated and have the
838 # safe_switch_usbkey_power RPC. I'll remove this once all beaglebones
839 # have been updated and also think about a better way to handle
840 # situations like this.
841 try:
842 self._server.safe_switch_usbkey_power(power_state)
843 except Exception:
844 self.set('prtctl4_pwren', power_state)
Fang Dengafb88142013-05-30 17:44:31 -0700845 if power_state == 'off':
846 time.sleep(self.USB_POWEROFF_DELAY)
847 elif detection_delay:
848 time.sleep(self.USB_DETECTION_DELAY)
849
850
851 def switch_usbkey(self, usb_state):
852 """Connect USB flash stick to either host or DUT, or turn USB port off.
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800853
854 This function switches the servo multiplexer to provide electrical
Fang Dengafb88142013-05-30 17:44:31 -0700855 connection between the USB port J3 and either host or DUT side. It
856 can also be used to turn the USB port off.
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800857
Fang Dengafb88142013-05-30 17:44:31 -0700858 Switching to 'dut' or 'host' is accompanied by powercycling
859 of the USB stick, because it sometimes gets wedged if the mux
860 is switched while the stick power is on.
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800861
Fang Dengafb88142013-05-30 17:44:31 -0700862 @param usb_state: A string, one of 'dut', 'host', or 'off'.
863 'dut' and 'host' indicate which side the
864 USB flash device is required to be connected to.
865 'off' indicates turning the USB port off.
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800866
Fang Dengafb88142013-05-30 17:44:31 -0700867 @raise: error.TestError in case the parameter is not 'dut'
868 'host', or 'off'.
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800869 """
Fang Dengafb88142013-05-30 17:44:31 -0700870 if self.get_usbkey_direction() == usb_state:
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800871 return
872
Fang Dengafb88142013-05-30 17:44:31 -0700873 if usb_state == 'off':
Dan Shia5fef052015-05-18 23:28:47 -0700874 self._switch_usbkey_power('off')
875 self._usb_state = usb_state
876 return
Fang Dengafb88142013-05-30 17:44:31 -0700877 elif usb_state == 'host':
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800878 mux_direction = 'servo_sees_usbkey'
Fang Dengafb88142013-05-30 17:44:31 -0700879 elif usb_state == 'dut':
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800880 mux_direction = 'dut_sees_usbkey'
881 else:
Fang Dengafb88142013-05-30 17:44:31 -0700882 raise error.TestError('Unknown USB state request: %s' % usb_state)
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800883
Fang Dengafb88142013-05-30 17:44:31 -0700884 self._switch_usbkey_power('off')
Kevin Chenga22c4a82016-10-07 14:13:25 -0700885 # TODO(kevcheng): Forgive me for this terrible hack. This is just to
886 # handle beaglebones that haven't yet updated and have the
887 # safe_switch_usbkey RPC. I'll remove this once all beaglebones have
888 # been updated and also think about a better way to handle situations
889 # like this.
890 try:
891 self._server.safe_switch_usbkey(mux_direction)
892 except Exception:
893 self.set('usb_mux_sel1', mux_direction)
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800894 time.sleep(self.USB_POWEROFF_DELAY)
Fang Dengafb88142013-05-30 17:44:31 -0700895 self._switch_usbkey_power('on', usb_state == 'host')
896 self._usb_state = usb_state
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800897
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800898
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800899 def get_usbkey_direction(self):
Fang Dengafb88142013-05-30 17:44:31 -0700900 """Get which side USB is connected to or 'off' if usb power is off.
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800901
Fang Dengafb88142013-05-30 17:44:31 -0700902 @return: A string, one of 'dut', 'host', or 'off'.
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800903 """
Fang Dengafb88142013-05-30 17:44:31 -0700904 if not self._usb_state:
905 if self.get('prtctl4_pwren') == 'off':
906 self._usb_state = 'off'
907 elif self.get('usb_mux_sel1').startswith('dut'):
908 self._usb_state = 'dut'
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800909 else:
Fang Dengafb88142013-05-30 17:44:31 -0700910 self._usb_state = 'host'
911 return self._usb_state
Congbin Guoa1f9cba2018-07-03 11:36:59 -0700912
913
914 def dump_uart_streams(self, output_dir):
915 """Get buffered UART streams and append to log files.
916
917 @param output_dir: A string of directory name to save log files.
918 """
919 if self._uart:
920 self._uart.dump(output_dir)
921
922
923 def close(self):
924 """Close the servo object."""
925 if self._uart:
926 self._uart.stop_capture()
927 self._uart = None