blob: fc33d5ca04ad0f55aeafcda302ab358448ad41e0 [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
Vic Yang4a1ef382012-08-21 17:03:19 +080058 SERVO_KEY_PRESS_DELAY = 0.1
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070059
Jon Salzc88e5b62011-11-30 14:38:54 +080060 # Time between an usb disk plugged-in and detected in the system.
61 USB_DETECTION_DELAY = 10
62
Todd Broch9753bd42012-03-21 10:15:08 -070063 KEY_MATRIX = {
64 'm1': {'ctrl_r': ['0', '0'], 'd': ['0', '1'],
65 'enter': ['1', '0'], 'none': ['1', '1']},
66 'm2': {'ctrl': ['0', '0'], 'refresh': ['0', '1'],
67 'unused': ['1', '0'], 'none': ['1', '1']}
68 }
Chris Masone6a0680f2012-03-02 08:40:00 -080069
J. Richard Barnette67ccb872012-04-19 16:34:56 -070070
Chris Masone6a0680f2012-03-02 08:40:00 -080071 @staticmethod
J. Richard Barnette67ccb872012-04-19 16:34:56 -070072 def _make_servo_hostname(hostname):
73 host_parts = hostname.split('.')
74 host_parts[0] = host_parts[0] + '-servo'
75 return '.'.join(host_parts)
Chris Masone6a0680f2012-03-02 08:40:00 -080076
J. Richard Barnette67ccb872012-04-19 16:34:56 -070077 @staticmethod
78 def get_lab_servo(target_hostname):
79 """Instantiate a Servo for |target_hostname| in the lab.
Chris Masone6a0680f2012-03-02 08:40:00 -080080
J. Richard Barnette67ccb872012-04-19 16:34:56 -070081 Assuming that |target_hostname| is a device in the CrOS test
82 lab, create and return a Servo object pointed at the servo
83 attached to that DUT. The servo in the test lab is assumed
84 to already have servod up and running on it.
85
86 @param target_hostname: device whose servo we want to target.
Chris Masone6a0680f2012-03-02 08:40:00 -080087 @return an appropriately configured Servo
88 """
J. Richard Barnette67ccb872012-04-19 16:34:56 -070089 servo_host = Servo._make_servo_hostname(target_hostname)
90 if utils.host_is_in_lab_zone(servo_host):
91 try:
92 return Servo(servo_host=servo_host)
93 except:
94 # TODO(jrbarnette): Long-term, if we can't get to
95 # a servo in the lab, we want to fail, so we should
96 # pass any exceptions along. Short-term, we're not
97 # ready to rely on servo, so we ignore failures.
98 pass
99 return None
Chris Masone6a0680f2012-03-02 08:40:00 -0800100
101
J. Richard Barnetteb6133972012-07-19 17:13:55 -0700102 def __init__(self, servo_host='localhost', servo_port=9999):
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700103 """Sets up the servo communication infrastructure.
104
J. Richard Barnette55fb8062012-05-23 10:29:31 -0700105 @param servo_host Name of the host where the servod process
106 is running.
107 @param servo_port Port the servod process is listening on.
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700108 """
J. Richard Barnette384056b2012-04-16 11:04:46 -0700109 self._server = None
Todd Brochf24d2782011-08-19 10:55:41 -0700110 self._connect_servod(servo_host, servo_port)
Chrome Bot9a1137d2011-07-19 14:35:00 -0700111
112
J. Richard Barnetteb6133972012-07-19 17:13:55 -0700113 def initialize_dut(self, cold_reset=False):
114 """Initializes a dut for testing purposes.
115
116 This sets various servo signals back to default values
117 appropriate for the target board. By default, if the DUT
118 is already on, it stays on. If the DUT is powered off
119 before initialization, its state afterward is unspecified.
120
121 If cold reset is requested, the DUT is guaranteed to be off
122 at the end of initialization, regardless of its initial
123 state.
124
125 Rationale: Basic initialization of servo sets the lid open,
126 when there is a lid. This operation won't affect powered on
127 units; however, setting the lid open may power on a unit
128 that's off, depending on factors outside the scope of this
129 function.
130
131 @param cold_reset If True, cold reset the device after
132 initialization.
133 """
134 self._server.hwinit()
135 if cold_reset:
136 self.cold_reset()
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700137
138
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700139 def power_long_press(self):
Chrome Bot9a1137d2011-07-19 14:35:00 -0700140 """Simulate a long power button press."""
J. Richard Barnettef12bff22012-07-18 14:41:06 -0700141 # After a long power press, the EC may ignore the next power
142 # button press (at least on Alex). To guarantee that this
143 # won't happen, we need to allow the EC one second to
144 # collect itself.
Chrome Bot9a1137d2011-07-19 14:35:00 -0700145 self.power_key(Servo.LONG_DELAY)
J. Richard Barnettef12bff22012-07-18 14:41:06 -0700146 time.sleep(1.0)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700147
148
149 def power_normal_press(self):
Chrome Bot9a1137d2011-07-19 14:35:00 -0700150 """Simulate a normal power button press."""
151 self.power_key()
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700152
153
154 def power_short_press(self):
Chrome Bot9a1137d2011-07-19 14:35:00 -0700155 """Simulate a short power button press."""
156 self.power_key(Servo.SHORT_DELAY)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700157
158
Chrome Bot9a1137d2011-07-19 14:35:00 -0700159 def power_key(self, secs=NORMAL_TRANSITION_DELAY):
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700160 """Simulate a power button press.
161
162 Args:
163 secs: Time in seconds to simulate the keypress.
164 """
Craig Harrison6b36b122011-06-28 17:58:43 -0700165 self.set_nocheck('pwr_button', 'press')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700166 time.sleep(secs)
Todd Broch31c82502011-08-29 08:14:39 -0700167 self.set_nocheck('pwr_button', 'release')
168 # TODO(tbroch) Different systems have different release times on the
169 # power button that this loop addresses. Longer term we may want to
170 # make this delay platform specific.
171 retry = 1
172 while True:
173 value = self.get('pwr_button')
174 if value == 'release' or retry > Servo.RELEASE_RETRY_MAX:
175 break
Todd Broch9753bd42012-03-21 10:15:08 -0700176 logging.info('Waiting for pwr_button to release, retry %d.', retry)
Todd Broch31c82502011-08-29 08:14:39 -0700177 retry += 1
178 time.sleep(Servo.SHORT_DELAY)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700179
180
181 def lid_open(self):
182 """Simulate opening the lid."""
Craig Harrison48997262011-06-27 14:31:10 -0700183 self.set_nocheck('lid_open', 'yes')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700184
185
186 def lid_close(self):
Craig Harrison48997262011-06-27 14:31:10 -0700187 """Simulate closing the lid.
188
189 Waits 6 seconds to ensure the device is fully asleep before returning.
190 """
191 self.set_nocheck('lid_open', 'no')
Chrome Bot9a1137d2011-07-19 14:35:00 -0700192 time.sleep(Servo.SLEEP_DELAY)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700193
194
Todd Broch9753bd42012-03-21 10:15:08 -0700195 def _press_and_release_keys(self, m1, m2,
Vic Yang4a1ef382012-08-21 17:03:19 +0800196 press_secs=SERVO_KEY_PRESS_DELAY):
Todd Broch9dfc3a82011-11-01 08:09:28 -0700197 """Simulate button presses."""
Todd Broch9753bd42012-03-21 10:15:08 -0700198 # set keys to none
199 (m2_a1, m2_a0) = self.KEY_MATRIX['m2']['none']
200 (m1_a1, m1_a0) = self.KEY_MATRIX['m1']['none']
201 self.set_nocheck('kbd_m2_a0', m2_a0)
202 self.set_nocheck('kbd_m2_a1', m2_a1)
203 self.set_nocheck('kbd_m1_a0', m1_a0)
204 self.set_nocheck('kbd_m1_a1', m1_a1)
Todd Broch9dfc3a82011-11-01 08:09:28 -0700205
Todd Broch9753bd42012-03-21 10:15:08 -0700206 (m2_a1, m2_a0) = self.KEY_MATRIX['m2'][m2]
207 (m1_a1, m1_a0) = self.KEY_MATRIX['m1'][m1]
Todd Broch9dfc3a82011-11-01 08:09:28 -0700208 self.set_nocheck('kbd_en', 'on')
Todd Broch9753bd42012-03-21 10:15:08 -0700209 self.set_nocheck('kbd_m2_a0', m2_a0)
210 self.set_nocheck('kbd_m2_a1', m2_a1)
211 self.set_nocheck('kbd_m1_a0', m1_a0)
212 self.set_nocheck('kbd_m1_a1', m1_a1)
Todd Broch9dfc3a82011-11-01 08:09:28 -0700213 time.sleep(press_secs)
214 self.set_nocheck('kbd_en', 'off')
215
216
Chrome Bot9a1137d2011-07-19 14:35:00 -0700217 def ctrl_d(self):
218 """Simulate Ctrl-d simultaneous button presses."""
Todd Broch9dfc3a82011-11-01 08:09:28 -0700219 self._press_and_release_keys('d', 'ctrl')
220
221
Todd Broch9753bd42012-03-21 10:15:08 -0700222 def ctrl_enter(self):
223 """Simulate Ctrl-enter simultaneous button presses."""
224 self._press_and_release_keys('enter', 'ctrl')
225
226
Todd Broch9dfc3a82011-11-01 08:09:28 -0700227 def d_key(self):
228 """Simulate Enter key button press."""
229 self._press_and_release_keys('d', 'none')
230
231
232 def ctrl_key(self):
233 """Simulate Enter key button press."""
234 self._press_and_release_keys('none', 'ctrl')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700235
236
Chrome Bot9a1137d2011-07-19 14:35:00 -0700237 def enter_key(self):
238 """Simulate Enter key button press."""
Todd Broch9dfc3a82011-11-01 08:09:28 -0700239 self._press_and_release_keys('enter', 'none')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700240
241
Chrome Bot9a1137d2011-07-19 14:35:00 -0700242 def refresh_key(self):
243 """Simulate Refresh key (F3) button press."""
Todd Broch9dfc3a82011-11-01 08:09:28 -0700244 self._press_and_release_keys('none', 'refresh')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700245
246
Tom Wai-Hong Tam9e61e662012-08-01 15:10:07 +0800247 def ctrl_refresh_key(self):
248 """Simulate Ctrl and Refresh (F3) simultaneous press.
249
250 This key combination is an alternative of Space key.
251 """
252 self._press_and_release_keys('ctrl_r', 'refresh')
253
254
Chrome Bot9a1137d2011-07-19 14:35:00 -0700255 def imaginary_key(self):
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700256 """Simulate imaginary key button press.
257
258 Maps to a key that doesn't physically exist.
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700259 """
Todd Broch9dfc3a82011-11-01 08:09:28 -0700260 self._press_and_release_keys('none', 'unused')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700261
262
Craig Harrison6b36b122011-06-28 17:58:43 -0700263 def enable_recovery_mode(self):
264 """Enable recovery mode on device."""
265 self.set('rec_mode', 'on')
266
267
268 def disable_recovery_mode(self):
269 """Disable recovery mode on device."""
270 self.set('rec_mode', 'off')
271
272
273 def enable_development_mode(self):
274 """Enable development mode on device."""
275 self.set('dev_mode', 'on')
276
277
278 def disable_development_mode(self):
279 """Disable development mode on device."""
280 self.set('dev_mode', 'off')
281
Chris Sosa8ee1d592011-08-14 16:50:31 -0700282 def enable_usb_hub(self, host=False):
Craig Harrison86b1a572011-08-12 11:26:52 -0700283 """Enable Servo's USB/ethernet hub.
284
Chris Sosa8ee1d592011-08-14 16:50:31 -0700285 This is equivalent to plugging in the USB devices attached to Servo to
286 the host (if |host| is True) or dut (if |host| is False).
287 For host=False, requires that the USB out on the servo board is
288 connected to a USB in port on the target device. Servo's USB ports are
289 labeled DUT_HUB_USB1 and DUT_HUB_USB2. Servo's ethernet port is also
290 connected to this hub. Servo's USB port DUT_HUB_IN is the output of the
291 hub.
Craig Harrison86b1a572011-08-12 11:26:52 -0700292 """
293 self.set('dut_hub_pwren', 'on')
Chris Sosa8ee1d592011-08-14 16:50:31 -0700294 if host:
Todd Broch9753bd42012-03-21 10:15:08 -0700295 self.set('usb_mux_oe1', 'on')
296 self.set('usb_mux_sel1', 'servo_sees_usbkey')
Chris Sosa8ee1d592011-08-14 16:50:31 -0700297 else:
Todd Broch9753bd42012-03-21 10:15:08 -0700298 self.set('dut_hub_sel', 'dut_sees_hub')
Chris Sosa8ee1d592011-08-14 16:50:31 -0700299
Craig Harrison86b1a572011-08-12 11:26:52 -0700300 self.set('dut_hub_on', 'yes')
301
302
303 def disable_usb_hub(self):
304 """Disable Servo's USB/ethernet hub.
305
306 This is equivalent to unplugging the USB devices attached to Servo.
307 """
308 self.set('dut_hub_on', 'no')
309
310
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700311 def boot_devmode(self):
312 """Boot a dev-mode device that is powered off."""
Tom Wai-Hong Tam23869102012-01-17 15:41:30 +0800313 self.power_short_press()
Craig Harrison48997262011-06-27 14:31:10 -0700314 self.pass_devmode()
315
316
317 def pass_devmode(self):
318 """Pass through boot screens in dev-mode."""
Chrome Bot9a1137d2011-07-19 14:35:00 -0700319 time.sleep(Servo.BOOT_DELAY)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700320 self.ctrl_d()
Chrome Bot9a1137d2011-07-19 14:35:00 -0700321 time.sleep(Servo.BOOT_DELAY)
Craig Harrison48997262011-06-27 14:31:10 -0700322
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700323
Craig Harrison6b36b122011-06-28 17:58:43 -0700324 def cold_reset(self):
325 """Perform a cold reset of the EC.
326
J. Richard Barnetteb6133972012-07-19 17:13:55 -0700327 This has the side effect of shutting off the device. The
328 device is guaranteed to be off at the end of this call.
Craig Harrison6b36b122011-06-28 17:58:43 -0700329 """
J. Richard Barnetteb6133972012-07-19 17:13:55 -0700330 # After the reset, give the EC the time it needs to
331 # re-initialize.
Craig Harrison6b36b122011-06-28 17:58:43 -0700332 self.set('cold_reset', 'on')
Chrome Bot9a1137d2011-07-19 14:35:00 -0700333 time.sleep(Servo.SERVO_SEND_SIGNAL_DELAY)
J. Richard Barnetteb6133972012-07-19 17:13:55 -0700334 self.set('cold_reset', 'off')
335 time.sleep(self._EC_RESET_DELAY)
Craig Harrison6b36b122011-06-28 17:58:43 -0700336
337
338 def warm_reset(self):
339 """Perform a warm reset of the device.
340
341 Has the side effect of restarting the device.
342 """
343 self.set('warm_reset', 'on')
Chrome Bot9a1137d2011-07-19 14:35:00 -0700344 time.sleep(Servo.SERVO_SEND_SIGNAL_DELAY)
Craig Harrison6b36b122011-06-28 17:58:43 -0700345 self.set('warm_reset', 'off')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700346
347
Todd Brochefe72cb2012-07-11 19:58:53 -0700348 def _get_xmlrpclib_exception(self, xmlexc):
349 """Get meaningful exception string from xmlrpc.
350
351 Args:
352 xmlexc: xmlrpclib.Fault object
353
354 xmlrpclib.Fault.faultString has the following format:
355
356 <type 'exception type'>:'actual error message'
357
358 Parse and return the real exception from the servod side instead of the
359 less meaningful one like,
360 <Fault 1: "<type 'exceptions.AttributeError'>:'tca6416' object has no
361 attribute 'hw_driver'">
362
363 Returns:
364 string of underlying exception raised in servod.
365 """
366 return re.sub('^.*>:', '', xmlexc.faultString)
367
368
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700369 def get(self, gpio_name):
370 """Get the value of a gpio from Servod."""
371 assert gpio_name
Todd Brochefe72cb2012-07-11 19:58:53 -0700372 try:
373 return self._server.get(gpio_name)
374 except xmlrpclib.Fault as e:
375 err_msg = "Getting '%s' :: %s" % \
376 (gpio_name, self._get_xmlrpclib_exception(e))
377 raise error.TestFail(err_msg)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700378
379
380 def set(self, gpio_name, gpio_value):
381 """Set and check the value of a gpio using Servod."""
Chrome Bot9a1137d2011-07-19 14:35:00 -0700382 self.set_nocheck(gpio_name, gpio_value)
Todd Brochcf7c6652012-02-24 13:03:59 -0800383 retry_count = Servo.GET_RETRY_MAX
384 while gpio_value != self.get(gpio_name) and retry_count:
385 logging.warn("%s != %s, retry %d", gpio_name, gpio_value,
386 retry_count)
387 retry_count -= 1
388 time.sleep(Servo.SHORT_DELAY)
389 if not retry_count:
390 assert gpio_value == self.get(gpio_name), \
391 'Servo failed to set %s to %s' % (gpio_name, gpio_value)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700392
393
394 def set_nocheck(self, gpio_name, gpio_value):
395 """Set the value of a gpio using Servod."""
396 assert gpio_name and gpio_value
Todd Broch9753bd42012-03-21 10:15:08 -0700397 logging.info('Setting %s to %s', gpio_name, gpio_value)
Todd Brochefe72cb2012-07-11 19:58:53 -0700398 try:
399 self._server.set(gpio_name, gpio_value)
400 except xmlrpclib.Fault as e:
401 err_msg = "Setting '%s' to '%s' :: %s" % \
402 (gpio_name, gpio_value, self._get_xmlrpclib_exception(e))
403 raise error.TestFail(err_msg)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700404
405
Jon Salzc88e5b62011-11-30 14:38:54 +0800406 # TODO(waihong) It may fail if multiple servo's are connected to the same
407 # host. Should look for a better way, like the USB serial name, to identify
408 # the USB device.
Simran Basi741b5d42012-05-18 11:27:15 -0700409 # TODO(sbasi) Remove this code from autoserv once firmware tests have been
410 # updated.
Jon Salzc88e5b62011-11-30 14:38:54 +0800411 def probe_host_usb_dev(self):
412 """Probe the USB disk device plugged-in the servo from the host side.
413
414 It tries to switch the USB mux to make the host unable to see the
415 USB disk and compares the result difference.
416
417 This only works if the servo is attached to the local host.
418
419 Returns:
420 A string of USB disk path, like '/dev/sdb', or None if not existed.
421 """
422 cmd = 'ls /dev/sd[a-z]'
423 original_value = self.get('usb_mux_sel1')
424
425 # Make the host unable to see the USB disk.
426 if original_value != 'dut_sees_usbkey':
427 self.set('usb_mux_sel1', 'dut_sees_usbkey')
428 time.sleep(self.USB_DETECTION_DELAY)
429 no_usb_set = set(utils.system_output(cmd, ignore_status=True).split())
430
431 # Make the host able to see the USB disk.
432 self.set('usb_mux_sel1', 'servo_sees_usbkey')
433 time.sleep(self.USB_DETECTION_DELAY)
434 has_usb_set = set(utils.system_output(cmd, ignore_status=True).split())
435
436 # Back to its original value.
437 if original_value != 'servo_sees_usbkey':
438 self.set('usb_mux_sel1', original_value)
439 time.sleep(self.USB_DETECTION_DELAY)
440
441 diff_set = has_usb_set - no_usb_set
442 if len(diff_set) == 1:
443 return diff_set.pop()
444 else:
445 return None
446
447
Mike Truty49153d82012-08-21 22:27:30 -0500448 def image_to_servo_usb(self, image_path=None,
449 make_image_noninteractive=False):
450 """Install an image to the USB key plugged into the servo.
451
452 This method may copy any image to the servo USB key including a
453 recovery image or a test image. These images are frequently used
454 for test purposes such as restoring a corrupted image or conducting
455 an upgrade of ec/fw/kernel as part of a test of a specific image part.
456
457 Args:
458 image_path: Path on the host to the recovery image.
459 make_image_noninteractive: Make the recovery image noninteractive,
460 therefore the DUT will reboot
461 automatically after installation.
462 """
463 # Turn the device off. This should happen before USB key detection, to
464 # prevent a recovery destined DUT from sensing the USB key due to the
465 # autodetection procedure.
466 self.initialize_dut(cold_reset=True)
467
468 # Set up Servo's usb mux.
469 self.set('prtctl4_pwren', 'on')
470 self.enable_usb_hub(host=True)
471 if image_path:
472 logging.info('Searching for usb device and copying image to it.')
473 if not self._server.download_image_to_usb(image_path):
474 logging.error('Failed to transfer requested image to USB. '
475 'Please take a look at Servo Logs.')
476 raise error.AutotestError('Download image to usb failed.')
477 if make_image_noninteractive:
478 logging.info('Making image noninteractive')
479 if not self._server.make_image_noninteractive():
480 logging.error('Failed to make image noninteractive. '
481 'Please take a look at Servo Logs.')
482
483
Simran Basi741b5d42012-05-18 11:27:15 -0700484 def install_recovery_image(self, image_path=None,
485 wait_timeout=RECOVERY_INSTALL_DELAY,
486 make_image_noninteractive=False,
487 host=None):
Jon Salzc88e5b62011-11-30 14:38:54 +0800488 """Install the recovery image specied by the path onto the DUT.
489
490 This method uses google recovery mode to install a recovery image
491 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 +0800492 board specified by the usb_dev. If no image path is specified
Jon Salzc88e5b62011-11-30 14:38:54 +0800493 we use the recovery image already on the usb image.
494
495 Args:
496 image_path: Path on the host to the recovery image.
Gilad Arnold9df73de2012-03-14 09:35:08 -0700497 wait_timeout: How long to wait for completion; default is
498 determined by a constant.
Simran Basi741b5d42012-05-18 11:27:15 -0700499 make_image_noninteractive: Make the recovery image noninteractive,
500 therefore the DUT will reboot
501 automatically after installation.
502 host: Host object for the DUT that the installation process is
503 running on. If provided, will wait to see if the host is back
504 up after starting recovery mode.
Jon Salzc88e5b62011-11-30 14:38:54 +0800505 """
Mike Truty49153d82012-08-21 22:27:30 -0500506 self.image_to_servo_usb(image_path, make_image_noninteractive)
Jon Salzc88e5b62011-11-30 14:38:54 +0800507
508 # Boot in recovery mode.
509 try:
Jon Salzc88e5b62011-11-30 14:38:54 +0800510 self.enable_recovery_mode()
Tom Wai-Hong Tam23869102012-01-17 15:41:30 +0800511 self.power_short_press()
Jon Salzc88e5b62011-11-30 14:38:54 +0800512 time.sleep(Servo.RECOVERY_BOOT_DELAY)
Tom Wai-Hong Tam922ed052012-01-09 12:27:52 +0800513 self.set('usb_mux_sel1', 'dut_sees_usbkey')
Jon Salzc88e5b62011-11-30 14:38:54 +0800514 self.disable_recovery_mode()
515
Simran Basi741b5d42012-05-18 11:27:15 -0700516 if host:
Jon Salzc88e5b62011-11-30 14:38:54 +0800517 logging.info('Running the recovery process on the DUT. '
Simran Basi741b5d42012-05-18 11:27:15 -0700518 'Will wait up to %d seconds for recovery to '
519 'complete.', wait_timeout)
520 start_time = time.time()
521 # Wait for the host to come up.
522 if host.wait_up(timeout=wait_timeout):
523 logging.info('Recovery process completed successfully in '
524 '%d seconds.', time.time() - start_time)
525 else:
526 logger.error('Host failed to come back up in the allotted '
527 'time: %d seconds.', wait_timeout)
Jon Salzc88e5b62011-11-30 14:38:54 +0800528 logging.info('Removing the usb key from the DUT.')
529 self.disable_usb_hub()
Jon Salzc88e5b62011-11-30 14:38:54 +0800530 except:
531 # In case anything went wrong we want to make sure to do a clean
532 # reset.
533 self.disable_recovery_mode()
534 self.warm_reset()
535 raise
536
537
Todd Brochf24d2782011-08-19 10:55:41 -0700538 def _connect_servod(self, servo_host, servo_port):
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700539 """Connect to the Servod process with XMLRPC.
540
541 Args:
542 servo_port: Port the Servod process is listening on.
543 """
Todd Brochf24d2782011-08-19 10:55:41 -0700544 remote = 'http://%s:%s' % (servo_host, servo_port)
Todd Broch96d83aa2011-08-29 14:37:38 -0700545 self._server = xmlrpclib.ServerProxy(remote)
Todd Brochf24d2782011-08-19 10:55:41 -0700546 try:
547 self._server.echo("ping-test")
Todd Broch96d83aa2011-08-29 14:37:38 -0700548 except:
549 logging.error('Connection to servod failed')
Todd Brochf24d2782011-08-19 10:55:41 -0700550 raise