blob: daf0c05dd1119719ae6d8f666213dc28b97cd550 [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
10from autotest_lib.server import utils
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070011
J. Richard Barnette384056b2012-04-16 11:04:46 -070012class Servo(object):
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070013 """Manages control of a Servo board.
14
15 Servo is a board developed by hardware group to aide in the debug and
16 control of various partner devices. Servo's features include the simulation
17 of pressing the power button, closing the lid, and pressing Ctrl-d. This
18 class manages setting up and communicating with a servo demon (servod)
19 process. It provides both high-level functions for common servo tasks and
20 low-level functions for directly setting and reading gpios.
21 """
22
Chrome Bot9a1137d2011-07-19 14:35:00 -070023 # Power button press delays in seconds.
24 LONG_DELAY = 8
25 SHORT_DELAY = 0.1
26 NORMAL_TRANSITION_DELAY = 1.2
Todd Broch31c82502011-08-29 08:14:39 -070027 # Maximum number of times to re-read power button on release.
28 RELEASE_RETRY_MAX = 5
Todd Brochcf7c6652012-02-24 13:03:59 -080029 GET_RETRY_MAX = 10
Chrome Bot9a1137d2011-07-19 14:35:00 -070030
31 # Delays to deal with computer transitions.
32 SLEEP_DELAY = 6
33 BOOT_DELAY = 10
Jon Salzc88e5b62011-11-30 14:38:54 +080034 RECOVERY_BOOT_DELAY = 30
35 RECOVERY_INSTALL_DELAY = 180
Chrome Bot9a1137d2011-07-19 14:35:00 -070036
37 # Servo-specific delays.
38 MAX_SERVO_STARTUP_DELAY = 10
39 SERVO_SEND_SIGNAL_DELAY = 0.5
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070040
Jon Salzc88e5b62011-11-30 14:38:54 +080041 # Time between an usb disk plugged-in and detected in the system.
42 USB_DETECTION_DELAY = 10
43
Todd Broch9753bd42012-03-21 10:15:08 -070044 KEY_MATRIX = {
45 'm1': {'ctrl_r': ['0', '0'], 'd': ['0', '1'],
46 'enter': ['1', '0'], 'none': ['1', '1']},
47 'm2': {'ctrl': ['0', '0'], 'refresh': ['0', '1'],
48 'unused': ['1', '0'], 'none': ['1', '1']}
49 }
Chris Masone6a0680f2012-03-02 08:40:00 -080050
51 @staticmethod
52 def create_simple(device_under_test_hostname):
53 """Instantiate a Servo for |device_under_test_hostname| in the lab.
54
55 Assuming that |device_under_test_hostname| is a device in the CrOS
56 test lab, create and return a Servo object pointed at the
57 servo attached to that DUT. The servo in the test lab is assumed to
58 already have servod up and running on it.
59
60 @param device_under_test_hostname: device whose servo we want to target.
61 @return an appropriately configured Servo
62 """
63 host_parts = device_under_test_hostname.split('.')
64 host_parts[0] = host_parts[0] + '-servo'
65 return Servo(servo_host='.'.join(host_parts))
66
67
68 def __init__(self, servo_host=None, servo_port=9999,
Todd Broch9753bd42012-03-21 10:15:08 -070069 xml_config=[], servo_vid=None, servo_pid=None,
Gilad Arnold9df73de2012-03-14 09:35:08 -070070 servo_serial=None, cold_reset=False, servo_interfaces=[]):
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070071 """Sets up the servo communication infrastructure.
72
73 Args:
Todd Brochf24d2782011-08-19 10:55:41 -070074 servo_host: Host the servod process should listen on.
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070075 servo_port: Port the servod process should listen on.
Tom Wai-Hong Tam5fc2c792011-11-03 13:05:39 +080076 xml_config: A list of configuration XML files for servod.
Todd Broch5fd6bc02011-07-20 15:53:37 -070077 servo_vid: USB vendor id of servo.
78 servo_pid: USB product id of servo.
79 servo_serial: USB serial id in device descriptor to host to
80 distinguish and control multiple servos. Note servo's EEPROM must
81 be programmed to use this feature.
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070082 cold_reset: If True, cold reset device and boot during init,
83 otherwise perform init with device running.
84 """
Todd Brochf24d2782011-08-19 10:55:41 -070085 self._servod = None
J. Richard Barnette384056b2012-04-16 11:04:46 -070086 self._server = None
Todd Broch5fd6bc02011-07-20 15:53:37 -070087
Todd Broch96d83aa2011-08-29 14:37:38 -070088 # TODO(tbroch) In case where servo h/w is not connected to the host
89 # running the autotest server, servod will need to be launched by
J. Richard Barnette384056b2012-04-16 11:04:46 -070090 # another means (udev likely). For now we can use servo_host ==
91 # localhost as a heuristic for determining this.
Todd Broch96d83aa2011-08-29 14:37:38 -070092 if not servo_host or servo_host == 'localhost':
93 servo_host = 'localhost'
94 self._launch_servod(servo_host, servo_port, xml_config, servo_vid,
Gilad Arnold9df73de2012-03-14 09:35:08 -070095 servo_pid, servo_serial, servo_interfaces)
Todd Broch96d83aa2011-08-29 14:37:38 -070096 else:
97 logging.info('servod should already be running on host = %s',
98 servo_host)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070099
Chrome Bot9a1137d2011-07-19 14:35:00 -0700100 self._do_cold_reset = cold_reset
Todd Brochf24d2782011-08-19 10:55:41 -0700101 self._connect_servod(servo_host, servo_port)
Chrome Bot9a1137d2011-07-19 14:35:00 -0700102
103
104 def initialize_dut(self):
105 """Initializes a dut for testing purposes."""
106 if self._do_cold_reset:
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700107 self._init_seq_cold_reset_devmode()
108 else:
109 self._init_seq()
110
111
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700112 def power_long_press(self):
Chrome Bot9a1137d2011-07-19 14:35:00 -0700113 """Simulate a long power button press."""
114 self.power_key(Servo.LONG_DELAY)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700115
116
117 def power_normal_press(self):
Chrome Bot9a1137d2011-07-19 14:35:00 -0700118 """Simulate a normal power button press."""
119 self.power_key()
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700120
121
122 def power_short_press(self):
Chrome Bot9a1137d2011-07-19 14:35:00 -0700123 """Simulate a short power button press."""
124 self.power_key(Servo.SHORT_DELAY)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700125
126
Chrome Bot9a1137d2011-07-19 14:35:00 -0700127 def power_key(self, secs=NORMAL_TRANSITION_DELAY):
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700128 """Simulate a power button press.
129
130 Args:
131 secs: Time in seconds to simulate the keypress.
132 """
Craig Harrison6b36b122011-06-28 17:58:43 -0700133 self.set_nocheck('pwr_button', 'press')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700134 time.sleep(secs)
Todd Broch31c82502011-08-29 08:14:39 -0700135 self.set_nocheck('pwr_button', 'release')
136 # TODO(tbroch) Different systems have different release times on the
137 # power button that this loop addresses. Longer term we may want to
138 # make this delay platform specific.
139 retry = 1
140 while True:
141 value = self.get('pwr_button')
142 if value == 'release' or retry > Servo.RELEASE_RETRY_MAX:
143 break
Todd Broch9753bd42012-03-21 10:15:08 -0700144 logging.info('Waiting for pwr_button to release, retry %d.', retry)
Todd Broch31c82502011-08-29 08:14:39 -0700145 retry += 1
146 time.sleep(Servo.SHORT_DELAY)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700147
148
149 def lid_open(self):
150 """Simulate opening the lid."""
Craig Harrison48997262011-06-27 14:31:10 -0700151 self.set_nocheck('lid_open', 'yes')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700152
153
154 def lid_close(self):
Craig Harrison48997262011-06-27 14:31:10 -0700155 """Simulate closing the lid.
156
157 Waits 6 seconds to ensure the device is fully asleep before returning.
158 """
159 self.set_nocheck('lid_open', 'no')
Chrome Bot9a1137d2011-07-19 14:35:00 -0700160 time.sleep(Servo.SLEEP_DELAY)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700161
162
Todd Broch9753bd42012-03-21 10:15:08 -0700163 def _press_and_release_keys(self, m1, m2,
164 press_secs=SERVO_SEND_SIGNAL_DELAY):
Todd Broch9dfc3a82011-11-01 08:09:28 -0700165 """Simulate button presses."""
Todd Broch9753bd42012-03-21 10:15:08 -0700166 # set keys to none
167 (m2_a1, m2_a0) = self.KEY_MATRIX['m2']['none']
168 (m1_a1, m1_a0) = self.KEY_MATRIX['m1']['none']
169 self.set_nocheck('kbd_m2_a0', m2_a0)
170 self.set_nocheck('kbd_m2_a1', m2_a1)
171 self.set_nocheck('kbd_m1_a0', m1_a0)
172 self.set_nocheck('kbd_m1_a1', m1_a1)
Todd Broch9dfc3a82011-11-01 08:09:28 -0700173
Todd Broch9753bd42012-03-21 10:15:08 -0700174 (m2_a1, m2_a0) = self.KEY_MATRIX['m2'][m2]
175 (m1_a1, m1_a0) = self.KEY_MATRIX['m1'][m1]
Todd Broch9dfc3a82011-11-01 08:09:28 -0700176 self.set_nocheck('kbd_en', 'on')
Todd Broch9753bd42012-03-21 10:15:08 -0700177 self.set_nocheck('kbd_m2_a0', m2_a0)
178 self.set_nocheck('kbd_m2_a1', m2_a1)
179 self.set_nocheck('kbd_m1_a0', m1_a0)
180 self.set_nocheck('kbd_m1_a1', m1_a1)
Todd Broch9dfc3a82011-11-01 08:09:28 -0700181 time.sleep(press_secs)
182 self.set_nocheck('kbd_en', 'off')
183
184
Chrome Bot9a1137d2011-07-19 14:35:00 -0700185 def ctrl_d(self):
186 """Simulate Ctrl-d simultaneous button presses."""
Todd Broch9dfc3a82011-11-01 08:09:28 -0700187 self._press_and_release_keys('d', 'ctrl')
188
189
Todd Broch9753bd42012-03-21 10:15:08 -0700190 def ctrl_enter(self):
191 """Simulate Ctrl-enter simultaneous button presses."""
192 self._press_and_release_keys('enter', 'ctrl')
193
194
Todd Broch9dfc3a82011-11-01 08:09:28 -0700195 def d_key(self):
196 """Simulate Enter key button press."""
197 self._press_and_release_keys('d', 'none')
198
199
200 def ctrl_key(self):
201 """Simulate Enter key button press."""
202 self._press_and_release_keys('none', 'ctrl')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700203
204
Chrome Bot9a1137d2011-07-19 14:35:00 -0700205 def enter_key(self):
206 """Simulate Enter key button press."""
Todd Broch9dfc3a82011-11-01 08:09:28 -0700207 self._press_and_release_keys('enter', 'none')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700208
209
Chrome Bot9a1137d2011-07-19 14:35:00 -0700210 def refresh_key(self):
211 """Simulate Refresh key (F3) button press."""
Todd Broch9dfc3a82011-11-01 08:09:28 -0700212 self._press_and_release_keys('none', 'refresh')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700213
214
Chrome Bot9a1137d2011-07-19 14:35:00 -0700215 def imaginary_key(self):
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700216 """Simulate imaginary key button press.
217
218 Maps to a key that doesn't physically exist.
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700219 """
Todd Broch9dfc3a82011-11-01 08:09:28 -0700220 self._press_and_release_keys('none', 'unused')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700221
222
Craig Harrison6b36b122011-06-28 17:58:43 -0700223 def enable_recovery_mode(self):
224 """Enable recovery mode on device."""
225 self.set('rec_mode', 'on')
226
227
228 def disable_recovery_mode(self):
229 """Disable recovery mode on device."""
230 self.set('rec_mode', 'off')
231
232
233 def enable_development_mode(self):
234 """Enable development mode on device."""
235 self.set('dev_mode', 'on')
236
237
238 def disable_development_mode(self):
239 """Disable development mode on device."""
240 self.set('dev_mode', 'off')
241
Chris Sosa8ee1d592011-08-14 16:50:31 -0700242 def enable_usb_hub(self, host=False):
Craig Harrison86b1a572011-08-12 11:26:52 -0700243 """Enable Servo's USB/ethernet hub.
244
Chris Sosa8ee1d592011-08-14 16:50:31 -0700245 This is equivalent to plugging in the USB devices attached to Servo to
246 the host (if |host| is True) or dut (if |host| is False).
247 For host=False, requires that the USB out on the servo board is
248 connected to a USB in port on the target device. Servo's USB ports are
249 labeled DUT_HUB_USB1 and DUT_HUB_USB2. Servo's ethernet port is also
250 connected to this hub. Servo's USB port DUT_HUB_IN is the output of the
251 hub.
Craig Harrison86b1a572011-08-12 11:26:52 -0700252 """
253 self.set('dut_hub_pwren', 'on')
Chris Sosa8ee1d592011-08-14 16:50:31 -0700254 if host:
Todd Broch9753bd42012-03-21 10:15:08 -0700255 self.set('usb_mux_oe1', 'on')
256 self.set('usb_mux_sel1', 'servo_sees_usbkey')
Chris Sosa8ee1d592011-08-14 16:50:31 -0700257 else:
Todd Broch9753bd42012-03-21 10:15:08 -0700258 self.set('dut_hub_sel', 'dut_sees_hub')
Chris Sosa8ee1d592011-08-14 16:50:31 -0700259
Craig Harrison86b1a572011-08-12 11:26:52 -0700260 self.set('dut_hub_on', 'yes')
261
262
263 def disable_usb_hub(self):
264 """Disable Servo's USB/ethernet hub.
265
266 This is equivalent to unplugging the USB devices attached to Servo.
267 """
268 self.set('dut_hub_on', 'no')
269
270
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700271 def boot_devmode(self):
272 """Boot a dev-mode device that is powered off."""
Tom Wai-Hong Tam23869102012-01-17 15:41:30 +0800273 self.power_short_press()
Craig Harrison48997262011-06-27 14:31:10 -0700274 self.pass_devmode()
275
276
277 def pass_devmode(self):
278 """Pass through boot screens in dev-mode."""
Chrome Bot9a1137d2011-07-19 14:35:00 -0700279 time.sleep(Servo.BOOT_DELAY)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700280 self.ctrl_d()
Chrome Bot9a1137d2011-07-19 14:35:00 -0700281 time.sleep(Servo.BOOT_DELAY)
Craig Harrison48997262011-06-27 14:31:10 -0700282
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700283
Craig Harrison6b36b122011-06-28 17:58:43 -0700284 def cold_reset(self):
285 """Perform a cold reset of the EC.
286
Chris Sosa8ee1d592011-08-14 16:50:31 -0700287 Has the side effect of shutting off the device. Device is guaranteed
288 to be off at the end of this call.
Craig Harrison6b36b122011-06-28 17:58:43 -0700289 """
290 self.set('cold_reset', 'on')
Chrome Bot9a1137d2011-07-19 14:35:00 -0700291 time.sleep(Servo.SERVO_SEND_SIGNAL_DELAY)
Craig Harrison6b36b122011-06-28 17:58:43 -0700292
293
294 def warm_reset(self):
295 """Perform a warm reset of the device.
296
297 Has the side effect of restarting the device.
298 """
299 self.set('warm_reset', 'on')
Chrome Bot9a1137d2011-07-19 14:35:00 -0700300 time.sleep(Servo.SERVO_SEND_SIGNAL_DELAY)
Craig Harrison6b36b122011-06-28 17:58:43 -0700301 self.set('warm_reset', 'off')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700302
303
304 def get(self, gpio_name):
305 """Get the value of a gpio from Servod."""
306 assert gpio_name
307 return self._server.get(gpio_name)
308
309
310 def set(self, gpio_name, gpio_value):
311 """Set and check the value of a gpio using Servod."""
Chrome Bot9a1137d2011-07-19 14:35:00 -0700312 self.set_nocheck(gpio_name, gpio_value)
Todd Brochcf7c6652012-02-24 13:03:59 -0800313 retry_count = Servo.GET_RETRY_MAX
314 while gpio_value != self.get(gpio_name) and retry_count:
315 logging.warn("%s != %s, retry %d", gpio_name, gpio_value,
316 retry_count)
317 retry_count -= 1
318 time.sleep(Servo.SHORT_DELAY)
319 if not retry_count:
320 assert gpio_value == self.get(gpio_name), \
321 'Servo failed to set %s to %s' % (gpio_name, gpio_value)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700322
323
324 def set_nocheck(self, gpio_name, gpio_value):
325 """Set the value of a gpio using Servod."""
326 assert gpio_name and gpio_value
Todd Broch9753bd42012-03-21 10:15:08 -0700327 logging.info('Setting %s to %s', gpio_name, gpio_value)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700328 self._server.set(gpio_name, gpio_value)
329
330
Jon Salzc88e5b62011-11-30 14:38:54 +0800331 # TODO(waihong) It may fail if multiple servo's are connected to the same
332 # host. Should look for a better way, like the USB serial name, to identify
333 # the USB device.
334 def probe_host_usb_dev(self):
335 """Probe the USB disk device plugged-in the servo from the host side.
336
337 It tries to switch the USB mux to make the host unable to see the
338 USB disk and compares the result difference.
339
340 This only works if the servo is attached to the local host.
341
342 Returns:
343 A string of USB disk path, like '/dev/sdb', or None if not existed.
344 """
345 cmd = 'ls /dev/sd[a-z]'
346 original_value = self.get('usb_mux_sel1')
347
348 # Make the host unable to see the USB disk.
349 if original_value != 'dut_sees_usbkey':
350 self.set('usb_mux_sel1', 'dut_sees_usbkey')
351 time.sleep(self.USB_DETECTION_DELAY)
352 no_usb_set = set(utils.system_output(cmd, ignore_status=True).split())
353
354 # Make the host able to see the USB disk.
355 self.set('usb_mux_sel1', 'servo_sees_usbkey')
356 time.sleep(self.USB_DETECTION_DELAY)
357 has_usb_set = set(utils.system_output(cmd, ignore_status=True).split())
358
359 # Back to its original value.
360 if original_value != 'servo_sees_usbkey':
361 self.set('usb_mux_sel1', original_value)
362 time.sleep(self.USB_DETECTION_DELAY)
363
364 diff_set = has_usb_set - no_usb_set
365 if len(diff_set) == 1:
366 return diff_set.pop()
367 else:
368 return None
369
370
Tom Wai-Hong Tama07115e2012-01-09 12:27:01 +0800371 def install_recovery_image(self, image_path=None, usb_dev=None,
Gilad Arnold9df73de2012-03-14 09:35:08 -0700372 wait_for_completion=True,
373 wait_timeout=RECOVERY_INSTALL_DELAY):
Jon Salzc88e5b62011-11-30 14:38:54 +0800374 """Install the recovery image specied by the path onto the DUT.
375
376 This method uses google recovery mode to install a recovery image
377 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 +0800378 board specified by the usb_dev. If no image path is specified
Jon Salzc88e5b62011-11-30 14:38:54 +0800379 we use the recovery image already on the usb image.
380
381 Args:
382 image_path: Path on the host to the recovery image.
Tom Wai-Hong Tama07115e2012-01-09 12:27:01 +0800383 usb_dev: When servo_sees_usbkey is enabled, which dev
384 e.g. /dev/sdb will the usb key show up as.
385 If None, detects it automatically.
Jon Salzc88e5b62011-11-30 14:38:54 +0800386 wait_for_completion: Whether to wait for completion of the
387 factory install and disable the USB hub
388 before returning. Currently this is just
Gilad Arnold9df73de2012-03-14 09:35:08 -0700389 waiting for a predetermined timeout period.
390 wait_timeout: How long to wait for completion; default is
391 determined by a constant.
Jon Salzc88e5b62011-11-30 14:38:54 +0800392 """
Gilad Arnold9df73de2012-03-14 09:35:08 -0700393 # Turn the device off. This should happen before USB key detection, to
394 # prevent a recovery destined DUT from sensing the USB key due to the
395 # autodetection procedure.
396 self.power_long_press()
397
Jon Salzc88e5b62011-11-30 14:38:54 +0800398 # Set up Servo's usb mux.
399 self.set('prtctl4_pwren', 'on')
400 self.enable_usb_hub(host=True)
Tom Wai-Hong Tama07115e2012-01-09 12:27:01 +0800401 if image_path:
402 if not usb_dev:
Gilad Arnold9df73de2012-03-14 09:35:08 -0700403 logging.info('Detecting USB stick device...')
Tom Wai-Hong Tama07115e2012-01-09 12:27:01 +0800404 usb_dev = self.probe_host_usb_dev()
Gilad Arnold9df73de2012-03-14 09:35:08 -0700405 if not usb_dev:
Todd Broch9753bd42012-03-21 10:15:08 -0700406 raise Exception('USB device not found')
407 logging.info('Found %s', usb_dev)
Tom Wai-Hong Tama07115e2012-01-09 12:27:01 +0800408 logging.info('Installing image onto usb stick. '
409 'This takes a while...')
410 client_utils.poll_for_condition(
411 lambda: os.path.exists(usb_dev),
412 timeout=Servo.USB_DETECTION_DELAY,
413 desc="%s exists" % usb_dev)
Gilad Arnold9df73de2012-03-14 09:35:08 -0700414 utils.system('sudo dd if=%s of=%s bs=4M status=noxfer' %
415 (image_path, usb_dev))
Jon Salzc88e5b62011-11-30 14:38:54 +0800416
417 # Boot in recovery mode.
418 try:
Jon Salzc88e5b62011-11-30 14:38:54 +0800419 self.enable_recovery_mode()
Tom Wai-Hong Tam23869102012-01-17 15:41:30 +0800420 self.power_short_press()
Jon Salzc88e5b62011-11-30 14:38:54 +0800421 time.sleep(Servo.RECOVERY_BOOT_DELAY)
Tom Wai-Hong Tam922ed052012-01-09 12:27:52 +0800422 self.set('usb_mux_sel1', 'dut_sees_usbkey')
Jon Salzc88e5b62011-11-30 14:38:54 +0800423 self.disable_recovery_mode()
424
425 if wait_for_completion:
426 # Enable recovery installation.
427 logging.info('Running the recovery process on the DUT. '
428 'Waiting %d seconds for recovery to complete ...',
Gilad Arnold9df73de2012-03-14 09:35:08 -0700429 wait_timeout)
430 time.sleep(wait_timeout)
Jon Salzc88e5b62011-11-30 14:38:54 +0800431
432 # Go back into normal mode and reboot.
433 # Machine automatically reboots after the usb key is removed.
434 logging.info('Removing the usb key from the DUT.')
435 self.disable_usb_hub()
436 time.sleep(Servo.BOOT_DELAY)
437 except:
438 # In case anything went wrong we want to make sure to do a clean
439 # reset.
440 self.disable_recovery_mode()
441 self.warm_reset()
442 raise
443
444
Craig Harrison6b36b122011-06-28 17:58:43 -0700445 def _init_seq_cold_reset_devmode(self):
446 """Cold reset, init device, and boot in dev-mode."""
447 self.cold_reset()
448 self._init_seq()
449 self.set('dev_mode', 'on')
450 self.boot_devmode()
451
452
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700453 def __del__(self):
454 """Kill the Servod process."""
Todd Brochf24d2782011-08-19 10:55:41 -0700455 if not self._servod:
456 return
457
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700458 # kill servod one way or another
459 try:
460 # won't work without superuser privileges
461 self._servod.terminate()
462 except:
463 # should work without superuser privileges
464 assert subprocess.call(['sudo', 'kill', str(self._servod.pid)])
465
466
Todd Brochf24d2782011-08-19 10:55:41 -0700467 def _launch_servod(self, servo_host, servo_port, xml_config, servo_vid,
Gilad Arnold9df73de2012-03-14 09:35:08 -0700468 servo_pid, servo_serial, servo_interfaces):
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700469 """Launch the servod process.
470
471 Args:
Todd Brochf24d2782011-08-19 10:55:41 -0700472 servo_host: Host to start servod listening on.
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700473 servo_port: Port to start servod listening on.
Tom Wai-Hong Tam5fc2c792011-11-03 13:05:39 +0800474 xml_config: A list of XML configuration files for servod.
Todd Broch5fd6bc02011-07-20 15:53:37 -0700475 servo_vid: USB vendor id of servo.
476 servo_pid: USB product id of servo.
477 servo_serial: USB serial id in device descriptor to host to
478 distinguish and control multiple servos. Note servo's EEPROM must
479 be programmed to use this feature.
Gilad Arnold9df73de2012-03-14 09:35:08 -0700480 servo_interfaces: a list of servo interface names out of 'gpio',
481 'i2c', 'uart', 'gpiouart' and 'dummy'.
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700482 """
Tom Wai-Hong Tam5fc2c792011-11-03 13:05:39 +0800483 cmdlist = ['sudo', 'servod']
484 for config in xml_config:
485 cmdlist += ['-c', str(config)]
Todd Broch96d83aa2011-08-29 14:37:38 -0700486 if servo_host is not None:
487 cmdlist.append('--host=%s' % str(servo_host))
488 if servo_port is not None:
489 cmdlist.append('--port=%s' % str(servo_port))
Todd Broch5fd6bc02011-07-20 15:53:37 -0700490 if servo_vid is not None:
Todd Brochf24d2782011-08-19 10:55:41 -0700491 cmdlist.append('--vendor=%s' % str(servo_vid))
Todd Broch5fd6bc02011-07-20 15:53:37 -0700492 if servo_pid is not None:
Todd Brochf24d2782011-08-19 10:55:41 -0700493 cmdlist.append('--product=%s' % str(servo_pid))
Todd Broch5fd6bc02011-07-20 15:53:37 -0700494 if servo_serial is not None:
Todd Brochf24d2782011-08-19 10:55:41 -0700495 cmdlist.append('--serialname=%s' % str(servo_serial))
Gilad Arnold9df73de2012-03-14 09:35:08 -0700496 if servo_interfaces:
497 cmdlist.append('--interfaces=%s' % ' '.join(servo_interfaces))
Todd Broch9753bd42012-03-21 10:15:08 -0700498 logging.info('starting servod w/ cmd :: %s', ' '.join(cmdlist))
Todd Broch5fd6bc02011-07-20 15:53:37 -0700499 self._servod = subprocess.Popen(cmdlist, 0, None, None, None,
500 subprocess.PIPE)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700501 # wait for servod to initialize
Chrome Bot9a1137d2011-07-19 14:35:00 -0700502 timeout = Servo.MAX_SERVO_STARTUP_DELAY
Todd Broch9753bd42012-03-21 10:15:08 -0700503 start_time = time.time()
504 listening = False
505 while (time.time() - start_time) < timeout and \
506 self._servod.returncode is None:
507 (rfds, _, _) = select.select([self._servod.stderr], [], [], 0)
508 if len(rfds) > 0:
509 if 'Listening' in rfds[0].readline():
510 listening = True
511 break
512
513 if not listening:
514 logging.fatal("Unable to successfully launch servod")
515 sys.exit(-1)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700516
517
518 def _init_seq(self):
519 """Initiate starting state for servo."""
Todd Broch9753bd42012-03-21 10:15:08 -0700520 # TODO(tbroch) This is only a servo V1 control. Need to add ability in
521 # servod to easily identify version so I can make this conditional not
522 # try and fail quietly
523 try:
524 self.set('tx_dir', 'input')
525 except:
526 logging.warning("Failed to set tx_dir. This is ok if not servo V1")
527
528
Todd Broch6ec29432011-12-19 14:32:02 -0800529 # TODO(tbroch) Investigate method to determine DUT's type so we can
530 # conditionally set lid if applicable
531 self.set_nocheck('lid_open', 'yes')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700532 self.set('rec_mode', 'off')
533
534
Todd Brochf24d2782011-08-19 10:55:41 -0700535 def _connect_servod(self, servo_host, servo_port):
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700536 """Connect to the Servod process with XMLRPC.
537
538 Args:
539 servo_port: Port the Servod process is listening on.
540 """
Todd Brochf24d2782011-08-19 10:55:41 -0700541 remote = 'http://%s:%s' % (servo_host, servo_port)
Todd Broch96d83aa2011-08-29 14:37:38 -0700542 self._server = xmlrpclib.ServerProxy(remote)
Todd Brochf24d2782011-08-19 10:55:41 -0700543 try:
544 self._server.echo("ping-test")
Todd Broch96d83aa2011-08-29 14:37:38 -0700545 except:
546 logging.error('Connection to servod failed')
Todd Brochf24d2782011-08-19 10:55:41 -0700547 raise