blob: 5e0e91daa977fe374cea071c5db333a60f04e19c [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 #
26 # TODO(jrbarnette): The EC specification says that 8.0 seconds
27 # should be enough for the long power press. However, on
28 # existing platforms (e.g. Alex), we need a bit more time.
29 # Being generous is the right thing to do for existing platforms,
30 # but if this code is to be used for qualification of new hardware,
31 # we should be less generous.
32 LONG_DELAY = 8.2
Chrome Bot9a1137d2011-07-19 14:35:00 -070033 SHORT_DELAY = 0.1
34 NORMAL_TRANSITION_DELAY = 1.2
Todd Broch31c82502011-08-29 08:14:39 -070035 # Maximum number of times to re-read power button on release.
36 RELEASE_RETRY_MAX = 5
Todd Brochcf7c6652012-02-24 13:03:59 -080037 GET_RETRY_MAX = 10
Chrome Bot9a1137d2011-07-19 14:35:00 -070038
39 # Delays to deal with computer transitions.
40 SLEEP_DELAY = 6
41 BOOT_DELAY = 10
J. Richard Barnette8bd49842012-07-19 14:21:15 -070042 RECOVERY_BOOT_DELAY = 10
J. Richard Barnettec5a77ad2012-04-25 08:19:00 -070043 RECOVERY_INSTALL_DELAY = 540
Chrome Bot9a1137d2011-07-19 14:35:00 -070044
J. Richard Barnetteb6133972012-07-19 17:13:55 -070045 # Time required for the EC to be working after cold reset.
46 # Five seconds is at least twice as big as necessary for Alex,
47 # and is presumably good enough for all future systems.
48 _EC_RESET_DELAY = 5.0
49
Chrome Bot9a1137d2011-07-19 14:35:00 -070050 # Servo-specific delays.
51 MAX_SERVO_STARTUP_DELAY = 10
52 SERVO_SEND_SIGNAL_DELAY = 0.5
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070053
Jon Salzc88e5b62011-11-30 14:38:54 +080054 # Time between an usb disk plugged-in and detected in the system.
55 USB_DETECTION_DELAY = 10
56
Todd Broch9753bd42012-03-21 10:15:08 -070057 KEY_MATRIX = {
58 'm1': {'ctrl_r': ['0', '0'], 'd': ['0', '1'],
59 'enter': ['1', '0'], 'none': ['1', '1']},
60 'm2': {'ctrl': ['0', '0'], 'refresh': ['0', '1'],
61 'unused': ['1', '0'], 'none': ['1', '1']}
62 }
Chris Masone6a0680f2012-03-02 08:40:00 -080063
J. Richard Barnette67ccb872012-04-19 16:34:56 -070064
Chris Masone6a0680f2012-03-02 08:40:00 -080065 @staticmethod
J. Richard Barnette67ccb872012-04-19 16:34:56 -070066 def _make_servo_hostname(hostname):
67 host_parts = hostname.split('.')
68 host_parts[0] = host_parts[0] + '-servo'
69 return '.'.join(host_parts)
Chris Masone6a0680f2012-03-02 08:40:00 -080070
J. Richard Barnette67ccb872012-04-19 16:34:56 -070071 @staticmethod
72 def get_lab_servo(target_hostname):
73 """Instantiate a Servo for |target_hostname| in the lab.
Chris Masone6a0680f2012-03-02 08:40:00 -080074
J. Richard Barnette67ccb872012-04-19 16:34:56 -070075 Assuming that |target_hostname| is a device in the CrOS test
76 lab, create and return a Servo object pointed at the servo
77 attached to that DUT. The servo in the test lab is assumed
78 to already have servod up and running on it.
79
80 @param target_hostname: device whose servo we want to target.
Chris Masone6a0680f2012-03-02 08:40:00 -080081 @return an appropriately configured Servo
82 """
J. Richard Barnette67ccb872012-04-19 16:34:56 -070083 servo_host = Servo._make_servo_hostname(target_hostname)
84 if utils.host_is_in_lab_zone(servo_host):
85 try:
86 return Servo(servo_host=servo_host)
87 except:
88 # TODO(jrbarnette): Long-term, if we can't get to
89 # a servo in the lab, we want to fail, so we should
90 # pass any exceptions along. Short-term, we're not
91 # ready to rely on servo, so we ignore failures.
92 pass
93 return None
Chris Masone6a0680f2012-03-02 08:40:00 -080094
95
J. Richard Barnetteb6133972012-07-19 17:13:55 -070096 def __init__(self, servo_host='localhost', servo_port=9999):
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070097 """Sets up the servo communication infrastructure.
98
J. Richard Barnette55fb8062012-05-23 10:29:31 -070099 @param servo_host Name of the host where the servod process
100 is running.
101 @param servo_port Port the servod process is listening on.
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700102 """
J. Richard Barnette384056b2012-04-16 11:04:46 -0700103 self._server = None
Todd Brochf24d2782011-08-19 10:55:41 -0700104 self._connect_servod(servo_host, servo_port)
Chrome Bot9a1137d2011-07-19 14:35:00 -0700105
106
J. Richard Barnetteb6133972012-07-19 17:13:55 -0700107 def initialize_dut(self, cold_reset=False):
108 """Initializes a dut for testing purposes.
109
110 This sets various servo signals back to default values
111 appropriate for the target board. By default, if the DUT
112 is already on, it stays on. If the DUT is powered off
113 before initialization, its state afterward is unspecified.
114
115 If cold reset is requested, the DUT is guaranteed to be off
116 at the end of initialization, regardless of its initial
117 state.
118
119 Rationale: Basic initialization of servo sets the lid open,
120 when there is a lid. This operation won't affect powered on
121 units; however, setting the lid open may power on a unit
122 that's off, depending on factors outside the scope of this
123 function.
124
125 @param cold_reset If True, cold reset the device after
126 initialization.
127 """
128 self._server.hwinit()
129 if cold_reset:
130 self.cold_reset()
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700131
132
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700133 def power_long_press(self):
Chrome Bot9a1137d2011-07-19 14:35:00 -0700134 """Simulate a long power button press."""
J. Richard Barnettef12bff22012-07-18 14:41:06 -0700135 # After a long power press, the EC may ignore the next power
136 # button press (at least on Alex). To guarantee that this
137 # won't happen, we need to allow the EC one second to
138 # collect itself.
Chrome Bot9a1137d2011-07-19 14:35:00 -0700139 self.power_key(Servo.LONG_DELAY)
J. Richard Barnettef12bff22012-07-18 14:41:06 -0700140 time.sleep(1.0)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700141
142
143 def power_normal_press(self):
Chrome Bot9a1137d2011-07-19 14:35:00 -0700144 """Simulate a normal power button press."""
145 self.power_key()
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700146
147
148 def power_short_press(self):
Chrome Bot9a1137d2011-07-19 14:35:00 -0700149 """Simulate a short power button press."""
150 self.power_key(Servo.SHORT_DELAY)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700151
152
Chrome Bot9a1137d2011-07-19 14:35:00 -0700153 def power_key(self, secs=NORMAL_TRANSITION_DELAY):
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700154 """Simulate a power button press.
155
156 Args:
157 secs: Time in seconds to simulate the keypress.
158 """
Craig Harrison6b36b122011-06-28 17:58:43 -0700159 self.set_nocheck('pwr_button', 'press')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700160 time.sleep(secs)
Todd Broch31c82502011-08-29 08:14:39 -0700161 self.set_nocheck('pwr_button', 'release')
162 # TODO(tbroch) Different systems have different release times on the
163 # power button that this loop addresses. Longer term we may want to
164 # make this delay platform specific.
165 retry = 1
166 while True:
167 value = self.get('pwr_button')
168 if value == 'release' or retry > Servo.RELEASE_RETRY_MAX:
169 break
Todd Broch9753bd42012-03-21 10:15:08 -0700170 logging.info('Waiting for pwr_button to release, retry %d.', retry)
Todd Broch31c82502011-08-29 08:14:39 -0700171 retry += 1
172 time.sleep(Servo.SHORT_DELAY)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700173
174
175 def lid_open(self):
176 """Simulate opening the lid."""
Craig Harrison48997262011-06-27 14:31:10 -0700177 self.set_nocheck('lid_open', 'yes')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700178
179
180 def lid_close(self):
Craig Harrison48997262011-06-27 14:31:10 -0700181 """Simulate closing the lid.
182
183 Waits 6 seconds to ensure the device is fully asleep before returning.
184 """
185 self.set_nocheck('lid_open', 'no')
Chrome Bot9a1137d2011-07-19 14:35:00 -0700186 time.sleep(Servo.SLEEP_DELAY)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700187
188
Todd Broch9753bd42012-03-21 10:15:08 -0700189 def _press_and_release_keys(self, m1, m2,
190 press_secs=SERVO_SEND_SIGNAL_DELAY):
Todd Broch9dfc3a82011-11-01 08:09:28 -0700191 """Simulate button presses."""
Todd Broch9753bd42012-03-21 10:15:08 -0700192 # set keys to none
193 (m2_a1, m2_a0) = self.KEY_MATRIX['m2']['none']
194 (m1_a1, m1_a0) = self.KEY_MATRIX['m1']['none']
195 self.set_nocheck('kbd_m2_a0', m2_a0)
196 self.set_nocheck('kbd_m2_a1', m2_a1)
197 self.set_nocheck('kbd_m1_a0', m1_a0)
198 self.set_nocheck('kbd_m1_a1', m1_a1)
Todd Broch9dfc3a82011-11-01 08:09:28 -0700199
Todd Broch9753bd42012-03-21 10:15:08 -0700200 (m2_a1, m2_a0) = self.KEY_MATRIX['m2'][m2]
201 (m1_a1, m1_a0) = self.KEY_MATRIX['m1'][m1]
Todd Broch9dfc3a82011-11-01 08:09:28 -0700202 self.set_nocheck('kbd_en', 'on')
Todd Broch9753bd42012-03-21 10:15:08 -0700203 self.set_nocheck('kbd_m2_a0', m2_a0)
204 self.set_nocheck('kbd_m2_a1', m2_a1)
205 self.set_nocheck('kbd_m1_a0', m1_a0)
206 self.set_nocheck('kbd_m1_a1', m1_a1)
Todd Broch9dfc3a82011-11-01 08:09:28 -0700207 time.sleep(press_secs)
208 self.set_nocheck('kbd_en', 'off')
209
210
Chrome Bot9a1137d2011-07-19 14:35:00 -0700211 def ctrl_d(self):
212 """Simulate Ctrl-d simultaneous button presses."""
Todd Broch9dfc3a82011-11-01 08:09:28 -0700213 self._press_and_release_keys('d', 'ctrl')
214
215
Todd Broch9753bd42012-03-21 10:15:08 -0700216 def ctrl_enter(self):
217 """Simulate Ctrl-enter simultaneous button presses."""
218 self._press_and_release_keys('enter', 'ctrl')
219
220
Todd Broch9dfc3a82011-11-01 08:09:28 -0700221 def d_key(self):
222 """Simulate Enter key button press."""
223 self._press_and_release_keys('d', 'none')
224
225
226 def ctrl_key(self):
227 """Simulate Enter key button press."""
228 self._press_and_release_keys('none', 'ctrl')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700229
230
Chrome Bot9a1137d2011-07-19 14:35:00 -0700231 def enter_key(self):
232 """Simulate Enter key button press."""
Todd Broch9dfc3a82011-11-01 08:09:28 -0700233 self._press_and_release_keys('enter', 'none')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700234
235
Chrome Bot9a1137d2011-07-19 14:35:00 -0700236 def refresh_key(self):
237 """Simulate Refresh key (F3) button press."""
Todd Broch9dfc3a82011-11-01 08:09:28 -0700238 self._press_and_release_keys('none', 'refresh')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700239
240
Chrome Bot9a1137d2011-07-19 14:35:00 -0700241 def imaginary_key(self):
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700242 """Simulate imaginary key button press.
243
244 Maps to a key that doesn't physically exist.
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700245 """
Todd Broch9dfc3a82011-11-01 08:09:28 -0700246 self._press_and_release_keys('none', 'unused')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700247
248
Craig Harrison6b36b122011-06-28 17:58:43 -0700249 def enable_recovery_mode(self):
250 """Enable recovery mode on device."""
251 self.set('rec_mode', 'on')
252
253
254 def disable_recovery_mode(self):
255 """Disable recovery mode on device."""
256 self.set('rec_mode', 'off')
257
258
259 def enable_development_mode(self):
260 """Enable development mode on device."""
261 self.set('dev_mode', 'on')
262
263
264 def disable_development_mode(self):
265 """Disable development mode on device."""
266 self.set('dev_mode', 'off')
267
Chris Sosa8ee1d592011-08-14 16:50:31 -0700268 def enable_usb_hub(self, host=False):
Craig Harrison86b1a572011-08-12 11:26:52 -0700269 """Enable Servo's USB/ethernet hub.
270
Chris Sosa8ee1d592011-08-14 16:50:31 -0700271 This is equivalent to plugging in the USB devices attached to Servo to
272 the host (if |host| is True) or dut (if |host| is False).
273 For host=False, requires that the USB out on the servo board is
274 connected to a USB in port on the target device. Servo's USB ports are
275 labeled DUT_HUB_USB1 and DUT_HUB_USB2. Servo's ethernet port is also
276 connected to this hub. Servo's USB port DUT_HUB_IN is the output of the
277 hub.
Craig Harrison86b1a572011-08-12 11:26:52 -0700278 """
279 self.set('dut_hub_pwren', 'on')
Chris Sosa8ee1d592011-08-14 16:50:31 -0700280 if host:
Todd Broch9753bd42012-03-21 10:15:08 -0700281 self.set('usb_mux_oe1', 'on')
282 self.set('usb_mux_sel1', 'servo_sees_usbkey')
Chris Sosa8ee1d592011-08-14 16:50:31 -0700283 else:
Todd Broch9753bd42012-03-21 10:15:08 -0700284 self.set('dut_hub_sel', 'dut_sees_hub')
Chris Sosa8ee1d592011-08-14 16:50:31 -0700285
Craig Harrison86b1a572011-08-12 11:26:52 -0700286 self.set('dut_hub_on', 'yes')
287
288
289 def disable_usb_hub(self):
290 """Disable Servo's USB/ethernet hub.
291
292 This is equivalent to unplugging the USB devices attached to Servo.
293 """
294 self.set('dut_hub_on', 'no')
295
296
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700297 def boot_devmode(self):
298 """Boot a dev-mode device that is powered off."""
Tom Wai-Hong Tam23869102012-01-17 15:41:30 +0800299 self.power_short_press()
Craig Harrison48997262011-06-27 14:31:10 -0700300 self.pass_devmode()
301
302
303 def pass_devmode(self):
304 """Pass through boot screens in dev-mode."""
Chrome Bot9a1137d2011-07-19 14:35:00 -0700305 time.sleep(Servo.BOOT_DELAY)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700306 self.ctrl_d()
Chrome Bot9a1137d2011-07-19 14:35:00 -0700307 time.sleep(Servo.BOOT_DELAY)
Craig Harrison48997262011-06-27 14:31:10 -0700308
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700309
Craig Harrison6b36b122011-06-28 17:58:43 -0700310 def cold_reset(self):
311 """Perform a cold reset of the EC.
312
J. Richard Barnetteb6133972012-07-19 17:13:55 -0700313 This has the side effect of shutting off the device. The
314 device is guaranteed to be off at the end of this call.
Craig Harrison6b36b122011-06-28 17:58:43 -0700315 """
J. Richard Barnetteb6133972012-07-19 17:13:55 -0700316 # After the reset, give the EC the time it needs to
317 # re-initialize.
Craig Harrison6b36b122011-06-28 17:58:43 -0700318 self.set('cold_reset', 'on')
Chrome Bot9a1137d2011-07-19 14:35:00 -0700319 time.sleep(Servo.SERVO_SEND_SIGNAL_DELAY)
J. Richard Barnetteb6133972012-07-19 17:13:55 -0700320 self.set('cold_reset', 'off')
321 time.sleep(self._EC_RESET_DELAY)
Craig Harrison6b36b122011-06-28 17:58:43 -0700322
323
324 def warm_reset(self):
325 """Perform a warm reset of the device.
326
327 Has the side effect of restarting the device.
328 """
329 self.set('warm_reset', 'on')
Chrome Bot9a1137d2011-07-19 14:35:00 -0700330 time.sleep(Servo.SERVO_SEND_SIGNAL_DELAY)
Craig Harrison6b36b122011-06-28 17:58:43 -0700331 self.set('warm_reset', 'off')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700332
333
Todd Brochefe72cb2012-07-11 19:58:53 -0700334 def _get_xmlrpclib_exception(self, xmlexc):
335 """Get meaningful exception string from xmlrpc.
336
337 Args:
338 xmlexc: xmlrpclib.Fault object
339
340 xmlrpclib.Fault.faultString has the following format:
341
342 <type 'exception type'>:'actual error message'
343
344 Parse and return the real exception from the servod side instead of the
345 less meaningful one like,
346 <Fault 1: "<type 'exceptions.AttributeError'>:'tca6416' object has no
347 attribute 'hw_driver'">
348
349 Returns:
350 string of underlying exception raised in servod.
351 """
352 return re.sub('^.*>:', '', xmlexc.faultString)
353
354
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700355 def get(self, gpio_name):
356 """Get the value of a gpio from Servod."""
357 assert gpio_name
Todd Brochefe72cb2012-07-11 19:58:53 -0700358 try:
359 return self._server.get(gpio_name)
360 except xmlrpclib.Fault as e:
361 err_msg = "Getting '%s' :: %s" % \
362 (gpio_name, self._get_xmlrpclib_exception(e))
363 raise error.TestFail(err_msg)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700364
365
366 def set(self, gpio_name, gpio_value):
367 """Set and check the value of a gpio using Servod."""
Chrome Bot9a1137d2011-07-19 14:35:00 -0700368 self.set_nocheck(gpio_name, gpio_value)
Todd Brochcf7c6652012-02-24 13:03:59 -0800369 retry_count = Servo.GET_RETRY_MAX
370 while gpio_value != self.get(gpio_name) and retry_count:
371 logging.warn("%s != %s, retry %d", gpio_name, gpio_value,
372 retry_count)
373 retry_count -= 1
374 time.sleep(Servo.SHORT_DELAY)
375 if not retry_count:
376 assert gpio_value == self.get(gpio_name), \
377 'Servo failed to set %s to %s' % (gpio_name, gpio_value)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700378
379
380 def set_nocheck(self, gpio_name, gpio_value):
381 """Set the value of a gpio using Servod."""
382 assert gpio_name and gpio_value
Todd Broch9753bd42012-03-21 10:15:08 -0700383 logging.info('Setting %s to %s', gpio_name, gpio_value)
Todd Brochefe72cb2012-07-11 19:58:53 -0700384 try:
385 self._server.set(gpio_name, gpio_value)
386 except xmlrpclib.Fault as e:
387 err_msg = "Setting '%s' to '%s' :: %s" % \
388 (gpio_name, gpio_value, self._get_xmlrpclib_exception(e))
389 raise error.TestFail(err_msg)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700390
391
Jon Salzc88e5b62011-11-30 14:38:54 +0800392 # TODO(waihong) It may fail if multiple servo's are connected to the same
393 # host. Should look for a better way, like the USB serial name, to identify
394 # the USB device.
Simran Basi741b5d42012-05-18 11:27:15 -0700395 # TODO(sbasi) Remove this code from autoserv once firmware tests have been
396 # updated.
Jon Salzc88e5b62011-11-30 14:38:54 +0800397 def probe_host_usb_dev(self):
398 """Probe the USB disk device plugged-in the servo from the host side.
399
400 It tries to switch the USB mux to make the host unable to see the
401 USB disk and compares the result difference.
402
403 This only works if the servo is attached to the local host.
404
405 Returns:
406 A string of USB disk path, like '/dev/sdb', or None if not existed.
407 """
408 cmd = 'ls /dev/sd[a-z]'
409 original_value = self.get('usb_mux_sel1')
410
411 # Make the host unable to see the USB disk.
412 if original_value != 'dut_sees_usbkey':
413 self.set('usb_mux_sel1', 'dut_sees_usbkey')
414 time.sleep(self.USB_DETECTION_DELAY)
415 no_usb_set = set(utils.system_output(cmd, ignore_status=True).split())
416
417 # Make the host able to see the USB disk.
418 self.set('usb_mux_sel1', 'servo_sees_usbkey')
419 time.sleep(self.USB_DETECTION_DELAY)
420 has_usb_set = set(utils.system_output(cmd, ignore_status=True).split())
421
422 # Back to its original value.
423 if original_value != 'servo_sees_usbkey':
424 self.set('usb_mux_sel1', original_value)
425 time.sleep(self.USB_DETECTION_DELAY)
426
427 diff_set = has_usb_set - no_usb_set
428 if len(diff_set) == 1:
429 return diff_set.pop()
430 else:
431 return None
432
433
Simran Basi741b5d42012-05-18 11:27:15 -0700434 def install_recovery_image(self, image_path=None,
435 wait_timeout=RECOVERY_INSTALL_DELAY,
436 make_image_noninteractive=False,
437 host=None):
Jon Salzc88e5b62011-11-30 14:38:54 +0800438 """Install the recovery image specied by the path onto the DUT.
439
440 This method uses google recovery mode to install a recovery image
441 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 +0800442 board specified by the usb_dev. If no image path is specified
Jon Salzc88e5b62011-11-30 14:38:54 +0800443 we use the recovery image already on the usb image.
444
445 Args:
446 image_path: Path on the host to the recovery image.
Gilad Arnold9df73de2012-03-14 09:35:08 -0700447 wait_timeout: How long to wait for completion; default is
448 determined by a constant.
Simran Basi741b5d42012-05-18 11:27:15 -0700449 make_image_noninteractive: Make the recovery image noninteractive,
450 therefore the DUT will reboot
451 automatically after installation.
452 host: Host object for the DUT that the installation process is
453 running on. If provided, will wait to see if the host is back
454 up after starting recovery mode.
Jon Salzc88e5b62011-11-30 14:38:54 +0800455 """
Gilad Arnold9df73de2012-03-14 09:35:08 -0700456 # Turn the device off. This should happen before USB key detection, to
457 # prevent a recovery destined DUT from sensing the USB key due to the
458 # autodetection procedure.
459 self.power_long_press()
460
Jon Salzc88e5b62011-11-30 14:38:54 +0800461 # Set up Servo's usb mux.
462 self.set('prtctl4_pwren', 'on')
463 self.enable_usb_hub(host=True)
Tom Wai-Hong Tama07115e2012-01-09 12:27:01 +0800464 if image_path:
Simran Basi741b5d42012-05-18 11:27:15 -0700465 logging.info('Searching for usb device')
466 if not self._server.download_image_to_usb(image_path):
467 logging.error('Failed to transfer requested image to USB. '
468 'Please take a look at Servo Logs.')
469 raise error.AutotestError('Download image to usb failed.')
470 if make_image_noninteractive:
471 logging.info('Making image noninteractive')
472 if not self._server.make_image_noninteractive():
473 logging.error('Failed to make image noninteractive. '
474 'Please take a look at Servo Logs.')
Jon Salzc88e5b62011-11-30 14:38:54 +0800475
476 # Boot in recovery mode.
477 try:
Jon Salzc88e5b62011-11-30 14:38:54 +0800478 self.enable_recovery_mode()
Tom Wai-Hong Tam23869102012-01-17 15:41:30 +0800479 self.power_short_press()
Jon Salzc88e5b62011-11-30 14:38:54 +0800480 time.sleep(Servo.RECOVERY_BOOT_DELAY)
Tom Wai-Hong Tam922ed052012-01-09 12:27:52 +0800481 self.set('usb_mux_sel1', 'dut_sees_usbkey')
Jon Salzc88e5b62011-11-30 14:38:54 +0800482 self.disable_recovery_mode()
483
Simran Basi741b5d42012-05-18 11:27:15 -0700484 if host:
Jon Salzc88e5b62011-11-30 14:38:54 +0800485 logging.info('Running the recovery process on the DUT. '
Simran Basi741b5d42012-05-18 11:27:15 -0700486 'Will wait up to %d seconds for recovery to '
487 'complete.', wait_timeout)
488 start_time = time.time()
489 # Wait for the host to come up.
490 if host.wait_up(timeout=wait_timeout):
491 logging.info('Recovery process completed successfully in '
492 '%d seconds.', time.time() - start_time)
493 else:
494 logger.error('Host failed to come back up in the allotted '
495 'time: %d seconds.', wait_timeout)
Jon Salzc88e5b62011-11-30 14:38:54 +0800496 logging.info('Removing the usb key from the DUT.')
497 self.disable_usb_hub()
Jon Salzc88e5b62011-11-30 14:38:54 +0800498 except:
499 # In case anything went wrong we want to make sure to do a clean
500 # reset.
501 self.disable_recovery_mode()
502 self.warm_reset()
503 raise
504
505
Todd Brochf24d2782011-08-19 10:55:41 -0700506 def _connect_servod(self, servo_host, servo_port):
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700507 """Connect to the Servod process with XMLRPC.
508
509 Args:
510 servo_port: Port the Servod process is listening on.
511 """
Todd Brochf24d2782011-08-19 10:55:41 -0700512 remote = 'http://%s:%s' % (servo_host, servo_port)
Todd Broch96d83aa2011-08-29 14:37:38 -0700513 self._server = xmlrpclib.ServerProxy(remote)
Todd Brochf24d2782011-08-19 10:55:41 -0700514 try:
515 self._server.echo("ping-test")
Todd Broch96d83aa2011-08-29 14:37:38 -0700516 except:
517 logging.error('Connection to servod failed')
Todd Brochf24d2782011-08-19 10:55:41 -0700518 raise