blob: a8d62202f405d841edbfb502b1feee055997302a [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
J. Richard Barnette67ccb872012-04-19 16:34:56 -070051
Chris Masone6a0680f2012-03-02 08:40:00 -080052 @staticmethod
J. Richard Barnette67ccb872012-04-19 16:34:56 -070053 def _make_servo_hostname(hostname):
54 host_parts = hostname.split('.')
55 host_parts[0] = host_parts[0] + '-servo'
56 return '.'.join(host_parts)
Chris Masone6a0680f2012-03-02 08:40:00 -080057
J. Richard Barnette67ccb872012-04-19 16:34:56 -070058 @staticmethod
59 def get_lab_servo(target_hostname):
60 """Instantiate a Servo for |target_hostname| in the lab.
Chris Masone6a0680f2012-03-02 08:40:00 -080061
J. Richard Barnette67ccb872012-04-19 16:34:56 -070062 Assuming that |target_hostname| is a device in the CrOS test
63 lab, create and return a Servo object pointed at the servo
64 attached to that DUT. The servo in the test lab is assumed
65 to already have servod up and running on it.
66
67 @param target_hostname: device whose servo we want to target.
Chris Masone6a0680f2012-03-02 08:40:00 -080068 @return an appropriately configured Servo
69 """
J. Richard Barnette67ccb872012-04-19 16:34:56 -070070 servo_host = Servo._make_servo_hostname(target_hostname)
71 if utils.host_is_in_lab_zone(servo_host):
72 try:
73 return Servo(servo_host=servo_host)
74 except:
75 # TODO(jrbarnette): Long-term, if we can't get to
76 # a servo in the lab, we want to fail, so we should
77 # pass any exceptions along. Short-term, we're not
78 # ready to rely on servo, so we ignore failures.
79 pass
80 return None
Chris Masone6a0680f2012-03-02 08:40:00 -080081
82
83 def __init__(self, servo_host=None, servo_port=9999,
Todd Broch9753bd42012-03-21 10:15:08 -070084 xml_config=[], servo_vid=None, servo_pid=None,
Gilad Arnold9df73de2012-03-14 09:35:08 -070085 servo_serial=None, cold_reset=False, servo_interfaces=[]):
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070086 """Sets up the servo communication infrastructure.
87
88 Args:
Todd Brochf24d2782011-08-19 10:55:41 -070089 servo_host: Host the servod process should listen on.
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070090 servo_port: Port the servod process should listen on.
Tom Wai-Hong Tam5fc2c792011-11-03 13:05:39 +080091 xml_config: A list of configuration XML files for servod.
Todd Broch5fd6bc02011-07-20 15:53:37 -070092 servo_vid: USB vendor id of servo.
93 servo_pid: USB product id of servo.
94 servo_serial: USB serial id in device descriptor to host to
95 distinguish and control multiple servos. Note servo's EEPROM must
96 be programmed to use this feature.
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070097 cold_reset: If True, cold reset device and boot during init,
98 otherwise perform init with device running.
99 """
Todd Brochf24d2782011-08-19 10:55:41 -0700100 self._servod = None
J. Richard Barnette384056b2012-04-16 11:04:46 -0700101 self._server = None
Todd Broch5fd6bc02011-07-20 15:53:37 -0700102
Todd Broch96d83aa2011-08-29 14:37:38 -0700103 # TODO(tbroch) In case where servo h/w is not connected to the host
104 # running the autotest server, servod will need to be launched by
J. Richard Barnette384056b2012-04-16 11:04:46 -0700105 # another means (udev likely). For now we can use servo_host ==
106 # localhost as a heuristic for determining this.
Todd Broch96d83aa2011-08-29 14:37:38 -0700107 if not servo_host or servo_host == 'localhost':
108 servo_host = 'localhost'
109 self._launch_servod(servo_host, servo_port, xml_config, servo_vid,
Gilad Arnold9df73de2012-03-14 09:35:08 -0700110 servo_pid, servo_serial, servo_interfaces)
Todd Broch96d83aa2011-08-29 14:37:38 -0700111 else:
112 logging.info('servod should already be running on host = %s',
113 servo_host)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700114
Chrome Bot9a1137d2011-07-19 14:35:00 -0700115 self._do_cold_reset = cold_reset
Todd Brochf24d2782011-08-19 10:55:41 -0700116 self._connect_servod(servo_host, servo_port)
Chrome Bot9a1137d2011-07-19 14:35:00 -0700117
118
119 def initialize_dut(self):
120 """Initializes a dut for testing purposes."""
121 if self._do_cold_reset:
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700122 self._init_seq_cold_reset_devmode()
123 else:
124 self._init_seq()
125
126
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700127 def power_long_press(self):
Chrome Bot9a1137d2011-07-19 14:35:00 -0700128 """Simulate a long power button press."""
129 self.power_key(Servo.LONG_DELAY)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700130
131
132 def power_normal_press(self):
Chrome Bot9a1137d2011-07-19 14:35:00 -0700133 """Simulate a normal power button press."""
134 self.power_key()
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700135
136
137 def power_short_press(self):
Chrome Bot9a1137d2011-07-19 14:35:00 -0700138 """Simulate a short power button press."""
139 self.power_key(Servo.SHORT_DELAY)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700140
141
Chrome Bot9a1137d2011-07-19 14:35:00 -0700142 def power_key(self, secs=NORMAL_TRANSITION_DELAY):
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700143 """Simulate a power button press.
144
145 Args:
146 secs: Time in seconds to simulate the keypress.
147 """
Craig Harrison6b36b122011-06-28 17:58:43 -0700148 self.set_nocheck('pwr_button', 'press')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700149 time.sleep(secs)
Todd Broch31c82502011-08-29 08:14:39 -0700150 self.set_nocheck('pwr_button', 'release')
151 # TODO(tbroch) Different systems have different release times on the
152 # power button that this loop addresses. Longer term we may want to
153 # make this delay platform specific.
154 retry = 1
155 while True:
156 value = self.get('pwr_button')
157 if value == 'release' or retry > Servo.RELEASE_RETRY_MAX:
158 break
Todd Broch9753bd42012-03-21 10:15:08 -0700159 logging.info('Waiting for pwr_button to release, retry %d.', retry)
Todd Broch31c82502011-08-29 08:14:39 -0700160 retry += 1
161 time.sleep(Servo.SHORT_DELAY)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700162
163
164 def lid_open(self):
165 """Simulate opening the lid."""
Craig Harrison48997262011-06-27 14:31:10 -0700166 self.set_nocheck('lid_open', 'yes')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700167
168
169 def lid_close(self):
Craig Harrison48997262011-06-27 14:31:10 -0700170 """Simulate closing the lid.
171
172 Waits 6 seconds to ensure the device is fully asleep before returning.
173 """
174 self.set_nocheck('lid_open', 'no')
Chrome Bot9a1137d2011-07-19 14:35:00 -0700175 time.sleep(Servo.SLEEP_DELAY)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700176
177
Todd Broch9753bd42012-03-21 10:15:08 -0700178 def _press_and_release_keys(self, m1, m2,
179 press_secs=SERVO_SEND_SIGNAL_DELAY):
Todd Broch9dfc3a82011-11-01 08:09:28 -0700180 """Simulate button presses."""
Todd Broch9753bd42012-03-21 10:15:08 -0700181 # set keys to none
182 (m2_a1, m2_a0) = self.KEY_MATRIX['m2']['none']
183 (m1_a1, m1_a0) = self.KEY_MATRIX['m1']['none']
184 self.set_nocheck('kbd_m2_a0', m2_a0)
185 self.set_nocheck('kbd_m2_a1', m2_a1)
186 self.set_nocheck('kbd_m1_a0', m1_a0)
187 self.set_nocheck('kbd_m1_a1', m1_a1)
Todd Broch9dfc3a82011-11-01 08:09:28 -0700188
Todd Broch9753bd42012-03-21 10:15:08 -0700189 (m2_a1, m2_a0) = self.KEY_MATRIX['m2'][m2]
190 (m1_a1, m1_a0) = self.KEY_MATRIX['m1'][m1]
Todd Broch9dfc3a82011-11-01 08:09:28 -0700191 self.set_nocheck('kbd_en', 'on')
Todd Broch9753bd42012-03-21 10:15:08 -0700192 self.set_nocheck('kbd_m2_a0', m2_a0)
193 self.set_nocheck('kbd_m2_a1', m2_a1)
194 self.set_nocheck('kbd_m1_a0', m1_a0)
195 self.set_nocheck('kbd_m1_a1', m1_a1)
Todd Broch9dfc3a82011-11-01 08:09:28 -0700196 time.sleep(press_secs)
197 self.set_nocheck('kbd_en', 'off')
198
199
Chrome Bot9a1137d2011-07-19 14:35:00 -0700200 def ctrl_d(self):
201 """Simulate Ctrl-d simultaneous button presses."""
Todd Broch9dfc3a82011-11-01 08:09:28 -0700202 self._press_and_release_keys('d', 'ctrl')
203
204
Todd Broch9753bd42012-03-21 10:15:08 -0700205 def ctrl_enter(self):
206 """Simulate Ctrl-enter simultaneous button presses."""
207 self._press_and_release_keys('enter', 'ctrl')
208
209
Todd Broch9dfc3a82011-11-01 08:09:28 -0700210 def d_key(self):
211 """Simulate Enter key button press."""
212 self._press_and_release_keys('d', 'none')
213
214
215 def ctrl_key(self):
216 """Simulate Enter key button press."""
217 self._press_and_release_keys('none', 'ctrl')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700218
219
Chrome Bot9a1137d2011-07-19 14:35:00 -0700220 def enter_key(self):
221 """Simulate Enter key button press."""
Todd Broch9dfc3a82011-11-01 08:09:28 -0700222 self._press_and_release_keys('enter', 'none')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700223
224
Chrome Bot9a1137d2011-07-19 14:35:00 -0700225 def refresh_key(self):
226 """Simulate Refresh key (F3) button press."""
Todd Broch9dfc3a82011-11-01 08:09:28 -0700227 self._press_and_release_keys('none', 'refresh')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700228
229
Chrome Bot9a1137d2011-07-19 14:35:00 -0700230 def imaginary_key(self):
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700231 """Simulate imaginary key button press.
232
233 Maps to a key that doesn't physically exist.
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700234 """
Todd Broch9dfc3a82011-11-01 08:09:28 -0700235 self._press_and_release_keys('none', 'unused')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700236
237
Craig Harrison6b36b122011-06-28 17:58:43 -0700238 def enable_recovery_mode(self):
239 """Enable recovery mode on device."""
240 self.set('rec_mode', 'on')
241
242
243 def disable_recovery_mode(self):
244 """Disable recovery mode on device."""
245 self.set('rec_mode', 'off')
246
247
248 def enable_development_mode(self):
249 """Enable development mode on device."""
250 self.set('dev_mode', 'on')
251
252
253 def disable_development_mode(self):
254 """Disable development mode on device."""
255 self.set('dev_mode', 'off')
256
Chris Sosa8ee1d592011-08-14 16:50:31 -0700257 def enable_usb_hub(self, host=False):
Craig Harrison86b1a572011-08-12 11:26:52 -0700258 """Enable Servo's USB/ethernet hub.
259
Chris Sosa8ee1d592011-08-14 16:50:31 -0700260 This is equivalent to plugging in the USB devices attached to Servo to
261 the host (if |host| is True) or dut (if |host| is False).
262 For host=False, requires that the USB out on the servo board is
263 connected to a USB in port on the target device. Servo's USB ports are
264 labeled DUT_HUB_USB1 and DUT_HUB_USB2. Servo's ethernet port is also
265 connected to this hub. Servo's USB port DUT_HUB_IN is the output of the
266 hub.
Craig Harrison86b1a572011-08-12 11:26:52 -0700267 """
268 self.set('dut_hub_pwren', 'on')
Chris Sosa8ee1d592011-08-14 16:50:31 -0700269 if host:
Todd Broch9753bd42012-03-21 10:15:08 -0700270 self.set('usb_mux_oe1', 'on')
271 self.set('usb_mux_sel1', 'servo_sees_usbkey')
Chris Sosa8ee1d592011-08-14 16:50:31 -0700272 else:
Todd Broch9753bd42012-03-21 10:15:08 -0700273 self.set('dut_hub_sel', 'dut_sees_hub')
Chris Sosa8ee1d592011-08-14 16:50:31 -0700274
Craig Harrison86b1a572011-08-12 11:26:52 -0700275 self.set('dut_hub_on', 'yes')
276
277
278 def disable_usb_hub(self):
279 """Disable Servo's USB/ethernet hub.
280
281 This is equivalent to unplugging the USB devices attached to Servo.
282 """
283 self.set('dut_hub_on', 'no')
284
285
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700286 def boot_devmode(self):
287 """Boot a dev-mode device that is powered off."""
Tom Wai-Hong Tam23869102012-01-17 15:41:30 +0800288 self.power_short_press()
Craig Harrison48997262011-06-27 14:31:10 -0700289 self.pass_devmode()
290
291
292 def pass_devmode(self):
293 """Pass through boot screens in dev-mode."""
Chrome Bot9a1137d2011-07-19 14:35:00 -0700294 time.sleep(Servo.BOOT_DELAY)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700295 self.ctrl_d()
Chrome Bot9a1137d2011-07-19 14:35:00 -0700296 time.sleep(Servo.BOOT_DELAY)
Craig Harrison48997262011-06-27 14:31:10 -0700297
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700298
Craig Harrison6b36b122011-06-28 17:58:43 -0700299 def cold_reset(self):
300 """Perform a cold reset of the EC.
301
Chris Sosa8ee1d592011-08-14 16:50:31 -0700302 Has the side effect of shutting off the device. Device is guaranteed
303 to be off at the end of this call.
Craig Harrison6b36b122011-06-28 17:58:43 -0700304 """
305 self.set('cold_reset', 'on')
Chrome Bot9a1137d2011-07-19 14:35:00 -0700306 time.sleep(Servo.SERVO_SEND_SIGNAL_DELAY)
Craig Harrison6b36b122011-06-28 17:58:43 -0700307
308
309 def warm_reset(self):
310 """Perform a warm reset of the device.
311
312 Has the side effect of restarting the device.
313 """
314 self.set('warm_reset', 'on')
Chrome Bot9a1137d2011-07-19 14:35:00 -0700315 time.sleep(Servo.SERVO_SEND_SIGNAL_DELAY)
Craig Harrison6b36b122011-06-28 17:58:43 -0700316 self.set('warm_reset', 'off')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700317
318
319 def get(self, gpio_name):
320 """Get the value of a gpio from Servod."""
321 assert gpio_name
322 return self._server.get(gpio_name)
323
324
325 def set(self, gpio_name, gpio_value):
326 """Set and check the value of a gpio using Servod."""
Chrome Bot9a1137d2011-07-19 14:35:00 -0700327 self.set_nocheck(gpio_name, gpio_value)
Todd Brochcf7c6652012-02-24 13:03:59 -0800328 retry_count = Servo.GET_RETRY_MAX
329 while gpio_value != self.get(gpio_name) and retry_count:
330 logging.warn("%s != %s, retry %d", gpio_name, gpio_value,
331 retry_count)
332 retry_count -= 1
333 time.sleep(Servo.SHORT_DELAY)
334 if not retry_count:
335 assert gpio_value == self.get(gpio_name), \
336 'Servo failed to set %s to %s' % (gpio_name, gpio_value)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700337
338
339 def set_nocheck(self, gpio_name, gpio_value):
340 """Set the value of a gpio using Servod."""
341 assert gpio_name and gpio_value
Todd Broch9753bd42012-03-21 10:15:08 -0700342 logging.info('Setting %s to %s', gpio_name, gpio_value)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700343 self._server.set(gpio_name, gpio_value)
344
345
Jon Salzc88e5b62011-11-30 14:38:54 +0800346 # TODO(waihong) It may fail if multiple servo's are connected to the same
347 # host. Should look for a better way, like the USB serial name, to identify
348 # the USB device.
349 def probe_host_usb_dev(self):
350 """Probe the USB disk device plugged-in the servo from the host side.
351
352 It tries to switch the USB mux to make the host unable to see the
353 USB disk and compares the result difference.
354
355 This only works if the servo is attached to the local host.
356
357 Returns:
358 A string of USB disk path, like '/dev/sdb', or None if not existed.
359 """
360 cmd = 'ls /dev/sd[a-z]'
361 original_value = self.get('usb_mux_sel1')
362
363 # Make the host unable to see the USB disk.
364 if original_value != 'dut_sees_usbkey':
365 self.set('usb_mux_sel1', 'dut_sees_usbkey')
366 time.sleep(self.USB_DETECTION_DELAY)
367 no_usb_set = set(utils.system_output(cmd, ignore_status=True).split())
368
369 # Make the host able to see the USB disk.
370 self.set('usb_mux_sel1', 'servo_sees_usbkey')
371 time.sleep(self.USB_DETECTION_DELAY)
372 has_usb_set = set(utils.system_output(cmd, ignore_status=True).split())
373
374 # Back to its original value.
375 if original_value != 'servo_sees_usbkey':
376 self.set('usb_mux_sel1', original_value)
377 time.sleep(self.USB_DETECTION_DELAY)
378
379 diff_set = has_usb_set - no_usb_set
380 if len(diff_set) == 1:
381 return diff_set.pop()
382 else:
383 return None
384
385
Tom Wai-Hong Tama07115e2012-01-09 12:27:01 +0800386 def install_recovery_image(self, image_path=None, usb_dev=None,
Gilad Arnold9df73de2012-03-14 09:35:08 -0700387 wait_for_completion=True,
388 wait_timeout=RECOVERY_INSTALL_DELAY):
Jon Salzc88e5b62011-11-30 14:38:54 +0800389 """Install the recovery image specied by the path onto the DUT.
390
391 This method uses google recovery mode to install a recovery image
392 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 +0800393 board specified by the usb_dev. If no image path is specified
Jon Salzc88e5b62011-11-30 14:38:54 +0800394 we use the recovery image already on the usb image.
395
396 Args:
397 image_path: Path on the host to the recovery image.
Tom Wai-Hong Tama07115e2012-01-09 12:27:01 +0800398 usb_dev: When servo_sees_usbkey is enabled, which dev
399 e.g. /dev/sdb will the usb key show up as.
400 If None, detects it automatically.
Jon Salzc88e5b62011-11-30 14:38:54 +0800401 wait_for_completion: Whether to wait for completion of the
402 factory install and disable the USB hub
403 before returning. Currently this is just
Gilad Arnold9df73de2012-03-14 09:35:08 -0700404 waiting for a predetermined timeout period.
405 wait_timeout: How long to wait for completion; default is
406 determined by a constant.
Jon Salzc88e5b62011-11-30 14:38:54 +0800407 """
Gilad Arnold9df73de2012-03-14 09:35:08 -0700408 # Turn the device off. This should happen before USB key detection, to
409 # prevent a recovery destined DUT from sensing the USB key due to the
410 # autodetection procedure.
411 self.power_long_press()
412
Jon Salzc88e5b62011-11-30 14:38:54 +0800413 # Set up Servo's usb mux.
414 self.set('prtctl4_pwren', 'on')
415 self.enable_usb_hub(host=True)
Tom Wai-Hong Tama07115e2012-01-09 12:27:01 +0800416 if image_path:
417 if not usb_dev:
Gilad Arnold9df73de2012-03-14 09:35:08 -0700418 logging.info('Detecting USB stick device...')
Tom Wai-Hong Tama07115e2012-01-09 12:27:01 +0800419 usb_dev = self.probe_host_usb_dev()
Gilad Arnold9df73de2012-03-14 09:35:08 -0700420 if not usb_dev:
Todd Broch9753bd42012-03-21 10:15:08 -0700421 raise Exception('USB device not found')
422 logging.info('Found %s', usb_dev)
Tom Wai-Hong Tama07115e2012-01-09 12:27:01 +0800423 logging.info('Installing image onto usb stick. '
424 'This takes a while...')
425 client_utils.poll_for_condition(
426 lambda: os.path.exists(usb_dev),
427 timeout=Servo.USB_DETECTION_DELAY,
428 desc="%s exists" % usb_dev)
Gilad Arnold9df73de2012-03-14 09:35:08 -0700429 utils.system('sudo dd if=%s of=%s bs=4M status=noxfer' %
430 (image_path, usb_dev))
Jon Salzc88e5b62011-11-30 14:38:54 +0800431
432 # Boot in recovery mode.
433 try:
Jon Salzc88e5b62011-11-30 14:38:54 +0800434 self.enable_recovery_mode()
Tom Wai-Hong Tam23869102012-01-17 15:41:30 +0800435 self.power_short_press()
Jon Salzc88e5b62011-11-30 14:38:54 +0800436 time.sleep(Servo.RECOVERY_BOOT_DELAY)
Tom Wai-Hong Tam922ed052012-01-09 12:27:52 +0800437 self.set('usb_mux_sel1', 'dut_sees_usbkey')
Jon Salzc88e5b62011-11-30 14:38:54 +0800438 self.disable_recovery_mode()
439
440 if wait_for_completion:
441 # Enable recovery installation.
442 logging.info('Running the recovery process on the DUT. '
443 'Waiting %d seconds for recovery to complete ...',
Gilad Arnold9df73de2012-03-14 09:35:08 -0700444 wait_timeout)
445 time.sleep(wait_timeout)
Jon Salzc88e5b62011-11-30 14:38:54 +0800446
447 # Go back into normal mode and reboot.
448 # Machine automatically reboots after the usb key is removed.
449 logging.info('Removing the usb key from the DUT.')
450 self.disable_usb_hub()
451 time.sleep(Servo.BOOT_DELAY)
452 except:
453 # In case anything went wrong we want to make sure to do a clean
454 # reset.
455 self.disable_recovery_mode()
456 self.warm_reset()
457 raise
458
459
Craig Harrison6b36b122011-06-28 17:58:43 -0700460 def _init_seq_cold_reset_devmode(self):
461 """Cold reset, init device, and boot in dev-mode."""
462 self.cold_reset()
463 self._init_seq()
464 self.set('dev_mode', 'on')
465 self.boot_devmode()
466
467
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700468 def __del__(self):
469 """Kill the Servod process."""
Todd Brochf24d2782011-08-19 10:55:41 -0700470 if not self._servod:
471 return
472
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700473 # kill servod one way or another
474 try:
475 # won't work without superuser privileges
476 self._servod.terminate()
477 except:
478 # should work without superuser privileges
479 assert subprocess.call(['sudo', 'kill', str(self._servod.pid)])
480
481
Todd Brochf24d2782011-08-19 10:55:41 -0700482 def _launch_servod(self, servo_host, servo_port, xml_config, servo_vid,
Gilad Arnold9df73de2012-03-14 09:35:08 -0700483 servo_pid, servo_serial, servo_interfaces):
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700484 """Launch the servod process.
485
486 Args:
Todd Brochf24d2782011-08-19 10:55:41 -0700487 servo_host: Host to start servod listening on.
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700488 servo_port: Port to start servod listening on.
Tom Wai-Hong Tam5fc2c792011-11-03 13:05:39 +0800489 xml_config: A list of XML configuration files for servod.
Todd Broch5fd6bc02011-07-20 15:53:37 -0700490 servo_vid: USB vendor id of servo.
491 servo_pid: USB product id of servo.
492 servo_serial: USB serial id in device descriptor to host to
493 distinguish and control multiple servos. Note servo's EEPROM must
494 be programmed to use this feature.
Gilad Arnold9df73de2012-03-14 09:35:08 -0700495 servo_interfaces: a list of servo interface names out of 'gpio',
496 'i2c', 'uart', 'gpiouart' and 'dummy'.
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700497 """
Tom Wai-Hong Tam5fc2c792011-11-03 13:05:39 +0800498 cmdlist = ['sudo', 'servod']
499 for config in xml_config:
500 cmdlist += ['-c', str(config)]
Todd Broch96d83aa2011-08-29 14:37:38 -0700501 if servo_host is not None:
502 cmdlist.append('--host=%s' % str(servo_host))
503 if servo_port is not None:
504 cmdlist.append('--port=%s' % str(servo_port))
Todd Broch5fd6bc02011-07-20 15:53:37 -0700505 if servo_vid is not None:
Todd Brochf24d2782011-08-19 10:55:41 -0700506 cmdlist.append('--vendor=%s' % str(servo_vid))
Todd Broch5fd6bc02011-07-20 15:53:37 -0700507 if servo_pid is not None:
Todd Brochf24d2782011-08-19 10:55:41 -0700508 cmdlist.append('--product=%s' % str(servo_pid))
Todd Broch5fd6bc02011-07-20 15:53:37 -0700509 if servo_serial is not None:
Todd Brochf24d2782011-08-19 10:55:41 -0700510 cmdlist.append('--serialname=%s' % str(servo_serial))
Gilad Arnold9df73de2012-03-14 09:35:08 -0700511 if servo_interfaces:
512 cmdlist.append('--interfaces=%s' % ' '.join(servo_interfaces))
Todd Broch9753bd42012-03-21 10:15:08 -0700513 logging.info('starting servod w/ cmd :: %s', ' '.join(cmdlist))
Todd Broch5fd6bc02011-07-20 15:53:37 -0700514 self._servod = subprocess.Popen(cmdlist, 0, None, None, None,
515 subprocess.PIPE)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700516 # wait for servod to initialize
Chrome Bot9a1137d2011-07-19 14:35:00 -0700517 timeout = Servo.MAX_SERVO_STARTUP_DELAY
Todd Broch9753bd42012-03-21 10:15:08 -0700518 start_time = time.time()
519 listening = False
520 while (time.time() - start_time) < timeout and \
521 self._servod.returncode is None:
522 (rfds, _, _) = select.select([self._servod.stderr], [], [], 0)
523 if len(rfds) > 0:
524 if 'Listening' in rfds[0].readline():
525 listening = True
526 break
527
528 if not listening:
529 logging.fatal("Unable to successfully launch servod")
530 sys.exit(-1)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700531
532
533 def _init_seq(self):
534 """Initiate starting state for servo."""
Todd Broch9753bd42012-03-21 10:15:08 -0700535 # TODO(tbroch) This is only a servo V1 control. Need to add ability in
536 # servod to easily identify version so I can make this conditional not
537 # try and fail quietly
538 try:
539 self.set('tx_dir', 'input')
540 except:
541 logging.warning("Failed to set tx_dir. This is ok if not servo V1")
542
543
Todd Broch6ec29432011-12-19 14:32:02 -0800544 # TODO(tbroch) Investigate method to determine DUT's type so we can
545 # conditionally set lid if applicable
546 self.set_nocheck('lid_open', 'yes')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700547 self.set('rec_mode', 'off')
548
549
Todd Brochf24d2782011-08-19 10:55:41 -0700550 def _connect_servod(self, servo_host, servo_port):
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700551 """Connect to the Servod process with XMLRPC.
552
553 Args:
554 servo_port: Port the Servod process is listening on.
555 """
Todd Brochf24d2782011-08-19 10:55:41 -0700556 remote = 'http://%s:%s' % (servo_host, servo_port)
Todd Broch96d83aa2011-08-29 14:37:38 -0700557 self._server = xmlrpclib.ServerProxy(remote)
Todd Brochf24d2782011-08-19 10:55:41 -0700558 try:
559 self._server.echo("ping-test")
Todd Broch96d83aa2011-08-29 14:37:38 -0700560 except:
561 logging.error('Connection to servod failed')
Todd Brochf24d2782011-08-19 10:55:41 -0700562 raise