blob: 3205cec2bec824e37710a92a1b3df9125bd76d1e [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
Todd Brochefe72cb2012-07-11 19:58:53 -07008import logging, os, re, select, subprocess, sys, time, xmlrpclib
Jon Salzc88e5b62011-11-30 14:38:54 +08009from autotest_lib.client.bin import utils as client_utils
Simran Basi741b5d42012-05-18 11:27:15 -070010from autotest_lib.client.common_lib import error
Jon Salzc88e5b62011-11-30 14:38:54 +080011from autotest_lib.server import utils
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070012
J. Richard Barnette384056b2012-04-16 11:04:46 -070013class Servo(object):
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070014 """Manages control of a Servo board.
15
16 Servo is a board developed by hardware group to aide in the debug and
17 control of various partner devices. Servo's features include the simulation
18 of pressing the power button, closing the lid, and pressing Ctrl-d. This
19 class manages setting up and communicating with a servo demon (servod)
20 process. It provides both high-level functions for common servo tasks and
21 low-level functions for directly setting and reading gpios.
22 """
23
Chrome Bot9a1137d2011-07-19 14:35:00 -070024 # Power button press delays in seconds.
J. Richard Barnetted2e4cbd2012-06-29 12:18:40 -070025 #
J. Richard Barnette5383f072012-07-26 17:35:40 -070026 # The EC specification says that 8.0 seconds should be enough
27 # for the long power press. However, some platforms need a bit
28 # more time. Empirical testing has found these requirements:
29 # Alex: 8.2 seconds
30 # ZGB: 8.5 seconds
31 # The actual value is set to the largest known necessary value.
32 #
33 # TODO(jrbarnette) Being generous is the right thing to do for
34 # existing platforms, but if this code is to be used for
35 # qualification of new hardware, we should be less generous.
36 LONG_DELAY = 8.5
Chrome Bot9a1137d2011-07-19 14:35:00 -070037 SHORT_DELAY = 0.1
38 NORMAL_TRANSITION_DELAY = 1.2
J. Richard Barnette5383f072012-07-26 17:35:40 -070039
Todd Broch31c82502011-08-29 08:14:39 -070040 # Maximum number of times to re-read power button on release.
41 RELEASE_RETRY_MAX = 5
Todd Brochcf7c6652012-02-24 13:03:59 -080042 GET_RETRY_MAX = 10
Chrome Bot9a1137d2011-07-19 14:35:00 -070043
J. Richard Barnette5383f072012-07-26 17:35:40 -070044 # Delays to deal with DUT state transitions.
Chrome Bot9a1137d2011-07-19 14:35:00 -070045 SLEEP_DELAY = 6
46 BOOT_DELAY = 10
J. Richard Barnette8bd49842012-07-19 14:21:15 -070047 RECOVERY_BOOT_DELAY = 10
J. Richard Barnettec5a77ad2012-04-25 08:19:00 -070048 RECOVERY_INSTALL_DELAY = 540
Chrome Bot9a1137d2011-07-19 14:35:00 -070049
J. Richard Barnetteb6133972012-07-19 17:13:55 -070050 # Time required for the EC to be working after cold reset.
51 # Five seconds is at least twice as big as necessary for Alex,
52 # and is presumably good enough for all future systems.
53 _EC_RESET_DELAY = 5.0
54
Chrome Bot9a1137d2011-07-19 14:35:00 -070055 # Servo-specific delays.
56 MAX_SERVO_STARTUP_DELAY = 10
57 SERVO_SEND_SIGNAL_DELAY = 0.5
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
Todd Broch9753bd42012-03-21 10:15:08 -070062 KEY_MATRIX = {
63 'm1': {'ctrl_r': ['0', '0'], 'd': ['0', '1'],
64 'enter': ['1', '0'], 'none': ['1', '1']},
65 'm2': {'ctrl': ['0', '0'], 'refresh': ['0', '1'],
66 'unused': ['1', '0'], 'none': ['1', '1']}
67 }
Chris Masone6a0680f2012-03-02 08:40:00 -080068
J. Richard Barnette67ccb872012-04-19 16:34:56 -070069
Chris Masone6a0680f2012-03-02 08:40:00 -080070 @staticmethod
J. Richard Barnette67ccb872012-04-19 16:34:56 -070071 def _make_servo_hostname(hostname):
72 host_parts = hostname.split('.')
73 host_parts[0] = host_parts[0] + '-servo'
74 return '.'.join(host_parts)
Chris Masone6a0680f2012-03-02 08:40:00 -080075
J. Richard Barnette67ccb872012-04-19 16:34:56 -070076 @staticmethod
77 def get_lab_servo(target_hostname):
78 """Instantiate a Servo for |target_hostname| in the lab.
Chris Masone6a0680f2012-03-02 08:40:00 -080079
J. Richard Barnette67ccb872012-04-19 16:34:56 -070080 Assuming that |target_hostname| is a device in the CrOS test
81 lab, create and return a Servo object pointed at the servo
82 attached to that DUT. The servo in the test lab is assumed
83 to already have servod up and running on it.
84
85 @param target_hostname: device whose servo we want to target.
Chris Masone6a0680f2012-03-02 08:40:00 -080086 @return an appropriately configured Servo
87 """
J. Richard Barnette67ccb872012-04-19 16:34:56 -070088 servo_host = Servo._make_servo_hostname(target_hostname)
89 if utils.host_is_in_lab_zone(servo_host):
90 try:
91 return Servo(servo_host=servo_host)
92 except:
93 # TODO(jrbarnette): Long-term, if we can't get to
94 # a servo in the lab, we want to fail, so we should
95 # pass any exceptions along. Short-term, we're not
96 # ready to rely on servo, so we ignore failures.
97 pass
98 return None
Chris Masone6a0680f2012-03-02 08:40:00 -080099
100
J. Richard Barnetteb6133972012-07-19 17:13:55 -0700101 def __init__(self, servo_host='localhost', servo_port=9999):
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700102 """Sets up the servo communication infrastructure.
103
J. Richard Barnette55fb8062012-05-23 10:29:31 -0700104 @param servo_host Name of the host where the servod process
105 is running.
106 @param servo_port Port the servod process is listening on.
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700107 """
J. Richard Barnette384056b2012-04-16 11:04:46 -0700108 self._server = None
Todd Brochf24d2782011-08-19 10:55:41 -0700109 self._connect_servod(servo_host, servo_port)
Chrome Bot9a1137d2011-07-19 14:35:00 -0700110
111
J. Richard Barnetteb6133972012-07-19 17:13:55 -0700112 def initialize_dut(self, cold_reset=False):
113 """Initializes a dut for testing purposes.
114
115 This sets various servo signals back to default values
116 appropriate for the target board. By default, if the DUT
117 is already on, it stays on. If the DUT is powered off
118 before initialization, its state afterward is unspecified.
119
120 If cold reset is requested, the DUT is guaranteed to be off
121 at the end of initialization, regardless of its initial
122 state.
123
124 Rationale: Basic initialization of servo sets the lid open,
125 when there is a lid. This operation won't affect powered on
126 units; however, setting the lid open may power on a unit
127 that's off, depending on factors outside the scope of this
128 function.
129
130 @param cold_reset If True, cold reset the device after
131 initialization.
132 """
133 self._server.hwinit()
134 if cold_reset:
135 self.cold_reset()
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700136
137
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700138 def power_long_press(self):
Chrome Bot9a1137d2011-07-19 14:35:00 -0700139 """Simulate a long power button press."""
J. Richard Barnettef12bff22012-07-18 14:41:06 -0700140 # After a long power press, the EC may ignore the next power
141 # button press (at least on Alex). To guarantee that this
142 # won't happen, we need to allow the EC one second to
143 # collect itself.
Chrome Bot9a1137d2011-07-19 14:35:00 -0700144 self.power_key(Servo.LONG_DELAY)
J. Richard Barnettef12bff22012-07-18 14:41:06 -0700145 time.sleep(1.0)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700146
147
148 def power_normal_press(self):
Chrome Bot9a1137d2011-07-19 14:35:00 -0700149 """Simulate a normal power button press."""
150 self.power_key()
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700151
152
153 def power_short_press(self):
Chrome Bot9a1137d2011-07-19 14:35:00 -0700154 """Simulate a short power button press."""
155 self.power_key(Servo.SHORT_DELAY)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700156
157
Chrome Bot9a1137d2011-07-19 14:35:00 -0700158 def power_key(self, secs=NORMAL_TRANSITION_DELAY):
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700159 """Simulate a power button press.
160
161 Args:
162 secs: Time in seconds to simulate the keypress.
163 """
Craig Harrison6b36b122011-06-28 17:58:43 -0700164 self.set_nocheck('pwr_button', 'press')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700165 time.sleep(secs)
Todd Broch31c82502011-08-29 08:14:39 -0700166 self.set_nocheck('pwr_button', 'release')
167 # TODO(tbroch) Different systems have different release times on the
168 # power button that this loop addresses. Longer term we may want to
169 # make this delay platform specific.
170 retry = 1
171 while True:
172 value = self.get('pwr_button')
173 if value == 'release' or retry > Servo.RELEASE_RETRY_MAX:
174 break
Todd Broch9753bd42012-03-21 10:15:08 -0700175 logging.info('Waiting for pwr_button to release, retry %d.', retry)
Todd Broch31c82502011-08-29 08:14:39 -0700176 retry += 1
177 time.sleep(Servo.SHORT_DELAY)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700178
179
180 def lid_open(self):
181 """Simulate opening the lid."""
Craig Harrison48997262011-06-27 14:31:10 -0700182 self.set_nocheck('lid_open', 'yes')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700183
184
185 def lid_close(self):
Craig Harrison48997262011-06-27 14:31:10 -0700186 """Simulate closing the lid.
187
188 Waits 6 seconds to ensure the device is fully asleep before returning.
189 """
190 self.set_nocheck('lid_open', 'no')
Chrome Bot9a1137d2011-07-19 14:35:00 -0700191 time.sleep(Servo.SLEEP_DELAY)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700192
193
Todd Broch9753bd42012-03-21 10:15:08 -0700194 def _press_and_release_keys(self, m1, m2,
195 press_secs=SERVO_SEND_SIGNAL_DELAY):
Todd Broch9dfc3a82011-11-01 08:09:28 -0700196 """Simulate button presses."""
Todd Broch9753bd42012-03-21 10:15:08 -0700197 # set keys to none
198 (m2_a1, m2_a0) = self.KEY_MATRIX['m2']['none']
199 (m1_a1, m1_a0) = self.KEY_MATRIX['m1']['none']
200 self.set_nocheck('kbd_m2_a0', m2_a0)
201 self.set_nocheck('kbd_m2_a1', m2_a1)
202 self.set_nocheck('kbd_m1_a0', m1_a0)
203 self.set_nocheck('kbd_m1_a1', m1_a1)
Todd Broch9dfc3a82011-11-01 08:09:28 -0700204
Todd Broch9753bd42012-03-21 10:15:08 -0700205 (m2_a1, m2_a0) = self.KEY_MATRIX['m2'][m2]
206 (m1_a1, m1_a0) = self.KEY_MATRIX['m1'][m1]
Todd Broch9dfc3a82011-11-01 08:09:28 -0700207 self.set_nocheck('kbd_en', 'on')
Todd Broch9753bd42012-03-21 10:15:08 -0700208 self.set_nocheck('kbd_m2_a0', m2_a0)
209 self.set_nocheck('kbd_m2_a1', m2_a1)
210 self.set_nocheck('kbd_m1_a0', m1_a0)
211 self.set_nocheck('kbd_m1_a1', m1_a1)
Todd Broch9dfc3a82011-11-01 08:09:28 -0700212 time.sleep(press_secs)
213 self.set_nocheck('kbd_en', 'off')
214
215
Chrome Bot9a1137d2011-07-19 14:35:00 -0700216 def ctrl_d(self):
217 """Simulate Ctrl-d simultaneous button presses."""
Todd Broch9dfc3a82011-11-01 08:09:28 -0700218 self._press_and_release_keys('d', 'ctrl')
219
220
Todd Broch9753bd42012-03-21 10:15:08 -0700221 def ctrl_enter(self):
222 """Simulate Ctrl-enter simultaneous button presses."""
223 self._press_and_release_keys('enter', 'ctrl')
224
225
Todd Broch9dfc3a82011-11-01 08:09:28 -0700226 def d_key(self):
227 """Simulate Enter key button press."""
228 self._press_and_release_keys('d', 'none')
229
230
231 def ctrl_key(self):
232 """Simulate Enter key button press."""
233 self._press_and_release_keys('none', 'ctrl')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700234
235
Chrome Bot9a1137d2011-07-19 14:35:00 -0700236 def enter_key(self):
237 """Simulate Enter key button press."""
Todd Broch9dfc3a82011-11-01 08:09:28 -0700238 self._press_and_release_keys('enter', 'none')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700239
240
Chrome Bot9a1137d2011-07-19 14:35:00 -0700241 def refresh_key(self):
242 """Simulate Refresh key (F3) button press."""
Todd Broch9dfc3a82011-11-01 08:09:28 -0700243 self._press_and_release_keys('none', 'refresh')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700244
245
Tom Wai-Hong Tam9e61e662012-08-01 15:10:07 +0800246 def ctrl_refresh_key(self):
247 """Simulate Ctrl and Refresh (F3) simultaneous press.
248
249 This key combination is an alternative of Space key.
250 """
251 self._press_and_release_keys('ctrl_r', 'refresh')
252
253
Chrome Bot9a1137d2011-07-19 14:35:00 -0700254 def imaginary_key(self):
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700255 """Simulate imaginary key button press.
256
257 Maps to a key that doesn't physically exist.
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700258 """
Todd Broch9dfc3a82011-11-01 08:09:28 -0700259 self._press_and_release_keys('none', 'unused')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700260
261
Craig Harrison6b36b122011-06-28 17:58:43 -0700262 def enable_recovery_mode(self):
263 """Enable recovery mode on device."""
264 self.set('rec_mode', 'on')
265
266
267 def disable_recovery_mode(self):
268 """Disable recovery mode on device."""
269 self.set('rec_mode', 'off')
270
271
272 def enable_development_mode(self):
273 """Enable development mode on device."""
274 self.set('dev_mode', 'on')
275
276
277 def disable_development_mode(self):
278 """Disable development mode on device."""
279 self.set('dev_mode', 'off')
280
Chris Sosa8ee1d592011-08-14 16:50:31 -0700281 def enable_usb_hub(self, host=False):
Craig Harrison86b1a572011-08-12 11:26:52 -0700282 """Enable Servo's USB/ethernet hub.
283
Chris Sosa8ee1d592011-08-14 16:50:31 -0700284 This is equivalent to plugging in the USB devices attached to Servo to
285 the host (if |host| is True) or dut (if |host| is False).
286 For host=False, requires that the USB out on the servo board is
287 connected to a USB in port on the target device. Servo's USB ports are
288 labeled DUT_HUB_USB1 and DUT_HUB_USB2. Servo's ethernet port is also
289 connected to this hub. Servo's USB port DUT_HUB_IN is the output of the
290 hub.
Craig Harrison86b1a572011-08-12 11:26:52 -0700291 """
292 self.set('dut_hub_pwren', 'on')
Chris Sosa8ee1d592011-08-14 16:50:31 -0700293 if host:
Todd Broch9753bd42012-03-21 10:15:08 -0700294 self.set('usb_mux_oe1', 'on')
295 self.set('usb_mux_sel1', 'servo_sees_usbkey')
Chris Sosa8ee1d592011-08-14 16:50:31 -0700296 else:
Todd Broch9753bd42012-03-21 10:15:08 -0700297 self.set('dut_hub_sel', 'dut_sees_hub')
Chris Sosa8ee1d592011-08-14 16:50:31 -0700298
Craig Harrison86b1a572011-08-12 11:26:52 -0700299 self.set('dut_hub_on', 'yes')
300
301
302 def disable_usb_hub(self):
303 """Disable Servo's USB/ethernet hub.
304
305 This is equivalent to unplugging the USB devices attached to Servo.
306 """
307 self.set('dut_hub_on', 'no')
308
309
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700310 def boot_devmode(self):
311 """Boot a dev-mode device that is powered off."""
Tom Wai-Hong Tam23869102012-01-17 15:41:30 +0800312 self.power_short_press()
Craig Harrison48997262011-06-27 14:31:10 -0700313 self.pass_devmode()
314
315
316 def pass_devmode(self):
317 """Pass through boot screens in dev-mode."""
Chrome Bot9a1137d2011-07-19 14:35:00 -0700318 time.sleep(Servo.BOOT_DELAY)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700319 self.ctrl_d()
Chrome Bot9a1137d2011-07-19 14:35:00 -0700320 time.sleep(Servo.BOOT_DELAY)
Craig Harrison48997262011-06-27 14:31:10 -0700321
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700322
Craig Harrison6b36b122011-06-28 17:58:43 -0700323 def cold_reset(self):
324 """Perform a cold reset of the EC.
325
J. Richard Barnetteb6133972012-07-19 17:13:55 -0700326 This has the side effect of shutting off the device. The
327 device is guaranteed to be off at the end of this call.
Craig Harrison6b36b122011-06-28 17:58:43 -0700328 """
J. Richard Barnetteb6133972012-07-19 17:13:55 -0700329 # After the reset, give the EC the time it needs to
330 # re-initialize.
Craig Harrison6b36b122011-06-28 17:58:43 -0700331 self.set('cold_reset', 'on')
Chrome Bot9a1137d2011-07-19 14:35:00 -0700332 time.sleep(Servo.SERVO_SEND_SIGNAL_DELAY)
J. Richard Barnetteb6133972012-07-19 17:13:55 -0700333 self.set('cold_reset', 'off')
334 time.sleep(self._EC_RESET_DELAY)
Craig Harrison6b36b122011-06-28 17:58:43 -0700335
336
337 def warm_reset(self):
338 """Perform a warm reset of the device.
339
340 Has the side effect of restarting the device.
341 """
342 self.set('warm_reset', 'on')
Chrome Bot9a1137d2011-07-19 14:35:00 -0700343 time.sleep(Servo.SERVO_SEND_SIGNAL_DELAY)
Craig Harrison6b36b122011-06-28 17:58:43 -0700344 self.set('warm_reset', 'off')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700345
346
Todd Brochefe72cb2012-07-11 19:58:53 -0700347 def _get_xmlrpclib_exception(self, xmlexc):
348 """Get meaningful exception string from xmlrpc.
349
350 Args:
351 xmlexc: xmlrpclib.Fault object
352
353 xmlrpclib.Fault.faultString has the following format:
354
355 <type 'exception type'>:'actual error message'
356
357 Parse and return the real exception from the servod side instead of the
358 less meaningful one like,
359 <Fault 1: "<type 'exceptions.AttributeError'>:'tca6416' object has no
360 attribute 'hw_driver'">
361
362 Returns:
363 string of underlying exception raised in servod.
364 """
365 return re.sub('^.*>:', '', xmlexc.faultString)
366
367
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700368 def get(self, gpio_name):
369 """Get the value of a gpio from Servod."""
370 assert gpio_name
Todd Brochefe72cb2012-07-11 19:58:53 -0700371 try:
372 return self._server.get(gpio_name)
373 except xmlrpclib.Fault as e:
374 err_msg = "Getting '%s' :: %s" % \
375 (gpio_name, self._get_xmlrpclib_exception(e))
376 raise error.TestFail(err_msg)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700377
378
379 def set(self, gpio_name, gpio_value):
380 """Set and check the value of a gpio using Servod."""
Chrome Bot9a1137d2011-07-19 14:35:00 -0700381 self.set_nocheck(gpio_name, gpio_value)
Todd Brochcf7c6652012-02-24 13:03:59 -0800382 retry_count = Servo.GET_RETRY_MAX
383 while gpio_value != self.get(gpio_name) and retry_count:
384 logging.warn("%s != %s, retry %d", gpio_name, gpio_value,
385 retry_count)
386 retry_count -= 1
387 time.sleep(Servo.SHORT_DELAY)
388 if not retry_count:
389 assert gpio_value == self.get(gpio_name), \
390 'Servo failed to set %s to %s' % (gpio_name, gpio_value)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700391
392
393 def set_nocheck(self, gpio_name, gpio_value):
394 """Set the value of a gpio using Servod."""
395 assert gpio_name and gpio_value
Todd Broch9753bd42012-03-21 10:15:08 -0700396 logging.info('Setting %s to %s', gpio_name, gpio_value)
Todd Brochefe72cb2012-07-11 19:58:53 -0700397 try:
398 self._server.set(gpio_name, gpio_value)
399 except xmlrpclib.Fault as e:
400 err_msg = "Setting '%s' to '%s' :: %s" % \
401 (gpio_name, gpio_value, self._get_xmlrpclib_exception(e))
402 raise error.TestFail(err_msg)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700403
404
Jon Salzc88e5b62011-11-30 14:38:54 +0800405 # TODO(waihong) It may fail if multiple servo's are connected to the same
406 # host. Should look for a better way, like the USB serial name, to identify
407 # the USB device.
Simran Basi741b5d42012-05-18 11:27:15 -0700408 # TODO(sbasi) Remove this code from autoserv once firmware tests have been
409 # updated.
Jon Salzc88e5b62011-11-30 14:38:54 +0800410 def probe_host_usb_dev(self):
411 """Probe the USB disk device plugged-in the servo from the host side.
412
413 It tries to switch the USB mux to make the host unable to see the
414 USB disk and compares the result difference.
415
416 This only works if the servo is attached to the local host.
417
418 Returns:
419 A string of USB disk path, like '/dev/sdb', or None if not existed.
420 """
421 cmd = 'ls /dev/sd[a-z]'
422 original_value = self.get('usb_mux_sel1')
423
424 # Make the host unable to see the USB disk.
425 if original_value != 'dut_sees_usbkey':
426 self.set('usb_mux_sel1', 'dut_sees_usbkey')
427 time.sleep(self.USB_DETECTION_DELAY)
428 no_usb_set = set(utils.system_output(cmd, ignore_status=True).split())
429
430 # Make the host able to see the USB disk.
431 self.set('usb_mux_sel1', 'servo_sees_usbkey')
432 time.sleep(self.USB_DETECTION_DELAY)
433 has_usb_set = set(utils.system_output(cmd, ignore_status=True).split())
434
435 # Back to its original value.
436 if original_value != 'servo_sees_usbkey':
437 self.set('usb_mux_sel1', original_value)
438 time.sleep(self.USB_DETECTION_DELAY)
439
440 diff_set = has_usb_set - no_usb_set
441 if len(diff_set) == 1:
442 return diff_set.pop()
443 else:
444 return None
445
446
Simran Basi741b5d42012-05-18 11:27:15 -0700447 def install_recovery_image(self, image_path=None,
448 wait_timeout=RECOVERY_INSTALL_DELAY,
449 make_image_noninteractive=False,
450 host=None):
Jon Salzc88e5b62011-11-30 14:38:54 +0800451 """Install the recovery image specied by the path onto the DUT.
452
453 This method uses google recovery mode to install a recovery image
454 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 +0800455 board specified by the usb_dev. If no image path is specified
Jon Salzc88e5b62011-11-30 14:38:54 +0800456 we use the recovery image already on the usb image.
457
458 Args:
459 image_path: Path on the host to the recovery image.
Gilad Arnold9df73de2012-03-14 09:35:08 -0700460 wait_timeout: How long to wait for completion; default is
461 determined by a constant.
Simran Basi741b5d42012-05-18 11:27:15 -0700462 make_image_noninteractive: Make the recovery image noninteractive,
463 therefore the DUT will reboot
464 automatically after installation.
465 host: Host object for the DUT that the installation process is
466 running on. If provided, will wait to see if the host is back
467 up after starting recovery mode.
Jon Salzc88e5b62011-11-30 14:38:54 +0800468 """
Gilad Arnold9df73de2012-03-14 09:35:08 -0700469 # Turn the device off. This should happen before USB key detection, to
470 # prevent a recovery destined DUT from sensing the USB key due to the
471 # autodetection procedure.
J. Richard Barnette524c7fb2012-07-18 16:30:10 -0700472 self.initialize_dut(cold_reset=True)
Gilad Arnold9df73de2012-03-14 09:35:08 -0700473
Jon Salzc88e5b62011-11-30 14:38:54 +0800474 # Set up Servo's usb mux.
475 self.set('prtctl4_pwren', 'on')
476 self.enable_usb_hub(host=True)
Tom Wai-Hong Tama07115e2012-01-09 12:27:01 +0800477 if image_path:
Simran Basi741b5d42012-05-18 11:27:15 -0700478 logging.info('Searching for usb device')
479 if not self._server.download_image_to_usb(image_path):
480 logging.error('Failed to transfer requested image to USB. '
481 'Please take a look at Servo Logs.')
482 raise error.AutotestError('Download image to usb failed.')
483 if make_image_noninteractive:
484 logging.info('Making image noninteractive')
485 if not self._server.make_image_noninteractive():
486 logging.error('Failed to make image noninteractive. '
487 'Please take a look at Servo Logs.')
Jon Salzc88e5b62011-11-30 14:38:54 +0800488
489 # Boot in recovery mode.
490 try:
Jon Salzc88e5b62011-11-30 14:38:54 +0800491 self.enable_recovery_mode()
Tom Wai-Hong Tam23869102012-01-17 15:41:30 +0800492 self.power_short_press()
Jon Salzc88e5b62011-11-30 14:38:54 +0800493 time.sleep(Servo.RECOVERY_BOOT_DELAY)
Tom Wai-Hong Tam922ed052012-01-09 12:27:52 +0800494 self.set('usb_mux_sel1', 'dut_sees_usbkey')
Jon Salzc88e5b62011-11-30 14:38:54 +0800495 self.disable_recovery_mode()
496
Simran Basi741b5d42012-05-18 11:27:15 -0700497 if host:
Jon Salzc88e5b62011-11-30 14:38:54 +0800498 logging.info('Running the recovery process on the DUT. '
Simran Basi741b5d42012-05-18 11:27:15 -0700499 'Will wait up to %d seconds for recovery to '
500 'complete.', wait_timeout)
501 start_time = time.time()
502 # Wait for the host to come up.
503 if host.wait_up(timeout=wait_timeout):
504 logging.info('Recovery process completed successfully in '
505 '%d seconds.', time.time() - start_time)
506 else:
507 logger.error('Host failed to come back up in the allotted '
508 'time: %d seconds.', wait_timeout)
Jon Salzc88e5b62011-11-30 14:38:54 +0800509 logging.info('Removing the usb key from the DUT.')
510 self.disable_usb_hub()
Jon Salzc88e5b62011-11-30 14:38:54 +0800511 except:
512 # In case anything went wrong we want to make sure to do a clean
513 # reset.
514 self.disable_recovery_mode()
515 self.warm_reset()
516 raise
517
518
Todd Brochf24d2782011-08-19 10:55:41 -0700519 def _connect_servod(self, servo_host, servo_port):
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700520 """Connect to the Servod process with XMLRPC.
521
522 Args:
523 servo_port: Port the Servod process is listening on.
524 """
Todd Brochf24d2782011-08-19 10:55:41 -0700525 remote = 'http://%s:%s' % (servo_host, servo_port)
Todd Broch96d83aa2011-08-29 14:37:38 -0700526 self._server = xmlrpclib.ServerProxy(remote)
Todd Brochf24d2782011-08-19 10:55:41 -0700527 try:
528 self._server.echo("ping-test")
Todd Broch96d83aa2011-08-29 14:37:38 -0700529 except:
530 logging.error('Connection to servod failed')
Todd Brochf24d2782011-08-19 10:55:41 -0700531 raise