blob: b6fb96f943b541b2be19625aad8b45f2d5a7845d [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
Vadim Bendeburyb80ba592012-12-07 15:02:34 -08008import os
9
Vic Yang3a7cf602012-11-07 17:28:39 +080010import logging, re, time, xmlrpclib
Vadim Bendeburyb80ba592012-12-07 15:02:34 -080011
Simran Basi741b5d42012-05-18 11:27:15 -070012from autotest_lib.client.common_lib import error
Jon Salzc88e5b62011-11-30 14:38:54 +080013from autotest_lib.server import utils
J. Richard Barnette41320ee2013-03-11 13:00:13 -070014from autotest_lib.server.cros.servo import power_state_controller
J. Richard Barnette75487572013-03-08 12:47:50 -080015from autotest_lib.server.cros.servo import programmer
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070016
J. Richard Barnette41320ee2013-03-11 13:00:13 -070017
J. Richard Barnette384056b2012-04-16 11:04:46 -070018class Servo(object):
J. Richard Barnette41320ee2013-03-11 13:00:13 -070019
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070020 """Manages control of a Servo board.
21
22 Servo is a board developed by hardware group to aide in the debug and
23 control of various partner devices. Servo's features include the simulation
24 of pressing the power button, closing the lid, and pressing Ctrl-d. This
25 class manages setting up and communicating with a servo demon (servod)
26 process. It provides both high-level functions for common servo tasks and
27 low-level functions for directly setting and reading gpios.
J. Richard Barnette41320ee2013-03-11 13:00:13 -070028
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070029 """
30
Chrome Bot9a1137d2011-07-19 14:35:00 -070031 # Power button press delays in seconds.
J. Richard Barnetted2e4cbd2012-06-29 12:18:40 -070032 #
J. Richard Barnette5383f072012-07-26 17:35:40 -070033 # The EC specification says that 8.0 seconds should be enough
34 # for the long power press. However, some platforms need a bit
35 # more time. Empirical testing has found these requirements:
36 # Alex: 8.2 seconds
37 # ZGB: 8.5 seconds
38 # The actual value is set to the largest known necessary value.
39 #
40 # TODO(jrbarnette) Being generous is the right thing to do for
41 # existing platforms, but if this code is to be used for
42 # qualification of new hardware, we should be less generous.
Chrome Bot9a1137d2011-07-19 14:35:00 -070043 SHORT_DELAY = 0.1
J. Richard Barnette5383f072012-07-26 17:35:40 -070044
Todd Broch31c82502011-08-29 08:14:39 -070045 # Maximum number of times to re-read power button on release.
Todd Brochcf7c6652012-02-24 13:03:59 -080046 GET_RETRY_MAX = 10
Chrome Bot9a1137d2011-07-19 14:35:00 -070047
J. Richard Barnette5383f072012-07-26 17:35:40 -070048 # Delays to deal with DUT state transitions.
Chrome Bot9a1137d2011-07-19 14:35:00 -070049 SLEEP_DELAY = 6
50 BOOT_DELAY = 10
J. Richard Barnette41320ee2013-03-11 13:00:13 -070051
J. Richard Barnette41320ee2013-03-11 13:00:13 -070052 # Default minimum time interval between 'press' and 'release'
53 # keyboard events.
Vic Yang0aca1c22012-11-19 18:33:56 -080054 SERVO_KEY_PRESS_DELAY = 0.1
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070055
Jon Salzc88e5b62011-11-30 14:38:54 +080056 # Time between an usb disk plugged-in and detected in the system.
57 USB_DETECTION_DELAY = 10
Vadim Bendeburye7bd9362012-12-19 14:35:20 -080058 # Time to keep USB power off before and after USB mux direction is changed
59 USB_POWEROFF_DELAY = 2
Jon Salzc88e5b62011-11-30 14:38:54 +080060
Simran Basib7850bb2013-07-24 12:33:42 -070061 # Time to wait before timing out on servo initialization.
62 INIT_TIMEOUT_SECS = 10
Simran Basi59331342013-07-12 12:06:29 -070063
J. Richard Barnette67ccb872012-04-19 16:34:56 -070064
Fang Deng5d518f42013-08-02 14:04:32 -070065 def __init__(self, servo_host):
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070066 """Sets up the servo communication infrastructure.
67
Fang Deng5d518f42013-08-02 14:04:32 -070068 @param servo_host: A ServoHost object representing
69 the host running servod.
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070070 """
Fang Deng5d518f42013-08-02 14:04:32 -070071 # TODO(fdeng): crbug.com/298379
72 # We should move servo_host object out of servo object
73 # to minimize the dependencies on the rest of Autotest.
74 self._servo_host = servo_host
75 self._server = servo_host.get_servod_server_proxy()
76 board = self._server.get_board()
J. Richard Barnette75136b32013-03-26 13:38:44 -070077 self._power_state = (
78 power_state_controller.create_controller(self, board))
Gediminas Ramanauskasba352ad2012-11-09 09:43:32 -080079
Vadim Bendeburye7bd9362012-12-19 14:35:20 -080080 # a string, showing what interface (host or dut) the USB device is
81 # connected to.
Fang Dengafb88142013-05-30 17:44:31 -070082 self._usb_state = None
Vadim Bendeburye7bd9362012-12-19 14:35:20 -080083 self.set('dut_hub_pwren', 'on')
84 self.set('usb_mux_oe1', 'on')
Fang Dengafb88142013-05-30 17:44:31 -070085 self.switch_usbkey('off')
Vadim Bendeburye7bd9362012-12-19 14:35:20 -080086
Gediminas Ramanauskasba352ad2012-11-09 09:43:32 -080087
Tom Wai-Hong Tam22ee0e52013-04-03 13:36:39 +080088 def get_power_state_controller(self):
J. Richard Barnette75136b32013-03-26 13:38:44 -070089 """Return the power state controller for this Servo.
90
91 The power state controller provides board-independent
92 interfaces for reset, power-on, power-off operations.
93
94 """
95 return self._power_state
96
Fang Deng5d518f42013-08-02 14:04:32 -070097
J. Richard Barnetteb6133972012-07-19 17:13:55 -070098 def initialize_dut(self, cold_reset=False):
99 """Initializes a dut for testing purposes.
100
101 This sets various servo signals back to default values
102 appropriate for the target board. By default, if the DUT
103 is already on, it stays on. If the DUT is powered off
104 before initialization, its state afterward is unspecified.
105
J. Richard Barnetteb6133972012-07-19 17:13:55 -0700106 Rationale: Basic initialization of servo sets the lid open,
107 when there is a lid. This operation won't affect powered on
108 units; however, setting the lid open may power on a unit
J. Richard Barnette75136b32013-03-26 13:38:44 -0700109 that's off, depending on the board type and previous state
110 of the device.
111
112 If `cold_reset` is a true value, cold reset will be applied
113 to the DUT. Cold reset will force the DUT to power off;
114 however, the final state of the DUT depends on the board type.
J. Richard Barnetteb6133972012-07-19 17:13:55 -0700115
116 @param cold_reset If True, cold reset the device after
117 initialization.
118 """
119 self._server.hwinit()
120 if cold_reset:
J. Richard Barnette75136b32013-03-26 13:38:44 -0700121 self._power_state.cold_reset()
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700122
123
Tom Wai-Hong Tam1c86c7a2012-10-22 10:08:24 +0800124 def is_localhost(self):
125 """Is the servod hosted locally?
126
127 Returns:
128 True if local hosted; otherwise, False.
129 """
Fang Deng5d518f42013-08-02 14:04:32 -0700130 return self._servo_host.is_localhost()
Tom Wai-Hong Tam1c86c7a2012-10-22 10:08:24 +0800131
132
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700133 def power_long_press(self):
Chrome Bot9a1137d2011-07-19 14:35:00 -0700134 """Simulate a long power button press."""
J. Richard Barnettef12bff22012-07-18 14:41:06 -0700135 # After a long power press, the EC may ignore the next power
136 # button press (at least on Alex). To guarantee that this
137 # won't happen, we need to allow the EC one second to
138 # collect itself.
Yusuf Mohsinally103441a2014-01-14 15:25:44 -0800139 self._server.power_long_press()
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700140
141
142 def power_normal_press(self):
Chrome Bot9a1137d2011-07-19 14:35:00 -0700143 """Simulate a normal power button press."""
Yusuf Mohsinally103441a2014-01-14 15:25:44 -0800144 self._server.power_normal_press()
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700145
146
147 def power_short_press(self):
Chrome Bot9a1137d2011-07-19 14:35:00 -0700148 """Simulate a short power button press."""
Yusuf Mohsinally103441a2014-01-14 15:25:44 -0800149 self._server.power_short_press()
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700150
151
Yusuf Mohsinally103441a2014-01-14 15:25:44 -0800152 def power_key(self, press_secs=''):
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700153 """Simulate a power button press.
154
Yusuf Mohsinally103441a2014-01-14 15:25:44 -0800155 @param press_secs : Str. Time to press key.
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700156 """
Yusuf Mohsinally103441a2014-01-14 15:25:44 -0800157 self._server.power_key(press_secs)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700158
159
160 def lid_open(self):
161 """Simulate opening the lid."""
Craig Harrison48997262011-06-27 14:31:10 -0700162 self.set_nocheck('lid_open', 'yes')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700163
164
165 def lid_close(self):
Craig Harrison48997262011-06-27 14:31:10 -0700166 """Simulate closing the lid.
167
168 Waits 6 seconds to ensure the device is fully asleep before returning.
169 """
170 self.set_nocheck('lid_open', 'no')
Chrome Bot9a1137d2011-07-19 14:35:00 -0700171 time.sleep(Servo.SLEEP_DELAY)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700172
173
Yusuf Mohsinally103441a2014-01-14 15:25:44 -0800174 def ctrl_d(self, press_secs=''):
175 """Simulate Ctrl-d simultaneous button presses.
Gediminas Ramanauskasba352ad2012-11-09 09:43:32 -0800176
Yusuf Mohsinally103441a2014-01-14 15:25:44 -0800177 @param press_secs : Str. Time to press key.
Gediminas Ramanauskasba352ad2012-11-09 09:43:32 -0800178 """
Yusuf Mohsinally103441a2014-01-14 15:25:44 -0800179 self._server.ctrl_d(press_secs)
Gediminas Ramanauskas9da80f22012-11-14 12:59:43 -0800180
Gediminas Ramanauskasba352ad2012-11-09 09:43:32 -0800181
Yusuf Mohsinally103441a2014-01-14 15:25:44 -0800182 def ctrl_u(self):
183 """Simulate Ctrl-u simultaneous button presses.
184
185 @param press_secs : Str. Time to press key.
186 """
187 self._server.ctrl_u()
Todd Broch9dfc3a82011-11-01 08:09:28 -0700188
189
Yusuf Mohsinally103441a2014-01-14 15:25:44 -0800190 def ctrl_enter(self, press_secs=''):
191 """Simulate Ctrl-enter simultaneous button presses.
192
193 @param press_secs : Str. Time to press key.
194 """
195 self._server.ctrl_enter(press_secs)
Gediminas Ramanauskas3297d4f2012-09-10 15:30:10 -0700196
197
Yusuf Mohsinally103441a2014-01-14 15:25:44 -0800198 def d_key(self, press_secs=''):
199 """Simulate Enter key button press.
200
201 @param press_secs : Str. Time to press key.
202 """
203 self._server.d_key(press_secs)
Todd Broch9dfc3a82011-11-01 08:09:28 -0700204
205
Yusuf Mohsinally103441a2014-01-14 15:25:44 -0800206 def ctrl_key(self, press_secs=''):
207 """Simulate Enter key button press.
208
209 @param press_secs : Str. Time to press key.
210 """
211 self._server.ctrl_key(press_secs)
Todd Broch9753bd42012-03-21 10:15:08 -0700212
213
Yusuf Mohsinally103441a2014-01-14 15:25:44 -0800214 def enter_key(self, press_secs=''):
215 """Simulate Enter key button press.
216
217 @param press_secs : Str. Time to press key.
218 """
219 self._server.enter_key(press_secs)
Todd Broch9dfc3a82011-11-01 08:09:28 -0700220
221
Yusuf Mohsinally103441a2014-01-14 15:25:44 -0800222 def refresh_key(self, press_secs=''):
223 """Simulate Refresh key (F3) button press.
224
225 @param press_secs : Str. Time to press key.
226 """
227 self._server.refresh_key(press_secs)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700228
229
Yusuf Mohsinally103441a2014-01-14 15:25:44 -0800230 def ctrl_refresh_key(self, press_secs=''):
Tom Wai-Hong Tam9e61e662012-08-01 15:10:07 +0800231 """Simulate Ctrl and Refresh (F3) simultaneous press.
232
233 This key combination is an alternative of Space key.
Yusuf Mohsinally103441a2014-01-14 15:25:44 -0800234
235 @param press_secs : Str. Time to press key.
Tom Wai-Hong Tam9e61e662012-08-01 15:10:07 +0800236 """
Yusuf Mohsinally103441a2014-01-14 15:25:44 -0800237 self._server.ctrl_refresh_key(press_secs)
Tom Wai-Hong Tam9e61e662012-08-01 15:10:07 +0800238
239
Yusuf Mohsinally103441a2014-01-14 15:25:44 -0800240 def imaginary_key(self, press_secs=''):
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700241 """Simulate imaginary key button press.
242
243 Maps to a key that doesn't physically exist.
Yusuf Mohsinally103441a2014-01-14 15:25:44 -0800244
245 @param press_secs : Str. Time to press key.
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700246 """
Yusuf Mohsinally103441a2014-01-14 15:25:44 -0800247 self._server.imaginary_key(press_secs)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700248
249
Craig Harrison6b36b122011-06-28 17:58:43 -0700250 def enable_recovery_mode(self):
251 """Enable recovery mode on device."""
252 self.set('rec_mode', 'on')
253
254
Gediminas Ramanauskasba352ad2012-11-09 09:43:32 -0800255 def custom_recovery_mode(self):
256 """Custom key combination to enter recovery mode."""
257 self._press_keys('rec_mode')
258 self.power_normal_press()
259 time.sleep(self.SERVO_KEY_PRESS_DELAY)
260 self.set_nocheck('kbd_en', 'off')
261
262
Craig Harrison6b36b122011-06-28 17:58:43 -0700263 def disable_recovery_mode(self):
264 """Disable recovery mode on device."""
265 self.set('rec_mode', 'off')
266
267
268 def enable_development_mode(self):
269 """Enable development mode on device."""
270 self.set('dev_mode', 'on')
271
272
273 def disable_development_mode(self):
274 """Disable development mode on device."""
275 self.set('dev_mode', 'off')
276
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700277 def boot_devmode(self):
278 """Boot a dev-mode device that is powered off."""
Tom Wai-Hong Tam23869102012-01-17 15:41:30 +0800279 self.power_short_press()
Craig Harrison48997262011-06-27 14:31:10 -0700280 self.pass_devmode()
281
282
283 def pass_devmode(self):
284 """Pass through boot screens in dev-mode."""
Chrome Bot9a1137d2011-07-19 14:35:00 -0700285 time.sleep(Servo.BOOT_DELAY)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700286 self.ctrl_d()
Chrome Bot9a1137d2011-07-19 14:35:00 -0700287 time.sleep(Servo.BOOT_DELAY)
Craig Harrison48997262011-06-27 14:31:10 -0700288
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700289
Todd Brochefe72cb2012-07-11 19:58:53 -0700290 def _get_xmlrpclib_exception(self, xmlexc):
291 """Get meaningful exception string from xmlrpc.
292
293 Args:
294 xmlexc: xmlrpclib.Fault object
295
296 xmlrpclib.Fault.faultString has the following format:
297
298 <type 'exception type'>:'actual error message'
299
300 Parse and return the real exception from the servod side instead of the
301 less meaningful one like,
302 <Fault 1: "<type 'exceptions.AttributeError'>:'tca6416' object has no
303 attribute 'hw_driver'">
304
305 Returns:
306 string of underlying exception raised in servod.
307 """
308 return re.sub('^.*>:', '', xmlexc.faultString)
309
310
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700311 def get(self, gpio_name):
312 """Get the value of a gpio from Servod."""
313 assert gpio_name
Todd Brochefe72cb2012-07-11 19:58:53 -0700314 try:
Simran Basi1cbc5f22013-07-17 14:23:58 -0700315 return self._server.get(gpio_name)
Todd Brochefe72cb2012-07-11 19:58:53 -0700316 except xmlrpclib.Fault as e:
317 err_msg = "Getting '%s' :: %s" % \
318 (gpio_name, self._get_xmlrpclib_exception(e))
319 raise error.TestFail(err_msg)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700320
321
322 def set(self, gpio_name, gpio_value):
323 """Set and check the value of a gpio using Servod."""
Chrome Bot9a1137d2011-07-19 14:35:00 -0700324 self.set_nocheck(gpio_name, gpio_value)
Todd Brochcf7c6652012-02-24 13:03:59 -0800325 retry_count = Servo.GET_RETRY_MAX
326 while gpio_value != self.get(gpio_name) and retry_count:
327 logging.warn("%s != %s, retry %d", gpio_name, gpio_value,
328 retry_count)
329 retry_count -= 1
330 time.sleep(Servo.SHORT_DELAY)
331 if not retry_count:
332 assert gpio_value == self.get(gpio_name), \
333 'Servo failed to set %s to %s' % (gpio_name, gpio_value)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700334
335
336 def set_nocheck(self, gpio_name, gpio_value):
337 """Set the value of a gpio using Servod."""
338 assert gpio_name and gpio_value
Todd Broch9753bd42012-03-21 10:15:08 -0700339 logging.info('Setting %s to %s', gpio_name, gpio_value)
Todd Brochefe72cb2012-07-11 19:58:53 -0700340 try:
Simran Basi1cbc5f22013-07-17 14:23:58 -0700341 self._server.set(gpio_name, gpio_value)
Todd Brochefe72cb2012-07-11 19:58:53 -0700342 except xmlrpclib.Fault as e:
343 err_msg = "Setting '%s' to '%s' :: %s" % \
344 (gpio_name, gpio_value, self._get_xmlrpclib_exception(e))
345 raise error.TestFail(err_msg)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700346
347
Tom Wai-Hong Tam92569bb2013-03-26 14:25:10 +0800348 def set_get_all(self, controls):
349 """Set &| get one or more control values.
350
351 @param controls: list of strings, controls to set &| get.
352
353 @raise: error.TestError in case error occurs setting/getting values.
354 """
355 rv = []
356 try:
Vic Yangcad9acb2013-05-21 14:02:05 +0800357 logging.info('Set/get all: %s', str(controls))
Tom Wai-Hong Tam92569bb2013-03-26 14:25:10 +0800358 rv = self._server.set_get_all(controls)
359 except xmlrpclib.Fault as e:
360 # TODO(waihong): Remove the following backward compatibility when
361 # the new versions of hdctools are deployed.
362 if 'not supported' in str(e):
363 logging.warning('The servod is too old that set_get_all '
364 'not supported. Use set and get instead.')
365 for control in controls:
366 if ':' in control:
367 (name, value) = control.split(':')
368 if name == 'sleep':
369 time.sleep(float(value))
370 else:
371 self.set_nocheck(name, value)
372 rv.append(True)
373 else:
374 rv.append(self.get(name))
375 else:
376 err_msg = "Problem with '%s' :: %s" % \
377 (controls, self._get_xmlrpclib_exception(e))
378 raise error.TestFail(err_msg)
379 return rv
380
381
Jon Salzc88e5b62011-11-30 14:38:54 +0800382 # TODO(waihong) It may fail if multiple servo's are connected to the same
383 # host. Should look for a better way, like the USB serial name, to identify
384 # the USB device.
Simran Basi741b5d42012-05-18 11:27:15 -0700385 # TODO(sbasi) Remove this code from autoserv once firmware tests have been
386 # updated.
Jon Salzc88e5b62011-11-30 14:38:54 +0800387 def probe_host_usb_dev(self):
388 """Probe the USB disk device plugged-in the servo from the host side.
389
390 It tries to switch the USB mux to make the host unable to see the
391 USB disk and compares the result difference.
392
Jon Salzc88e5b62011-11-30 14:38:54 +0800393 Returns:
394 A string of USB disk path, like '/dev/sdb', or None if not existed.
395 """
396 cmd = 'ls /dev/sd[a-z]'
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800397 original_value = self.get_usbkey_direction()
Jon Salzc88e5b62011-11-30 14:38:54 +0800398
399 # Make the host unable to see the USB disk.
Fang Dengafb88142013-05-30 17:44:31 -0700400 self.switch_usbkey('off')
Vadim Bendebury89ec24e2012-12-17 12:54:18 -0800401 no_usb_set = set(self.system_output(cmd, ignore_status=True).split())
Jon Salzc88e5b62011-11-30 14:38:54 +0800402
403 # Make the host able to see the USB disk.
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800404 self.switch_usbkey('host')
Vadim Bendebury89ec24e2012-12-17 12:54:18 -0800405 has_usb_set = set(self.system_output(cmd, ignore_status=True).split())
Jon Salzc88e5b62011-11-30 14:38:54 +0800406
407 # Back to its original value.
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800408 if original_value != self.get_usbkey_direction():
409 self.switch_usbkey(original_value)
Jon Salzc88e5b62011-11-30 14:38:54 +0800410
411 diff_set = has_usb_set - no_usb_set
412 if len(diff_set) == 1:
413 return diff_set.pop()
414 else:
415 return None
416
417
J. Richard Barnette69929a52013-03-15 13:22:11 -0700418 def recovery_supported(self):
419 """Return whether servo-based recovery should work.
420
421 Use of `image_to_servo_usb()` and `install_recovery_image()`
422 relies on DUT-board specific behaviors, and is not supported
423 for all types of board. Return whether these two operations
424 are expected to succeed for the current DUT.
425
426 @return `True` iff the recovery related methods are supported
427 for this servo and DUT.
428
429 """
J. Richard Barnette75136b32013-03-26 13:38:44 -0700430 return self._power_state.recovery_supported()
J. Richard Barnette69929a52013-03-15 13:22:11 -0700431
432
Mike Truty49153d82012-08-21 22:27:30 -0500433 def image_to_servo_usb(self, image_path=None,
434 make_image_noninteractive=False):
435 """Install an image to the USB key plugged into the servo.
436
437 This method may copy any image to the servo USB key including a
438 recovery image or a test image. These images are frequently used
439 for test purposes such as restoring a corrupted image or conducting
440 an upgrade of ec/fw/kernel as part of a test of a specific image part.
441
442 Args:
443 image_path: Path on the host to the recovery image.
444 make_image_noninteractive: Make the recovery image noninteractive,
445 therefore the DUT will reboot
446 automatically after installation.
447 """
J. Richard Barnette41320ee2013-03-11 13:00:13 -0700448 # We're about to start plugging/unplugging the USB key. We
449 # don't know the state of the DUT, or what it might choose
450 # to do to the device after hotplug. To avoid surprises,
451 # force the DUT to be off.
452 self._server.hwinit()
453 self._power_state.power_off()
Mike Truty49153d82012-08-21 22:27:30 -0500454
455 # Set up Servo's usb mux.
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800456 self.switch_usbkey('host')
Mike Truty49153d82012-08-21 22:27:30 -0500457 if image_path:
Tom Wai-Hong Tam42f136d2012-10-26 11:11:23 +0800458 logging.info('Searching for usb device and copying image to it. '
459 'Please wait a few minutes...')
Mike Truty49153d82012-08-21 22:27:30 -0500460 if not self._server.download_image_to_usb(image_path):
461 logging.error('Failed to transfer requested image to USB. '
462 'Please take a look at Servo Logs.')
463 raise error.AutotestError('Download image to usb failed.')
464 if make_image_noninteractive:
465 logging.info('Making image noninteractive')
466 if not self._server.make_image_noninteractive():
467 logging.error('Failed to make image noninteractive. '
468 'Please take a look at Servo Logs.')
469
470
Simran Basi741b5d42012-05-18 11:27:15 -0700471 def install_recovery_image(self, image_path=None,
J. Richard Barnetteb6de7e32013-02-14 13:28:04 -0800472 make_image_noninteractive=False):
Jon Salzc88e5b62011-11-30 14:38:54 +0800473 """Install the recovery image specied by the path onto the DUT.
474
475 This method uses google recovery mode to install a recovery image
476 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 +0800477 board specified by the usb_dev. If no image path is specified
Jon Salzc88e5b62011-11-30 14:38:54 +0800478 we use the recovery image already on the usb image.
479
480 Args:
481 image_path: Path on the host to the recovery image.
Simran Basi741b5d42012-05-18 11:27:15 -0700482 make_image_noninteractive: Make the recovery image noninteractive,
483 therefore the DUT will reboot
484 automatically after installation.
Jon Salzc88e5b62011-11-30 14:38:54 +0800485 """
Mike Truty49153d82012-08-21 22:27:30 -0500486 self.image_to_servo_usb(image_path, make_image_noninteractive)
J. Richard Barnette75136b32013-03-26 13:38:44 -0700487 self._power_state.power_on(rec_mode=power_state_controller.REC_ON)
J. Richard Barnette41320ee2013-03-11 13:00:13 -0700488 self.switch_usbkey('dut')
Jon Salzc88e5b62011-11-30 14:38:54 +0800489
490
Vadim Bendeburyb80ba592012-12-07 15:02:34 -0800491 def _scp_image(self, image_path):
492 """Copy image to the servo host.
493
494 When programming a firmware image on the DUT, the image must be
495 located on the host to which the servo device is connected. Sometimes
496 servo is controlled by a remote host, in this case the image needs to
497 be transferred to the remote host.
498
499 @param image_path: a string, name of the firmware image file to be
500 transferred.
501 @return: a string, full path name of the copied file on the remote.
502 """
503
504 dest_path = os.path.join('/tmp', os.path.basename(image_path))
Fang Deng5d518f42013-08-02 14:04:32 -0700505 self._servo_host.send_file(image_path, dest_path)
Vadim Bendeburyb80ba592012-12-07 15:02:34 -0800506 return dest_path
507
508
Vadim Bendebury89ec24e2012-12-17 12:54:18 -0800509 def system(self, command, timeout=None):
Vadim Bendeburyb80ba592012-12-07 15:02:34 -0800510 """Execute the passed in command on the servod host."""
Vadim Bendebury89ec24e2012-12-17 12:54:18 -0800511 logging.info('Will execute on servo host: %s', command)
Fang Deng5d518f42013-08-02 14:04:32 -0700512 self._servo_host.run(command, timeout=timeout)
Vadim Bendebury89ec24e2012-12-17 12:54:18 -0800513
514
515 def system_output(self, command, timeout=None,
516 ignore_status=False, args=()):
517 """Execute the passed in command on the servod host, return stdout.
518
519 @param command, a string, the command to execute
520 @param timeout, an int, max number of seconds to wait til command
521 execution completes
522 @ignore_status, a Boolean, if true - ignore command's nonzero exit
523 status, otherwise an exception will be thrown
524 @param args, a tuple of strings, each becoming a separate command line
525 parameter for the command
526 @return: command's stdout as a string.
527 """
Vadim Bendebury89ec24e2012-12-17 12:54:18 -0800528 logging.info('Will execute and collect output on servo host: %s %s',
529 command, ' '.join("'%s'" % x for x in args))
Fang Deng5d518f42013-08-02 14:04:32 -0700530 return self._servo_host.run(command, timeout=timeout,
531 ignore_status=ignore_status,
532 args=args).stdout.strip()
Vadim Bendeburyb80ba592012-12-07 15:02:34 -0800533
534
535 def program_ec(self, board, image):
Vadim Bendebury1a7ec632013-02-17 16:22:09 -0800536 """Program EC on a given board using given image.
537
538 @param board: a string, type of the DUT board
539 @param image: a string, file name of the EC image to program on the
540 DUT
541 """
Vadim Bendeburyb80ba592012-12-07 15:02:34 -0800542 if not self.is_localhost():
543 image = self._scp_image(image)
544 programmer.program_ec(board, self, image)
545
546
547 def program_bootprom(self, board, image):
Vadim Bendebury1a7ec632013-02-17 16:22:09 -0800548 """Program bootprom on a given board using given image.
549
550 In case servo is controlled by a remote host, the image needs to be
551 transferred to the host.
552
553 If the device tree subdirectory is present along with the image, the
554 subdirectory is also copied to the remote host.
555
556 @param board: a string, type of the DUT board
557 @param image: a string, file name of the firmware image to program on
558 the DUT. The device tree subdirectory, if present, is on
559 the same level with the image file.
560 """
Vadim Bendeburyb80ba592012-12-07 15:02:34 -0800561 if not self.is_localhost():
Vadim Bendebury1a7ec632013-02-17 16:22:09 -0800562 dts_path = os.path.join(os.path.dirname(image), 'dts')
Vadim Bendeburyb80ba592012-12-07 15:02:34 -0800563 image = self._scp_image(image)
Vadim Bendebury1a7ec632013-02-17 16:22:09 -0800564 if os.path.isdir(dts_path):
565 self._scp_image(dts_path)
Vadim Bendeburyb80ba592012-12-07 15:02:34 -0800566 programmer.program_bootprom(board, self, image)
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800567
Fang Dengafb88142013-05-30 17:44:31 -0700568
569 def _switch_usbkey_power(self, power_state, detection_delay=False):
570 """Switch usbkey power.
571
572 This function switches usbkey power by setting the value of
573 'prtctl4_pwren'. If the power is already in the
574 requested state, this function simply returns.
575
576 @param power_state: A string, 'on' or 'off'.
577 @param detection_delay: A boolean value, if True, sleep
578 for |USB_DETECTION_DELAY| after switching
579 the power on.
580 """
581 self.set('prtctl4_pwren', power_state)
582 if power_state == 'off':
583 time.sleep(self.USB_POWEROFF_DELAY)
584 elif detection_delay:
585 time.sleep(self.USB_DETECTION_DELAY)
586
587
588 def switch_usbkey(self, usb_state):
589 """Connect USB flash stick to either host or DUT, or turn USB port off.
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800590
591 This function switches the servo multiplexer to provide electrical
Fang Dengafb88142013-05-30 17:44:31 -0700592 connection between the USB port J3 and either host or DUT side. It
593 can also be used to turn the USB port off.
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800594
Fang Dengafb88142013-05-30 17:44:31 -0700595 Switching to 'dut' or 'host' is accompanied by powercycling
596 of the USB stick, because it sometimes gets wedged if the mux
597 is switched while the stick power is on.
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800598
Fang Dengafb88142013-05-30 17:44:31 -0700599 @param usb_state: A string, one of 'dut', 'host', or 'off'.
600 'dut' and 'host' indicate which side the
601 USB flash device is required to be connected to.
602 'off' indicates turning the USB port off.
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800603
Fang Dengafb88142013-05-30 17:44:31 -0700604 @raise: error.TestError in case the parameter is not 'dut'
605 'host', or 'off'.
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800606 """
Fang Dengafb88142013-05-30 17:44:31 -0700607 if self.get_usbkey_direction() == usb_state:
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800608 return
609
Fang Dengafb88142013-05-30 17:44:31 -0700610 if usb_state == 'off':
611 self._switch_usbkey_power('off')
612 self._usb_state = usb_state
613 return
614 elif usb_state == 'host':
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800615 mux_direction = 'servo_sees_usbkey'
Fang Dengafb88142013-05-30 17:44:31 -0700616 elif usb_state == 'dut':
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800617 mux_direction = 'dut_sees_usbkey'
618 else:
Fang Dengafb88142013-05-30 17:44:31 -0700619 raise error.TestError('Unknown USB state request: %s' % usb_state)
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800620
Fang Dengafb88142013-05-30 17:44:31 -0700621 self._switch_usbkey_power('off')
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800622 self.set('usb_mux_sel1', mux_direction)
623 time.sleep(self.USB_POWEROFF_DELAY)
Fang Dengafb88142013-05-30 17:44:31 -0700624 self._switch_usbkey_power('on', usb_state == 'host')
625 self._usb_state = usb_state
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800626
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800627
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800628 def get_usbkey_direction(self):
Fang Dengafb88142013-05-30 17:44:31 -0700629 """Get which side USB is connected to or 'off' if usb power is off.
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800630
Fang Dengafb88142013-05-30 17:44:31 -0700631 @return: A string, one of 'dut', 'host', or 'off'.
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800632 """
Fang Dengafb88142013-05-30 17:44:31 -0700633 if not self._usb_state:
634 if self.get('prtctl4_pwren') == 'off':
635 self._usb_state = 'off'
636 elif self.get('usb_mux_sel1').startswith('dut'):
637 self._usb_state = 'dut'
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800638 else:
Fang Dengafb88142013-05-30 17:44:31 -0700639 self._usb_state = 'host'
640 return self._usb_state