blob: 9a427e43aefaba3b6e237fcbd7247a94cd839b98 [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 Broch9753bd42012-03-21 10:15:08 -07008import logging, os, 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.
25 LONG_DELAY = 8
26 SHORT_DELAY = 0.1
27 NORMAL_TRANSITION_DELAY = 1.2
Todd Broch31c82502011-08-29 08:14:39 -070028 # Maximum number of times to re-read power button on release.
29 RELEASE_RETRY_MAX = 5
Todd Brochcf7c6652012-02-24 13:03:59 -080030 GET_RETRY_MAX = 10
Chrome Bot9a1137d2011-07-19 14:35:00 -070031
32 # Delays to deal with computer transitions.
33 SLEEP_DELAY = 6
34 BOOT_DELAY = 10
Jon Salzc88e5b62011-11-30 14:38:54 +080035 RECOVERY_BOOT_DELAY = 30
J. Richard Barnettec5a77ad2012-04-25 08:19:00 -070036 RECOVERY_INSTALL_DELAY = 540
Chrome Bot9a1137d2011-07-19 14:35:00 -070037
38 # Servo-specific delays.
39 MAX_SERVO_STARTUP_DELAY = 10
40 SERVO_SEND_SIGNAL_DELAY = 0.5
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070041
Jon Salzc88e5b62011-11-30 14:38:54 +080042 # Time between an usb disk plugged-in and detected in the system.
43 USB_DETECTION_DELAY = 10
44
Todd Broch9753bd42012-03-21 10:15:08 -070045 KEY_MATRIX = {
46 'm1': {'ctrl_r': ['0', '0'], 'd': ['0', '1'],
47 'enter': ['1', '0'], 'none': ['1', '1']},
48 'm2': {'ctrl': ['0', '0'], 'refresh': ['0', '1'],
49 'unused': ['1', '0'], 'none': ['1', '1']}
50 }
Chris Masone6a0680f2012-03-02 08:40:00 -080051
J. Richard Barnette67ccb872012-04-19 16:34:56 -070052
Chris Masone6a0680f2012-03-02 08:40:00 -080053 @staticmethod
J. Richard Barnette67ccb872012-04-19 16:34:56 -070054 def _make_servo_hostname(hostname):
55 host_parts = hostname.split('.')
56 host_parts[0] = host_parts[0] + '-servo'
57 return '.'.join(host_parts)
Chris Masone6a0680f2012-03-02 08:40:00 -080058
J. Richard Barnette67ccb872012-04-19 16:34:56 -070059 @staticmethod
60 def get_lab_servo(target_hostname):
61 """Instantiate a Servo for |target_hostname| in the lab.
Chris Masone6a0680f2012-03-02 08:40:00 -080062
J. Richard Barnette67ccb872012-04-19 16:34:56 -070063 Assuming that |target_hostname| is a device in the CrOS test
64 lab, create and return a Servo object pointed at the servo
65 attached to that DUT. The servo in the test lab is assumed
66 to already have servod up and running on it.
67
68 @param target_hostname: device whose servo we want to target.
Chris Masone6a0680f2012-03-02 08:40:00 -080069 @return an appropriately configured Servo
70 """
J. Richard Barnette67ccb872012-04-19 16:34:56 -070071 servo_host = Servo._make_servo_hostname(target_hostname)
72 if utils.host_is_in_lab_zone(servo_host):
73 try:
74 return Servo(servo_host=servo_host)
75 except:
76 # TODO(jrbarnette): Long-term, if we can't get to
77 # a servo in the lab, we want to fail, so we should
78 # pass any exceptions along. Short-term, we're not
79 # ready to rely on servo, so we ignore failures.
80 pass
81 return None
Chris Masone6a0680f2012-03-02 08:40:00 -080082
83
84 def __init__(self, servo_host=None, servo_port=9999,
Todd Broch9753bd42012-03-21 10:15:08 -070085 xml_config=[], servo_vid=None, servo_pid=None,
Gilad Arnold9df73de2012-03-14 09:35:08 -070086 servo_serial=None, cold_reset=False, servo_interfaces=[]):
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070087 """Sets up the servo communication infrastructure.
88
89 Args:
Todd Brochf24d2782011-08-19 10:55:41 -070090 servo_host: Host the servod process should listen on.
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070091 servo_port: Port the servod process should listen on.
Tom Wai-Hong Tam5fc2c792011-11-03 13:05:39 +080092 xml_config: A list of configuration XML files for servod.
Todd Broch5fd6bc02011-07-20 15:53:37 -070093 servo_vid: USB vendor id of servo.
94 servo_pid: USB product id of servo.
95 servo_serial: USB serial id in device descriptor to host to
96 distinguish and control multiple servos. Note servo's EEPROM must
97 be programmed to use this feature.
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070098 cold_reset: If True, cold reset device and boot during init,
99 otherwise perform init with device running.
100 """
Todd Brochf24d2782011-08-19 10:55:41 -0700101 self._servod = None
J. Richard Barnette384056b2012-04-16 11:04:46 -0700102 self._server = None
Todd Broch5fd6bc02011-07-20 15:53:37 -0700103
Todd Broch96d83aa2011-08-29 14:37:38 -0700104 # TODO(tbroch) In case where servo h/w is not connected to the host
105 # running the autotest server, servod will need to be launched by
J. Richard Barnette384056b2012-04-16 11:04:46 -0700106 # another means (udev likely). For now we can use servo_host ==
107 # localhost as a heuristic for determining this.
Todd Broch96d83aa2011-08-29 14:37:38 -0700108 if not servo_host or servo_host == 'localhost':
109 servo_host = 'localhost'
110 self._launch_servod(servo_host, servo_port, xml_config, servo_vid,
Gilad Arnold9df73de2012-03-14 09:35:08 -0700111 servo_pid, servo_serial, servo_interfaces)
Todd Broch96d83aa2011-08-29 14:37:38 -0700112 else:
113 logging.info('servod should already be running on host = %s',
114 servo_host)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700115
Chrome Bot9a1137d2011-07-19 14:35:00 -0700116 self._do_cold_reset = cold_reset
Todd Brochf24d2782011-08-19 10:55:41 -0700117 self._connect_servod(servo_host, servo_port)
Chrome Bot9a1137d2011-07-19 14:35:00 -0700118
119
120 def initialize_dut(self):
121 """Initializes a dut for testing purposes."""
122 if self._do_cold_reset:
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700123 self._init_seq_cold_reset_devmode()
124 else:
125 self._init_seq()
126
127
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700128 def power_long_press(self):
Chrome Bot9a1137d2011-07-19 14:35:00 -0700129 """Simulate a long power button press."""
130 self.power_key(Servo.LONG_DELAY)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700131
132
133 def power_normal_press(self):
Chrome Bot9a1137d2011-07-19 14:35:00 -0700134 """Simulate a normal power button press."""
135 self.power_key()
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700136
137
138 def power_short_press(self):
Chrome Bot9a1137d2011-07-19 14:35:00 -0700139 """Simulate a short power button press."""
140 self.power_key(Servo.SHORT_DELAY)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700141
142
Chrome Bot9a1137d2011-07-19 14:35:00 -0700143 def power_key(self, secs=NORMAL_TRANSITION_DELAY):
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700144 """Simulate a power button press.
145
146 Args:
147 secs: Time in seconds to simulate the keypress.
148 """
Craig Harrison6b36b122011-06-28 17:58:43 -0700149 self.set_nocheck('pwr_button', 'press')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700150 time.sleep(secs)
Todd Broch31c82502011-08-29 08:14:39 -0700151 self.set_nocheck('pwr_button', 'release')
152 # TODO(tbroch) Different systems have different release times on the
153 # power button that this loop addresses. Longer term we may want to
154 # make this delay platform specific.
155 retry = 1
156 while True:
157 value = self.get('pwr_button')
158 if value == 'release' or retry > Servo.RELEASE_RETRY_MAX:
159 break
Todd Broch9753bd42012-03-21 10:15:08 -0700160 logging.info('Waiting for pwr_button to release, retry %d.', retry)
Todd Broch31c82502011-08-29 08:14:39 -0700161 retry += 1
162 time.sleep(Servo.SHORT_DELAY)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700163
164
165 def lid_open(self):
166 """Simulate opening the lid."""
Craig Harrison48997262011-06-27 14:31:10 -0700167 self.set_nocheck('lid_open', 'yes')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700168
169
170 def lid_close(self):
Craig Harrison48997262011-06-27 14:31:10 -0700171 """Simulate closing the lid.
172
173 Waits 6 seconds to ensure the device is fully asleep before returning.
174 """
175 self.set_nocheck('lid_open', 'no')
Chrome Bot9a1137d2011-07-19 14:35:00 -0700176 time.sleep(Servo.SLEEP_DELAY)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700177
178
Todd Broch9753bd42012-03-21 10:15:08 -0700179 def _press_and_release_keys(self, m1, m2,
180 press_secs=SERVO_SEND_SIGNAL_DELAY):
Todd Broch9dfc3a82011-11-01 08:09:28 -0700181 """Simulate button presses."""
Todd Broch9753bd42012-03-21 10:15:08 -0700182 # set keys to none
183 (m2_a1, m2_a0) = self.KEY_MATRIX['m2']['none']
184 (m1_a1, m1_a0) = self.KEY_MATRIX['m1']['none']
185 self.set_nocheck('kbd_m2_a0', m2_a0)
186 self.set_nocheck('kbd_m2_a1', m2_a1)
187 self.set_nocheck('kbd_m1_a0', m1_a0)
188 self.set_nocheck('kbd_m1_a1', m1_a1)
Todd Broch9dfc3a82011-11-01 08:09:28 -0700189
Todd Broch9753bd42012-03-21 10:15:08 -0700190 (m2_a1, m2_a0) = self.KEY_MATRIX['m2'][m2]
191 (m1_a1, m1_a0) = self.KEY_MATRIX['m1'][m1]
Todd Broch9dfc3a82011-11-01 08:09:28 -0700192 self.set_nocheck('kbd_en', 'on')
Todd Broch9753bd42012-03-21 10:15:08 -0700193 self.set_nocheck('kbd_m2_a0', m2_a0)
194 self.set_nocheck('kbd_m2_a1', m2_a1)
195 self.set_nocheck('kbd_m1_a0', m1_a0)
196 self.set_nocheck('kbd_m1_a1', m1_a1)
Todd Broch9dfc3a82011-11-01 08:09:28 -0700197 time.sleep(press_secs)
198 self.set_nocheck('kbd_en', 'off')
199
200
Chrome Bot9a1137d2011-07-19 14:35:00 -0700201 def ctrl_d(self):
202 """Simulate Ctrl-d simultaneous button presses."""
Todd Broch9dfc3a82011-11-01 08:09:28 -0700203 self._press_and_release_keys('d', 'ctrl')
204
205
Todd Broch9753bd42012-03-21 10:15:08 -0700206 def ctrl_enter(self):
207 """Simulate Ctrl-enter simultaneous button presses."""
208 self._press_and_release_keys('enter', 'ctrl')
209
210
Todd Broch9dfc3a82011-11-01 08:09:28 -0700211 def d_key(self):
212 """Simulate Enter key button press."""
213 self._press_and_release_keys('d', 'none')
214
215
216 def ctrl_key(self):
217 """Simulate Enter key button press."""
218 self._press_and_release_keys('none', 'ctrl')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700219
220
Chrome Bot9a1137d2011-07-19 14:35:00 -0700221 def enter_key(self):
222 """Simulate Enter key button press."""
Todd Broch9dfc3a82011-11-01 08:09:28 -0700223 self._press_and_release_keys('enter', 'none')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700224
225
Chrome Bot9a1137d2011-07-19 14:35:00 -0700226 def refresh_key(self):
227 """Simulate Refresh key (F3) button press."""
Todd Broch9dfc3a82011-11-01 08:09:28 -0700228 self._press_and_release_keys('none', 'refresh')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700229
230
Chrome Bot9a1137d2011-07-19 14:35:00 -0700231 def imaginary_key(self):
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700232 """Simulate imaginary key button press.
233
234 Maps to a key that doesn't physically exist.
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700235 """
Todd Broch9dfc3a82011-11-01 08:09:28 -0700236 self._press_and_release_keys('none', 'unused')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700237
238
Craig Harrison6b36b122011-06-28 17:58:43 -0700239 def enable_recovery_mode(self):
240 """Enable recovery mode on device."""
241 self.set('rec_mode', 'on')
242
243
244 def disable_recovery_mode(self):
245 """Disable recovery mode on device."""
246 self.set('rec_mode', 'off')
247
248
249 def enable_development_mode(self):
250 """Enable development mode on device."""
251 self.set('dev_mode', 'on')
252
253
254 def disable_development_mode(self):
255 """Disable development mode on device."""
256 self.set('dev_mode', 'off')
257
Chris Sosa8ee1d592011-08-14 16:50:31 -0700258 def enable_usb_hub(self, host=False):
Craig Harrison86b1a572011-08-12 11:26:52 -0700259 """Enable Servo's USB/ethernet hub.
260
Chris Sosa8ee1d592011-08-14 16:50:31 -0700261 This is equivalent to plugging in the USB devices attached to Servo to
262 the host (if |host| is True) or dut (if |host| is False).
263 For host=False, requires that the USB out on the servo board is
264 connected to a USB in port on the target device. Servo's USB ports are
265 labeled DUT_HUB_USB1 and DUT_HUB_USB2. Servo's ethernet port is also
266 connected to this hub. Servo's USB port DUT_HUB_IN is the output of the
267 hub.
Craig Harrison86b1a572011-08-12 11:26:52 -0700268 """
269 self.set('dut_hub_pwren', 'on')
Chris Sosa8ee1d592011-08-14 16:50:31 -0700270 if host:
Todd Broch9753bd42012-03-21 10:15:08 -0700271 self.set('usb_mux_oe1', 'on')
272 self.set('usb_mux_sel1', 'servo_sees_usbkey')
Chris Sosa8ee1d592011-08-14 16:50:31 -0700273 else:
Todd Broch9753bd42012-03-21 10:15:08 -0700274 self.set('dut_hub_sel', 'dut_sees_hub')
Chris Sosa8ee1d592011-08-14 16:50:31 -0700275
Craig Harrison86b1a572011-08-12 11:26:52 -0700276 self.set('dut_hub_on', 'yes')
277
278
279 def disable_usb_hub(self):
280 """Disable Servo's USB/ethernet hub.
281
282 This is equivalent to unplugging the USB devices attached to Servo.
283 """
284 self.set('dut_hub_on', 'no')
285
286
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700287 def boot_devmode(self):
288 """Boot a dev-mode device that is powered off."""
Tom Wai-Hong Tam23869102012-01-17 15:41:30 +0800289 self.power_short_press()
Craig Harrison48997262011-06-27 14:31:10 -0700290 self.pass_devmode()
291
292
293 def pass_devmode(self):
294 """Pass through boot screens in dev-mode."""
Chrome Bot9a1137d2011-07-19 14:35:00 -0700295 time.sleep(Servo.BOOT_DELAY)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700296 self.ctrl_d()
Chrome Bot9a1137d2011-07-19 14:35:00 -0700297 time.sleep(Servo.BOOT_DELAY)
Craig Harrison48997262011-06-27 14:31:10 -0700298
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700299
Craig Harrison6b36b122011-06-28 17:58:43 -0700300 def cold_reset(self):
301 """Perform a cold reset of the EC.
302
Chris Sosa8ee1d592011-08-14 16:50:31 -0700303 Has the side effect of shutting off the device. Device is guaranteed
304 to be off at the end of this call.
Craig Harrison6b36b122011-06-28 17:58:43 -0700305 """
306 self.set('cold_reset', 'on')
Chrome Bot9a1137d2011-07-19 14:35:00 -0700307 time.sleep(Servo.SERVO_SEND_SIGNAL_DELAY)
Craig Harrison6b36b122011-06-28 17:58:43 -0700308
309
310 def warm_reset(self):
311 """Perform a warm reset of the device.
312
313 Has the side effect of restarting the device.
314 """
315 self.set('warm_reset', 'on')
Chrome Bot9a1137d2011-07-19 14:35:00 -0700316 time.sleep(Servo.SERVO_SEND_SIGNAL_DELAY)
Craig Harrison6b36b122011-06-28 17:58:43 -0700317 self.set('warm_reset', 'off')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700318
319
320 def get(self, gpio_name):
321 """Get the value of a gpio from Servod."""
322 assert gpio_name
323 return self._server.get(gpio_name)
324
325
326 def set(self, gpio_name, gpio_value):
327 """Set and check the value of a gpio using Servod."""
Chrome Bot9a1137d2011-07-19 14:35:00 -0700328 self.set_nocheck(gpio_name, gpio_value)
Todd Brochcf7c6652012-02-24 13:03:59 -0800329 retry_count = Servo.GET_RETRY_MAX
330 while gpio_value != self.get(gpio_name) and retry_count:
331 logging.warn("%s != %s, retry %d", gpio_name, gpio_value,
332 retry_count)
333 retry_count -= 1
334 time.sleep(Servo.SHORT_DELAY)
335 if not retry_count:
336 assert gpio_value == self.get(gpio_name), \
337 'Servo failed to set %s to %s' % (gpio_name, gpio_value)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700338
339
340 def set_nocheck(self, gpio_name, gpio_value):
341 """Set the value of a gpio using Servod."""
342 assert gpio_name and gpio_value
Todd Broch9753bd42012-03-21 10:15:08 -0700343 logging.info('Setting %s to %s', gpio_name, gpio_value)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700344 self._server.set(gpio_name, gpio_value)
345
346
Jon Salzc88e5b62011-11-30 14:38:54 +0800347 # TODO(waihong) It may fail if multiple servo's are connected to the same
348 # host. Should look for a better way, like the USB serial name, to identify
349 # the USB device.
Simran Basi741b5d42012-05-18 11:27:15 -0700350 # TODO(sbasi) Remove this code from autoserv once firmware tests have been
351 # updated.
Jon Salzc88e5b62011-11-30 14:38:54 +0800352 def probe_host_usb_dev(self):
353 """Probe the USB disk device plugged-in the servo from the host side.
354
355 It tries to switch the USB mux to make the host unable to see the
356 USB disk and compares the result difference.
357
358 This only works if the servo is attached to the local host.
359
360 Returns:
361 A string of USB disk path, like '/dev/sdb', or None if not existed.
362 """
363 cmd = 'ls /dev/sd[a-z]'
364 original_value = self.get('usb_mux_sel1')
365
366 # Make the host unable to see the USB disk.
367 if original_value != 'dut_sees_usbkey':
368 self.set('usb_mux_sel1', 'dut_sees_usbkey')
369 time.sleep(self.USB_DETECTION_DELAY)
370 no_usb_set = set(utils.system_output(cmd, ignore_status=True).split())
371
372 # Make the host able to see the USB disk.
373 self.set('usb_mux_sel1', 'servo_sees_usbkey')
374 time.sleep(self.USB_DETECTION_DELAY)
375 has_usb_set = set(utils.system_output(cmd, ignore_status=True).split())
376
377 # Back to its original value.
378 if original_value != 'servo_sees_usbkey':
379 self.set('usb_mux_sel1', original_value)
380 time.sleep(self.USB_DETECTION_DELAY)
381
382 diff_set = has_usb_set - no_usb_set
383 if len(diff_set) == 1:
384 return diff_set.pop()
385 else:
386 return None
387
388
Simran Basi741b5d42012-05-18 11:27:15 -0700389 def install_recovery_image(self, image_path=None,
390 wait_timeout=RECOVERY_INSTALL_DELAY,
391 make_image_noninteractive=False,
392 host=None):
Jon Salzc88e5b62011-11-30 14:38:54 +0800393 """Install the recovery image specied by the path onto the DUT.
394
395 This method uses google recovery mode to install a recovery image
396 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 +0800397 board specified by the usb_dev. If no image path is specified
Jon Salzc88e5b62011-11-30 14:38:54 +0800398 we use the recovery image already on the usb image.
399
400 Args:
401 image_path: Path on the host to the recovery image.
Gilad Arnold9df73de2012-03-14 09:35:08 -0700402 wait_timeout: How long to wait for completion; default is
403 determined by a constant.
Simran Basi741b5d42012-05-18 11:27:15 -0700404 make_image_noninteractive: Make the recovery image noninteractive,
405 therefore the DUT will reboot
406 automatically after installation.
407 host: Host object for the DUT that the installation process is
408 running on. If provided, will wait to see if the host is back
409 up after starting recovery mode.
Jon Salzc88e5b62011-11-30 14:38:54 +0800410 """
Gilad Arnold9df73de2012-03-14 09:35:08 -0700411 # Turn the device off. This should happen before USB key detection, to
412 # prevent a recovery destined DUT from sensing the USB key due to the
413 # autodetection procedure.
414 self.power_long_press()
415
Jon Salzc88e5b62011-11-30 14:38:54 +0800416 # Set up Servo's usb mux.
417 self.set('prtctl4_pwren', 'on')
418 self.enable_usb_hub(host=True)
Tom Wai-Hong Tama07115e2012-01-09 12:27:01 +0800419 if image_path:
Simran Basi741b5d42012-05-18 11:27:15 -0700420 logging.info('Searching for usb device')
421 if not self._server.download_image_to_usb(image_path):
422 logging.error('Failed to transfer requested image to USB. '
423 'Please take a look at Servo Logs.')
424 raise error.AutotestError('Download image to usb failed.')
425 if make_image_noninteractive:
426 logging.info('Making image noninteractive')
427 if not self._server.make_image_noninteractive():
428 logging.error('Failed to make image noninteractive. '
429 'Please take a look at Servo Logs.')
Jon Salzc88e5b62011-11-30 14:38:54 +0800430
431 # Boot in recovery mode.
432 try:
Jon Salzc88e5b62011-11-30 14:38:54 +0800433 self.enable_recovery_mode()
Tom Wai-Hong Tam23869102012-01-17 15:41:30 +0800434 self.power_short_press()
Jon Salzc88e5b62011-11-30 14:38:54 +0800435 time.sleep(Servo.RECOVERY_BOOT_DELAY)
Tom Wai-Hong Tam922ed052012-01-09 12:27:52 +0800436 self.set('usb_mux_sel1', 'dut_sees_usbkey')
Jon Salzc88e5b62011-11-30 14:38:54 +0800437 self.disable_recovery_mode()
438
Simran Basi741b5d42012-05-18 11:27:15 -0700439 if host:
Jon Salzc88e5b62011-11-30 14:38:54 +0800440 logging.info('Running the recovery process on the DUT. '
Simran Basi741b5d42012-05-18 11:27:15 -0700441 'Will wait up to %d seconds for recovery to '
442 'complete.', wait_timeout)
443 start_time = time.time()
444 # Wait for the host to come up.
445 if host.wait_up(timeout=wait_timeout):
446 logging.info('Recovery process completed successfully in '
447 '%d seconds.', time.time() - start_time)
448 else:
449 logger.error('Host failed to come back up in the allotted '
450 'time: %d seconds.', wait_timeout)
Jon Salzc88e5b62011-11-30 14:38:54 +0800451 logging.info('Removing the usb key from the DUT.')
452 self.disable_usb_hub()
Jon Salzc88e5b62011-11-30 14:38:54 +0800453 except:
454 # In case anything went wrong we want to make sure to do a clean
455 # reset.
456 self.disable_recovery_mode()
457 self.warm_reset()
458 raise
459
460
Craig Harrison6b36b122011-06-28 17:58:43 -0700461 def _init_seq_cold_reset_devmode(self):
462 """Cold reset, init device, and boot in dev-mode."""
463 self.cold_reset()
464 self._init_seq()
465 self.set('dev_mode', 'on')
466 self.boot_devmode()
467
468
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700469 def __del__(self):
470 """Kill the Servod process."""
Todd Brochf24d2782011-08-19 10:55:41 -0700471 if not self._servod:
472 return
473
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700474 # kill servod one way or another
475 try:
476 # won't work without superuser privileges
477 self._servod.terminate()
478 except:
479 # should work without superuser privileges
480 assert subprocess.call(['sudo', 'kill', str(self._servod.pid)])
481
482
Todd Brochf24d2782011-08-19 10:55:41 -0700483 def _launch_servod(self, servo_host, servo_port, xml_config, servo_vid,
Gilad Arnold9df73de2012-03-14 09:35:08 -0700484 servo_pid, servo_serial, servo_interfaces):
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700485 """Launch the servod process.
486
487 Args:
Todd Brochf24d2782011-08-19 10:55:41 -0700488 servo_host: Host to start servod listening on.
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700489 servo_port: Port to start servod listening on.
Tom Wai-Hong Tam5fc2c792011-11-03 13:05:39 +0800490 xml_config: A list of XML configuration files for servod.
Todd Broch5fd6bc02011-07-20 15:53:37 -0700491 servo_vid: USB vendor id of servo.
492 servo_pid: USB product id of servo.
493 servo_serial: USB serial id in device descriptor to host to
494 distinguish and control multiple servos. Note servo's EEPROM must
495 be programmed to use this feature.
Gilad Arnold9df73de2012-03-14 09:35:08 -0700496 servo_interfaces: a list of servo interface names out of 'gpio',
497 'i2c', 'uart', 'gpiouart' and 'dummy'.
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700498 """
Tom Wai-Hong Tam5fc2c792011-11-03 13:05:39 +0800499 cmdlist = ['sudo', 'servod']
500 for config in xml_config:
501 cmdlist += ['-c', str(config)]
Todd Broch96d83aa2011-08-29 14:37:38 -0700502 if servo_host is not None:
503 cmdlist.append('--host=%s' % str(servo_host))
504 if servo_port is not None:
505 cmdlist.append('--port=%s' % str(servo_port))
Todd Broch5fd6bc02011-07-20 15:53:37 -0700506 if servo_vid is not None:
Todd Brochf24d2782011-08-19 10:55:41 -0700507 cmdlist.append('--vendor=%s' % str(servo_vid))
Todd Broch5fd6bc02011-07-20 15:53:37 -0700508 if servo_pid is not None:
Todd Brochf24d2782011-08-19 10:55:41 -0700509 cmdlist.append('--product=%s' % str(servo_pid))
Todd Broch5fd6bc02011-07-20 15:53:37 -0700510 if servo_serial is not None:
Todd Brochf24d2782011-08-19 10:55:41 -0700511 cmdlist.append('--serialname=%s' % str(servo_serial))
Gilad Arnold9df73de2012-03-14 09:35:08 -0700512 if servo_interfaces:
513 cmdlist.append('--interfaces=%s' % ' '.join(servo_interfaces))
Todd Broch9753bd42012-03-21 10:15:08 -0700514 logging.info('starting servod w/ cmd :: %s', ' '.join(cmdlist))
Todd Broch5fd6bc02011-07-20 15:53:37 -0700515 self._servod = subprocess.Popen(cmdlist, 0, None, None, None,
516 subprocess.PIPE)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700517 # wait for servod to initialize
Chrome Bot9a1137d2011-07-19 14:35:00 -0700518 timeout = Servo.MAX_SERVO_STARTUP_DELAY
Todd Broch9753bd42012-03-21 10:15:08 -0700519 start_time = time.time()
520 listening = False
521 while (time.time() - start_time) < timeout and \
522 self._servod.returncode is None:
523 (rfds, _, _) = select.select([self._servod.stderr], [], [], 0)
524 if len(rfds) > 0:
525 if 'Listening' in rfds[0].readline():
526 listening = True
527 break
528
529 if not listening:
530 logging.fatal("Unable to successfully launch servod")
531 sys.exit(-1)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700532
533
534 def _init_seq(self):
535 """Initiate starting state for servo."""
Todd Broch9753bd42012-03-21 10:15:08 -0700536 # TODO(tbroch) This is only a servo V1 control. Need to add ability in
537 # servod to easily identify version so I can make this conditional not
538 # try and fail quietly
539 try:
540 self.set('tx_dir', 'input')
541 except:
542 logging.warning("Failed to set tx_dir. This is ok if not servo V1")
543
544
Todd Broch6ec29432011-12-19 14:32:02 -0800545 # TODO(tbroch) Investigate method to determine DUT's type so we can
546 # conditionally set lid if applicable
547 self.set_nocheck('lid_open', 'yes')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700548 self.set('rec_mode', 'off')
549
550
Todd Brochf24d2782011-08-19 10:55:41 -0700551 def _connect_servod(self, servo_host, servo_port):
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700552 """Connect to the Servod process with XMLRPC.
553
554 Args:
555 servo_port: Port the Servod process is listening on.
556 """
Todd Brochf24d2782011-08-19 10:55:41 -0700557 remote = 'http://%s:%s' % (servo_host, servo_port)
Todd Broch96d83aa2011-08-29 14:37:38 -0700558 self._server = xmlrpclib.ServerProxy(remote)
Todd Brochf24d2782011-08-19 10:55:41 -0700559 try:
560 self._server.echo("ping-test")
Todd Broch96d83aa2011-08-29 14:37:38 -0700561 except:
562 logging.error('Connection to servod failed')
Todd Brochf24d2782011-08-19 10:55:41 -0700563 raise