blob: 1ba4c5e505b6b5761010ddb9cc87cdd053d196c0 [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
Vic Yang3a7cf602012-11-07 17:28:39 +08008import logging, re, time, xmlrpclib
Simran Basi741b5d42012-05-18 11:27:15 -07009from autotest_lib.client.common_lib import error
Jon Salzc88e5b62011-11-30 14:38:54 +080010from autotest_lib.server import utils
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070011
J. Richard Barnette384056b2012-04-16 11:04:46 -070012class Servo(object):
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070013 """Manages control of a Servo board.
14
15 Servo is a board developed by hardware group to aide in the debug and
16 control of various partner devices. Servo's features include the simulation
17 of pressing the power button, closing the lid, and pressing Ctrl-d. This
18 class manages setting up and communicating with a servo demon (servod)
19 process. It provides both high-level functions for common servo tasks and
20 low-level functions for directly setting and reading gpios.
21 """
22
Chrome Bot9a1137d2011-07-19 14:35:00 -070023 # Power button press delays in seconds.
J. Richard Barnetted2e4cbd2012-06-29 12:18:40 -070024 #
J. Richard Barnette5383f072012-07-26 17:35:40 -070025 # The EC specification says that 8.0 seconds should be enough
26 # for the long power press. However, some platforms need a bit
27 # more time. Empirical testing has found these requirements:
28 # Alex: 8.2 seconds
29 # ZGB: 8.5 seconds
30 # The actual value is set to the largest known necessary value.
31 #
32 # TODO(jrbarnette) Being generous is the right thing to do for
33 # existing platforms, but if this code is to be used for
34 # qualification of new hardware, we should be less generous.
35 LONG_DELAY = 8.5
Chrome Bot9a1137d2011-07-19 14:35:00 -070036 SHORT_DELAY = 0.1
37 NORMAL_TRANSITION_DELAY = 1.2
J. Richard Barnette5383f072012-07-26 17:35:40 -070038
Todd Broch31c82502011-08-29 08:14:39 -070039 # Maximum number of times to re-read power button on release.
40 RELEASE_RETRY_MAX = 5
Todd Brochcf7c6652012-02-24 13:03:59 -080041 GET_RETRY_MAX = 10
Chrome Bot9a1137d2011-07-19 14:35:00 -070042
J. Richard Barnette5383f072012-07-26 17:35:40 -070043 # Delays to deal with DUT state transitions.
Chrome Bot9a1137d2011-07-19 14:35:00 -070044 SLEEP_DELAY = 6
45 BOOT_DELAY = 10
J. Richard Barnette8bd49842012-07-19 14:21:15 -070046 RECOVERY_BOOT_DELAY = 10
J. Richard Barnettec5a77ad2012-04-25 08:19:00 -070047 RECOVERY_INSTALL_DELAY = 540
Chrome Bot9a1137d2011-07-19 14:35:00 -070048
J. Richard Barnetteb6133972012-07-19 17:13:55 -070049 # Time required for the EC to be working after cold reset.
50 # Five seconds is at least twice as big as necessary for Alex,
51 # and is presumably good enough for all future systems.
52 _EC_RESET_DELAY = 5.0
53
Chrome Bot9a1137d2011-07-19 14:35:00 -070054 # Servo-specific delays.
55 MAX_SERVO_STARTUP_DELAY = 10
56 SERVO_SEND_SIGNAL_DELAY = 0.5
Vic Yange6bdfeb2012-11-07 11:06:21 +080057 SERVO_KEY_PRESS_DELAY = 0.3
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070058
Jon Salzc88e5b62011-11-30 14:38:54 +080059 # Time between an usb disk plugged-in and detected in the system.
60 USB_DETECTION_DELAY = 10
61
Gediminas Ramanauskas3297d4f2012-09-10 15:30:10 -070062 KEY_MATRIX_ALT_0 = {
Gediminas Ramanauskas515e7012012-09-18 17:01:10 -070063 'ctrl_refresh': ['0', '0', '0', '1'],
64 'ctrl_d': ['0', '1', '0', '0'],
65 'd': ['0', '1', '1', '1'],
66 'ctrl_enter': ['1', '0', '0', '0'],
67 'enter': ['1', '0', '1', '1'],
68 'ctrl': ['1', '1', '0', '0'],
69 'refresh': ['1', '1', '0', '1'],
70 'unused': ['1', '1', '1', '0'],
71 'none': ['1', '1', '1', '1']}
Chris Masone6a0680f2012-03-02 08:40:00 -080072
Gediminas Ramanauskas3297d4f2012-09-10 15:30:10 -070073 KEY_MATRIX_ALT_1 = {
Gediminas Ramanauskas515e7012012-09-18 17:01:10 -070074 'ctrl_d': ['0', '0', '1', '0'],
75 'd': ['0', '0', '1', '1'],
76 'ctrl_enter': ['0', '1', '1', '0'],
77 'enter': ['0', '1', '1', '1'],
78 'ctrl_refresh': ['1', '0', '0', '1'],
79 'unused': ['1', '1', '0', '0'],
80 'refresh': ['1', '1', '0', '1'],
81 'ctrl': ['1', '1', '1', '0'],
82 'none': ['1', '1', '1', '1']}
Gediminas Ramanauskas3297d4f2012-09-10 15:30:10 -070083
Gediminas Ramanauskasba352ad2012-11-09 09:43:32 -080084 KEY_MATRIX_ALT_2 = {
85 'ctrl_d': ['0', '0', '0', '1'],
86 'd': ['0', '0', '1', '1'],
87 'unused': ['0', '1', '1', '1'],
88 'rec_mode': ['1', '0', '0', '0'],
89 'ctrl_enter': ['1', '0', '0', '1'],
90 'enter': ['1', '0', '1', '1'],
91 'ctrl': ['1', '1', '0', '1'],
92 'refresh': ['1', '1', '1', '0'],
93 'ctrl_refresh': ['1', '1', '1', '1'],
94 'none': ['1', '1', '1', '1']}
95
96 KEY_MATRIX = [KEY_MATRIX_ALT_0, KEY_MATRIX_ALT_1, KEY_MATRIX_ALT_2]
J. Richard Barnette67ccb872012-04-19 16:34:56 -070097
Chris Masone6a0680f2012-03-02 08:40:00 -080098 @staticmethod
J. Richard Barnette67ccb872012-04-19 16:34:56 -070099 def _make_servo_hostname(hostname):
100 host_parts = hostname.split('.')
101 host_parts[0] = host_parts[0] + '-servo'
102 return '.'.join(host_parts)
Chris Masone6a0680f2012-03-02 08:40:00 -0800103
J. Richard Barnette67ccb872012-04-19 16:34:56 -0700104 @staticmethod
105 def get_lab_servo(target_hostname):
106 """Instantiate a Servo for |target_hostname| in the lab.
Chris Masone6a0680f2012-03-02 08:40:00 -0800107
J. Richard Barnette67ccb872012-04-19 16:34:56 -0700108 Assuming that |target_hostname| is a device in the CrOS test
109 lab, create and return a Servo object pointed at the servo
110 attached to that DUT. The servo in the test lab is assumed
111 to already have servod up and running on it.
112
113 @param target_hostname: device whose servo we want to target.
Chris Masone6a0680f2012-03-02 08:40:00 -0800114 @return an appropriately configured Servo
115 """
J. Richard Barnette67ccb872012-04-19 16:34:56 -0700116 servo_host = Servo._make_servo_hostname(target_hostname)
117 if utils.host_is_in_lab_zone(servo_host):
Vic Yang3a7cf602012-11-07 17:28:39 +0800118 try:
Gediminas Ramanauskasba352ad2012-11-09 09:43:32 -0800119 return Servo(servo_host=servo_host, target_host=target_hostname)
Vic Yang3a7cf602012-11-07 17:28:39 +0800120 except: # pylint: disable=W0702
121 # TODO(jrbarnette): Long-term, if we can't get to
122 # a servo in the lab, we want to fail, so we should
123 # pass any exceptions along. Short-term, we're not
124 # ready to rely on servo, so we ignore failures.
125 pass
J. Richard Barnette67ccb872012-04-19 16:34:56 -0700126 return None
Chris Masone6a0680f2012-03-02 08:40:00 -0800127
128
Gediminas Ramanauskasba352ad2012-11-09 09:43:32 -0800129 def __init__(self, servo_host='localhost', target_host='local',
130 servo_port=9999):
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700131 """Sets up the servo communication infrastructure.
132
Gediminas Ramanauskasba352ad2012-11-09 09:43:32 -0800133 @param servo_host Name of the host where the servod process
134 is running.
135 @param target_host Name of the target which is connected to servo
136 @param servo_port Port the servod process is listening on.
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700137 """
Gediminas Ramanauskas3297d4f2012-09-10 15:30:10 -0700138 self._key_matrix = 0
J. Richard Barnette384056b2012-04-16 11:04:46 -0700139 self._server = None
Todd Brochf24d2782011-08-19 10:55:41 -0700140 self._connect_servod(servo_host, servo_port)
Tom Wai-Hong Tam1c86c7a2012-10-22 10:08:24 +0800141 self._is_localhost = (servo_host == 'localhost')
Gediminas Ramanauskasba352ad2012-11-09 09:43:32 -0800142 self._target_host = target_host
143
144
145 def get_target_hostname(self):
146 """Retrieves target (DUT) hostname."""
147 return self._target_host
Chrome Bot9a1137d2011-07-19 14:35:00 -0700148
149
J. Richard Barnetteb6133972012-07-19 17:13:55 -0700150 def initialize_dut(self, cold_reset=False):
151 """Initializes a dut for testing purposes.
152
153 This sets various servo signals back to default values
154 appropriate for the target board. By default, if the DUT
155 is already on, it stays on. If the DUT is powered off
156 before initialization, its state afterward is unspecified.
157
158 If cold reset is requested, the DUT is guaranteed to be off
159 at the end of initialization, regardless of its initial
160 state.
161
162 Rationale: Basic initialization of servo sets the lid open,
163 when there is a lid. This operation won't affect powered on
164 units; however, setting the lid open may power on a unit
165 that's off, depending on factors outside the scope of this
166 function.
167
168 @param cold_reset If True, cold reset the device after
169 initialization.
170 """
171 self._server.hwinit()
172 if cold_reset:
173 self.cold_reset()
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700174
175
Tom Wai-Hong Tam1c86c7a2012-10-22 10:08:24 +0800176 def is_localhost(self):
177 """Is the servod hosted locally?
178
179 Returns:
180 True if local hosted; otherwise, False.
181 """
182 return self._is_localhost
183
184
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700185 def power_long_press(self):
Chrome Bot9a1137d2011-07-19 14:35:00 -0700186 """Simulate a long power button press."""
J. Richard Barnettef12bff22012-07-18 14:41:06 -0700187 # After a long power press, the EC may ignore the next power
188 # button press (at least on Alex). To guarantee that this
189 # won't happen, we need to allow the EC one second to
190 # collect itself.
Chrome Bot9a1137d2011-07-19 14:35:00 -0700191 self.power_key(Servo.LONG_DELAY)
J. Richard Barnettef12bff22012-07-18 14:41:06 -0700192 time.sleep(1.0)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700193
194
195 def power_normal_press(self):
Chrome Bot9a1137d2011-07-19 14:35:00 -0700196 """Simulate a normal power button press."""
197 self.power_key()
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700198
199
200 def power_short_press(self):
Chrome Bot9a1137d2011-07-19 14:35:00 -0700201 """Simulate a short power button press."""
202 self.power_key(Servo.SHORT_DELAY)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700203
204
Chrome Bot9a1137d2011-07-19 14:35:00 -0700205 def power_key(self, secs=NORMAL_TRANSITION_DELAY):
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700206 """Simulate a power button press.
207
208 Args:
209 secs: Time in seconds to simulate the keypress.
210 """
Craig Harrison6b36b122011-06-28 17:58:43 -0700211 self.set_nocheck('pwr_button', 'press')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700212 time.sleep(secs)
Todd Broch31c82502011-08-29 08:14:39 -0700213 self.set_nocheck('pwr_button', 'release')
214 # TODO(tbroch) Different systems have different release times on the
215 # power button that this loop addresses. Longer term we may want to
216 # make this delay platform specific.
217 retry = 1
218 while True:
219 value = self.get('pwr_button')
220 if value == 'release' or retry > Servo.RELEASE_RETRY_MAX:
221 break
Todd Broch9753bd42012-03-21 10:15:08 -0700222 logging.info('Waiting for pwr_button to release, retry %d.', retry)
Todd Broch31c82502011-08-29 08:14:39 -0700223 retry += 1
224 time.sleep(Servo.SHORT_DELAY)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700225
226
227 def lid_open(self):
228 """Simulate opening the lid."""
Craig Harrison48997262011-06-27 14:31:10 -0700229 self.set_nocheck('lid_open', 'yes')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700230
231
232 def lid_close(self):
Craig Harrison48997262011-06-27 14:31:10 -0700233 """Simulate closing the lid.
234
235 Waits 6 seconds to ensure the device is fully asleep before returning.
236 """
237 self.set_nocheck('lid_open', 'no')
Chrome Bot9a1137d2011-07-19 14:35:00 -0700238 time.sleep(Servo.SLEEP_DELAY)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700239
240
Gediminas Ramanauskasba352ad2012-11-09 09:43:32 -0800241 def _press_keys(self, key):
242 """Simulate button presses.
243
244 Note, key presses will remain on indefinitely. See
245 _press_and_release_keys for release procedure.
246 """
Gediminas Ramanauskas515e7012012-09-18 17:01:10 -0700247 (m1_a1, m1_a0, m2_a1, m2_a0) = self.KEY_MATRIX[self._key_matrix][key]
Todd Broch9753bd42012-03-21 10:15:08 -0700248 self.set_nocheck('kbd_m2_a0', m2_a0)
249 self.set_nocheck('kbd_m2_a1', m2_a1)
250 self.set_nocheck('kbd_m1_a0', m1_a0)
251 self.set_nocheck('kbd_m1_a1', m1_a1)
Vic Yange262a3e2012-11-02 18:48:37 +0800252 self.set_nocheck('kbd_en', 'on')
Gediminas Ramanauskasba352ad2012-11-09 09:43:32 -0800253
254
255 def _press_and_release_keys(self, key,
256 press_secs=SERVO_KEY_PRESS_DELAY):
257 """Simulate button presses and release."""
258 self._press_keys(key)
Todd Broch9dfc3a82011-11-01 08:09:28 -0700259 time.sleep(press_secs)
260 self.set_nocheck('kbd_en', 'off')
261
262
Gediminas Ramanauskas3297d4f2012-09-10 15:30:10 -0700263 def set_key_matrix(self, matrix=0):
264 """Set keyboard mapping"""
265 self._key_matrix = matrix
266
267
Chrome Bot9a1137d2011-07-19 14:35:00 -0700268 def ctrl_d(self):
269 """Simulate Ctrl-d simultaneous button presses."""
Gediminas Ramanauskas515e7012012-09-18 17:01:10 -0700270 self._press_and_release_keys('ctrl_d')
Todd Broch9dfc3a82011-11-01 08:09:28 -0700271
272
Todd Broch9753bd42012-03-21 10:15:08 -0700273 def ctrl_enter(self):
274 """Simulate Ctrl-enter simultaneous button presses."""
Gediminas Ramanauskas515e7012012-09-18 17:01:10 -0700275 self._press_and_release_keys('ctrl_enter')
Todd Broch9753bd42012-03-21 10:15:08 -0700276
277
Todd Broch9dfc3a82011-11-01 08:09:28 -0700278 def d_key(self):
279 """Simulate Enter key button press."""
Gediminas Ramanauskas515e7012012-09-18 17:01:10 -0700280 self._press_and_release_keys('d')
Todd Broch9dfc3a82011-11-01 08:09:28 -0700281
282
283 def ctrl_key(self):
284 """Simulate Enter key button press."""
Gediminas Ramanauskas515e7012012-09-18 17:01:10 -0700285 self._press_and_release_keys('ctrl')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700286
287
Chrome Bot9a1137d2011-07-19 14:35:00 -0700288 def enter_key(self):
289 """Simulate Enter key button press."""
Gediminas Ramanauskas515e7012012-09-18 17:01:10 -0700290 self._press_and_release_keys('enter')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700291
292
Chrome Bot9a1137d2011-07-19 14:35:00 -0700293 def refresh_key(self):
294 """Simulate Refresh key (F3) button press."""
Gediminas Ramanauskas515e7012012-09-18 17:01:10 -0700295 self._press_and_release_keys('refresh')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700296
297
Tom Wai-Hong Tam9e61e662012-08-01 15:10:07 +0800298 def ctrl_refresh_key(self):
299 """Simulate Ctrl and Refresh (F3) simultaneous press.
300
301 This key combination is an alternative of Space key.
302 """
Gediminas Ramanauskas515e7012012-09-18 17:01:10 -0700303 self._press_and_release_keys('ctrl_refresh')
Tom Wai-Hong Tam9e61e662012-08-01 15:10:07 +0800304
305
Chrome Bot9a1137d2011-07-19 14:35:00 -0700306 def imaginary_key(self):
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700307 """Simulate imaginary key button press.
308
309 Maps to a key that doesn't physically exist.
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700310 """
Gediminas Ramanauskas515e7012012-09-18 17:01:10 -0700311 self._press_and_release_keys('unused')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700312
313
Craig Harrison6b36b122011-06-28 17:58:43 -0700314 def enable_recovery_mode(self):
315 """Enable recovery mode on device."""
316 self.set('rec_mode', 'on')
317
318
Gediminas Ramanauskasba352ad2012-11-09 09:43:32 -0800319 def custom_recovery_mode(self):
320 """Custom key combination to enter recovery mode."""
321 self._press_keys('rec_mode')
322 self.power_normal_press()
323 time.sleep(self.SERVO_KEY_PRESS_DELAY)
324 self.set_nocheck('kbd_en', 'off')
325
326
Craig Harrison6b36b122011-06-28 17:58:43 -0700327 def disable_recovery_mode(self):
328 """Disable recovery mode on device."""
329 self.set('rec_mode', 'off')
330
331
332 def enable_development_mode(self):
333 """Enable development mode on device."""
334 self.set('dev_mode', 'on')
335
336
337 def disable_development_mode(self):
338 """Disable development mode on device."""
339 self.set('dev_mode', 'off')
340
Chris Sosa8ee1d592011-08-14 16:50:31 -0700341 def enable_usb_hub(self, host=False):
Craig Harrison86b1a572011-08-12 11:26:52 -0700342 """Enable Servo's USB/ethernet hub.
343
Chris Sosa8ee1d592011-08-14 16:50:31 -0700344 This is equivalent to plugging in the USB devices attached to Servo to
345 the host (if |host| is True) or dut (if |host| is False).
346 For host=False, requires that the USB out on the servo board is
347 connected to a USB in port on the target device. Servo's USB ports are
348 labeled DUT_HUB_USB1 and DUT_HUB_USB2. Servo's ethernet port is also
349 connected to this hub. Servo's USB port DUT_HUB_IN is the output of the
350 hub.
Craig Harrison86b1a572011-08-12 11:26:52 -0700351 """
352 self.set('dut_hub_pwren', 'on')
Chris Sosa8ee1d592011-08-14 16:50:31 -0700353 if host:
Todd Broch9753bd42012-03-21 10:15:08 -0700354 self.set('usb_mux_oe1', 'on')
355 self.set('usb_mux_sel1', 'servo_sees_usbkey')
Chris Sosa8ee1d592011-08-14 16:50:31 -0700356 else:
Todd Broch9753bd42012-03-21 10:15:08 -0700357 self.set('dut_hub_sel', 'dut_sees_hub')
Chris Sosa8ee1d592011-08-14 16:50:31 -0700358
Craig Harrison86b1a572011-08-12 11:26:52 -0700359 self.set('dut_hub_on', 'yes')
360
361
362 def disable_usb_hub(self):
363 """Disable Servo's USB/ethernet hub.
364
365 This is equivalent to unplugging the USB devices attached to Servo.
366 """
367 self.set('dut_hub_on', 'no')
368
369
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700370 def boot_devmode(self):
371 """Boot a dev-mode device that is powered off."""
Tom Wai-Hong Tam23869102012-01-17 15:41:30 +0800372 self.power_short_press()
Craig Harrison48997262011-06-27 14:31:10 -0700373 self.pass_devmode()
374
375
376 def pass_devmode(self):
377 """Pass through boot screens in dev-mode."""
Chrome Bot9a1137d2011-07-19 14:35:00 -0700378 time.sleep(Servo.BOOT_DELAY)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700379 self.ctrl_d()
Chrome Bot9a1137d2011-07-19 14:35:00 -0700380 time.sleep(Servo.BOOT_DELAY)
Craig Harrison48997262011-06-27 14:31:10 -0700381
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700382
Craig Harrison6b36b122011-06-28 17:58:43 -0700383 def cold_reset(self):
384 """Perform a cold reset of the EC.
385
J. Richard Barnetteb6133972012-07-19 17:13:55 -0700386 This has the side effect of shutting off the device. The
387 device is guaranteed to be off at the end of this call.
Craig Harrison6b36b122011-06-28 17:58:43 -0700388 """
J. Richard Barnetteb6133972012-07-19 17:13:55 -0700389 # After the reset, give the EC the time it needs to
390 # re-initialize.
Craig Harrison6b36b122011-06-28 17:58:43 -0700391 self.set('cold_reset', 'on')
Chrome Bot9a1137d2011-07-19 14:35:00 -0700392 time.sleep(Servo.SERVO_SEND_SIGNAL_DELAY)
J. Richard Barnetteb6133972012-07-19 17:13:55 -0700393 self.set('cold_reset', 'off')
394 time.sleep(self._EC_RESET_DELAY)
Craig Harrison6b36b122011-06-28 17:58:43 -0700395
396
397 def warm_reset(self):
398 """Perform a warm reset of the device.
399
400 Has the side effect of restarting the device.
401 """
402 self.set('warm_reset', 'on')
Chrome Bot9a1137d2011-07-19 14:35:00 -0700403 time.sleep(Servo.SERVO_SEND_SIGNAL_DELAY)
Craig Harrison6b36b122011-06-28 17:58:43 -0700404 self.set('warm_reset', 'off')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700405
406
Todd Brochefe72cb2012-07-11 19:58:53 -0700407 def _get_xmlrpclib_exception(self, xmlexc):
408 """Get meaningful exception string from xmlrpc.
409
410 Args:
411 xmlexc: xmlrpclib.Fault object
412
413 xmlrpclib.Fault.faultString has the following format:
414
415 <type 'exception type'>:'actual error message'
416
417 Parse and return the real exception from the servod side instead of the
418 less meaningful one like,
419 <Fault 1: "<type 'exceptions.AttributeError'>:'tca6416' object has no
420 attribute 'hw_driver'">
421
422 Returns:
423 string of underlying exception raised in servod.
424 """
425 return re.sub('^.*>:', '', xmlexc.faultString)
426
427
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700428 def get(self, gpio_name):
429 """Get the value of a gpio from Servod."""
430 assert gpio_name
Todd Brochefe72cb2012-07-11 19:58:53 -0700431 try:
432 return self._server.get(gpio_name)
433 except xmlrpclib.Fault as e:
434 err_msg = "Getting '%s' :: %s" % \
435 (gpio_name, self._get_xmlrpclib_exception(e))
436 raise error.TestFail(err_msg)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700437
438
439 def set(self, gpio_name, gpio_value):
440 """Set and check the value of a gpio using Servod."""
Chrome Bot9a1137d2011-07-19 14:35:00 -0700441 self.set_nocheck(gpio_name, gpio_value)
Todd Brochcf7c6652012-02-24 13:03:59 -0800442 retry_count = Servo.GET_RETRY_MAX
443 while gpio_value != self.get(gpio_name) and retry_count:
444 logging.warn("%s != %s, retry %d", gpio_name, gpio_value,
445 retry_count)
446 retry_count -= 1
447 time.sleep(Servo.SHORT_DELAY)
448 if not retry_count:
449 assert gpio_value == self.get(gpio_name), \
450 'Servo failed to set %s to %s' % (gpio_name, gpio_value)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700451
452
453 def set_nocheck(self, gpio_name, gpio_value):
454 """Set the value of a gpio using Servod."""
455 assert gpio_name and gpio_value
Todd Broch9753bd42012-03-21 10:15:08 -0700456 logging.info('Setting %s to %s', gpio_name, gpio_value)
Todd Brochefe72cb2012-07-11 19:58:53 -0700457 try:
458 self._server.set(gpio_name, gpio_value)
459 except xmlrpclib.Fault as e:
460 err_msg = "Setting '%s' to '%s' :: %s" % \
461 (gpio_name, gpio_value, self._get_xmlrpclib_exception(e))
462 raise error.TestFail(err_msg)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700463
464
Jon Salzc88e5b62011-11-30 14:38:54 +0800465 # TODO(waihong) It may fail if multiple servo's are connected to the same
466 # host. Should look for a better way, like the USB serial name, to identify
467 # the USB device.
Simran Basi741b5d42012-05-18 11:27:15 -0700468 # TODO(sbasi) Remove this code from autoserv once firmware tests have been
469 # updated.
Jon Salzc88e5b62011-11-30 14:38:54 +0800470 def probe_host_usb_dev(self):
471 """Probe the USB disk device plugged-in the servo from the host side.
472
473 It tries to switch the USB mux to make the host unable to see the
474 USB disk and compares the result difference.
475
476 This only works if the servo is attached to the local host.
477
478 Returns:
479 A string of USB disk path, like '/dev/sdb', or None if not existed.
480 """
481 cmd = 'ls /dev/sd[a-z]'
482 original_value = self.get('usb_mux_sel1')
483
484 # Make the host unable to see the USB disk.
485 if original_value != 'dut_sees_usbkey':
486 self.set('usb_mux_sel1', 'dut_sees_usbkey')
487 time.sleep(self.USB_DETECTION_DELAY)
488 no_usb_set = set(utils.system_output(cmd, ignore_status=True).split())
489
490 # Make the host able to see the USB disk.
491 self.set('usb_mux_sel1', 'servo_sees_usbkey')
492 time.sleep(self.USB_DETECTION_DELAY)
493 has_usb_set = set(utils.system_output(cmd, ignore_status=True).split())
494
495 # Back to its original value.
496 if original_value != 'servo_sees_usbkey':
497 self.set('usb_mux_sel1', original_value)
498 time.sleep(self.USB_DETECTION_DELAY)
499
500 diff_set = has_usb_set - no_usb_set
501 if len(diff_set) == 1:
502 return diff_set.pop()
503 else:
504 return None
505
506
Mike Truty49153d82012-08-21 22:27:30 -0500507 def image_to_servo_usb(self, image_path=None,
508 make_image_noninteractive=False):
509 """Install an image to the USB key plugged into the servo.
510
511 This method may copy any image to the servo USB key including a
512 recovery image or a test image. These images are frequently used
513 for test purposes such as restoring a corrupted image or conducting
514 an upgrade of ec/fw/kernel as part of a test of a specific image part.
515
516 Args:
517 image_path: Path on the host to the recovery image.
518 make_image_noninteractive: Make the recovery image noninteractive,
519 therefore the DUT will reboot
520 automatically after installation.
521 """
522 # Turn the device off. This should happen before USB key detection, to
523 # prevent a recovery destined DUT from sensing the USB key due to the
524 # autodetection procedure.
525 self.initialize_dut(cold_reset=True)
526
527 # Set up Servo's usb mux.
528 self.set('prtctl4_pwren', 'on')
529 self.enable_usb_hub(host=True)
530 if image_path:
Tom Wai-Hong Tam42f136d2012-10-26 11:11:23 +0800531 logging.info('Searching for usb device and copying image to it. '
532 'Please wait a few minutes...')
Mike Truty49153d82012-08-21 22:27:30 -0500533 if not self._server.download_image_to_usb(image_path):
534 logging.error('Failed to transfer requested image to USB. '
535 'Please take a look at Servo Logs.')
536 raise error.AutotestError('Download image to usb failed.')
537 if make_image_noninteractive:
538 logging.info('Making image noninteractive')
539 if not self._server.make_image_noninteractive():
540 logging.error('Failed to make image noninteractive. '
541 'Please take a look at Servo Logs.')
542
543
Simran Basi741b5d42012-05-18 11:27:15 -0700544 def install_recovery_image(self, image_path=None,
545 wait_timeout=RECOVERY_INSTALL_DELAY,
546 make_image_noninteractive=False,
547 host=None):
Jon Salzc88e5b62011-11-30 14:38:54 +0800548 """Install the recovery image specied by the path onto the DUT.
549
550 This method uses google recovery mode to install a recovery image
551 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 +0800552 board specified by the usb_dev. If no image path is specified
Jon Salzc88e5b62011-11-30 14:38:54 +0800553 we use the recovery image already on the usb image.
554
555 Args:
556 image_path: Path on the host to the recovery image.
Gilad Arnold9df73de2012-03-14 09:35:08 -0700557 wait_timeout: How long to wait for completion; default is
558 determined by a constant.
Simran Basi741b5d42012-05-18 11:27:15 -0700559 make_image_noninteractive: Make the recovery image noninteractive,
560 therefore the DUT will reboot
561 automatically after installation.
562 host: Host object for the DUT that the installation process is
563 running on. If provided, will wait to see if the host is back
564 up after starting recovery mode.
Jon Salzc88e5b62011-11-30 14:38:54 +0800565 """
Mike Truty49153d82012-08-21 22:27:30 -0500566 self.image_to_servo_usb(image_path, make_image_noninteractive)
Jon Salzc88e5b62011-11-30 14:38:54 +0800567
568 # Boot in recovery mode.
569 try:
Jon Salzc88e5b62011-11-30 14:38:54 +0800570 self.enable_recovery_mode()
Tom Wai-Hong Tam23869102012-01-17 15:41:30 +0800571 self.power_short_press()
Jon Salzc88e5b62011-11-30 14:38:54 +0800572 time.sleep(Servo.RECOVERY_BOOT_DELAY)
Tom Wai-Hong Tam922ed052012-01-09 12:27:52 +0800573 self.set('usb_mux_sel1', 'dut_sees_usbkey')
Jon Salzc88e5b62011-11-30 14:38:54 +0800574 self.disable_recovery_mode()
575
Simran Basi741b5d42012-05-18 11:27:15 -0700576 if host:
Jon Salzc88e5b62011-11-30 14:38:54 +0800577 logging.info('Running the recovery process on the DUT. '
Simran Basi741b5d42012-05-18 11:27:15 -0700578 'Will wait up to %d seconds for recovery to '
579 'complete.', wait_timeout)
580 start_time = time.time()
581 # Wait for the host to come up.
582 if host.wait_up(timeout=wait_timeout):
583 logging.info('Recovery process completed successfully in '
584 '%d seconds.', time.time() - start_time)
585 else:
Vic Yang3a7cf602012-11-07 17:28:39 +0800586 logging.error('Host failed to come back up in the allotted '
587 'time: %d seconds.', wait_timeout)
Jon Salzc88e5b62011-11-30 14:38:54 +0800588 logging.info('Removing the usb key from the DUT.')
589 self.disable_usb_hub()
Jon Salzc88e5b62011-11-30 14:38:54 +0800590 except:
591 # In case anything went wrong we want to make sure to do a clean
592 # reset.
593 self.disable_recovery_mode()
594 self.warm_reset()
595 raise
596
597
Todd Brochf24d2782011-08-19 10:55:41 -0700598 def _connect_servod(self, servo_host, servo_port):
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700599 """Connect to the Servod process with XMLRPC.
600
601 Args:
602 servo_port: Port the Servod process is listening on.
603 """
Todd Brochf24d2782011-08-19 10:55:41 -0700604 remote = 'http://%s:%s' % (servo_host, servo_port)
Todd Broch96d83aa2011-08-29 14:37:38 -0700605 self._server = xmlrpclib.ServerProxy(remote)
Todd Brochf24d2782011-08-19 10:55:41 -0700606 try:
607 self._server.echo("ping-test")
Todd Broch96d83aa2011-08-29 14:37:38 -0700608 except:
609 logging.error('Connection to servod failed')
Todd Brochf24d2782011-08-19 10:55:41 -0700610 raise