blob: fed97ceb40e4283abcc7c474051456b8ddcdb7cf [file] [log] [blame]
Craig Harrison2b6c6fc2011-06-23 10:34:02 -07001# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
2# 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
8
Todd Broch5fd6bc02011-07-20 15:53:37 -07009import logging
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070010import time
11import xmlrpclib
12import subprocess
13
14
15class Servo:
16 """Manages control of a Servo board.
17
18 Servo is a board developed by hardware group to aide in the debug and
19 control of various partner devices. Servo's features include the simulation
20 of pressing the power button, closing the lid, and pressing Ctrl-d. This
21 class manages setting up and communicating with a servo demon (servod)
22 process. It provides both high-level functions for common servo tasks and
23 low-level functions for directly setting and reading gpios.
24 """
25
26 _server = None
27 _servod = None
28
Chrome Bot9a1137d2011-07-19 14:35:00 -070029 # Power button press delays in seconds.
30 LONG_DELAY = 8
31 SHORT_DELAY = 0.1
32 NORMAL_TRANSITION_DELAY = 1.2
33
34 # Delays to deal with computer transitions.
35 SLEEP_DELAY = 6
36 BOOT_DELAY = 10
37
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
Todd Broch5fd6bc02011-07-20 15:53:37 -070042 def __init__(self, servo_port, xml_config='servo.xml', servo_vid=None,
43 servo_pid=None, servo_serial=None, cold_reset=False):
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070044 """Sets up the servo communication infrastructure.
45
46 Args:
47 servo_port: Port the servod process should listen on.
48 xml_config: Configuration XML file for servod.
Todd Broch5fd6bc02011-07-20 15:53:37 -070049 servo_vid: USB vendor id of servo.
50 servo_pid: USB product id of servo.
51 servo_serial: USB serial id in device descriptor to host to
52 distinguish and control multiple servos. Note servo's EEPROM must
53 be programmed to use this feature.
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070054 cold_reset: If True, cold reset device and boot during init,
55 otherwise perform init with device running.
56 """
57 # launch servod
Todd Broch5fd6bc02011-07-20 15:53:37 -070058 self._launch_servod(servo_port, xml_config, servo_vid, servo_pid,
59 servo_serial)
60
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070061
62 # connect to servod
63 assert servo_port
64
Chrome Bot9a1137d2011-07-19 14:35:00 -070065 self._do_cold_reset = cold_reset
66
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070067 self._connect_servod(servo_port)
Chrome Bot9a1137d2011-07-19 14:35:00 -070068
69
70 def initialize_dut(self):
71 """Initializes a dut for testing purposes."""
72 if self._do_cold_reset:
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070073 self._init_seq_cold_reset_devmode()
74 else:
75 self._init_seq()
76
77
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070078 def power_long_press(self):
Chrome Bot9a1137d2011-07-19 14:35:00 -070079 """Simulate a long power button press."""
80 self.power_key(Servo.LONG_DELAY)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070081
82
83 def power_normal_press(self):
Chrome Bot9a1137d2011-07-19 14:35:00 -070084 """Simulate a normal power button press."""
85 self.power_key()
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070086
87
88 def power_short_press(self):
Chrome Bot9a1137d2011-07-19 14:35:00 -070089 """Simulate a short power button press."""
90 self.power_key(Servo.SHORT_DELAY)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070091
92
Chrome Bot9a1137d2011-07-19 14:35:00 -070093 def power_key(self, secs=NORMAL_TRANSITION_DELAY):
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070094 """Simulate a power button press.
95
96 Args:
97 secs: Time in seconds to simulate the keypress.
98 """
Craig Harrison6b36b122011-06-28 17:58:43 -070099 self.set_nocheck('pwr_button', 'press')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700100 time.sleep(secs)
101 self.set('pwr_button', 'release')
102
103
104 def lid_open(self):
105 """Simulate opening the lid."""
Craig Harrison48997262011-06-27 14:31:10 -0700106 self.set_nocheck('lid_open', 'yes')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700107
108
109 def lid_close(self):
Craig Harrison48997262011-06-27 14:31:10 -0700110 """Simulate closing the lid.
111
112 Waits 6 seconds to ensure the device is fully asleep before returning.
113 """
114 self.set_nocheck('lid_open', 'no')
Chrome Bot9a1137d2011-07-19 14:35:00 -0700115 time.sleep(Servo.SLEEP_DELAY)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700116
117
Chrome Bot9a1137d2011-07-19 14:35:00 -0700118 def ctrl_d(self):
119 """Simulate Ctrl-d simultaneous button presses."""
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700120 self.set_nocheck('kbd_en', 'on')
121 self.set_nocheck('kbd_m1', 'r2_c2')
122 self.set_nocheck('kbd_m2', 'r1_c1')
Chrome Bot9a1137d2011-07-19 14:35:00 -0700123 time.sleep(Servo.SERVO_SEND_SIGNAL_DELAY)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700124 self.set_nocheck('kbd_en', 'off')
125
126
Chrome Bot9a1137d2011-07-19 14:35:00 -0700127 def enter_key(self):
128 """Simulate Enter key button press."""
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700129 self.set_nocheck('kbd_en', 'on')
130 self.set_nocheck('kbd_m1', 'r3_c2')
Chrome Bot9a1137d2011-07-19 14:35:00 -0700131 time.sleep(Servo.SERVO_SEND_SIGNAL_DELAY)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700132 self.set_nocheck('kbd_en', 'off')
133
134
Chrome Bot9a1137d2011-07-19 14:35:00 -0700135 def refresh_key(self):
136 """Simulate Refresh key (F3) button press."""
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700137 self.set_nocheck('kbd_en', 'on')
138 self.set_nocheck('kbd_m2', 'r2_c1')
Chrome Bot9a1137d2011-07-19 14:35:00 -0700139 time.sleep(Servo.SERVO_SEND_SIGNAL_DELAY)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700140 self.set_nocheck('kbd_en', 'off')
141
142
Chrome Bot9a1137d2011-07-19 14:35:00 -0700143 def imaginary_key(self):
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700144 """Simulate imaginary key button press.
145
146 Maps to a key that doesn't physically exist.
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700147 """
148 self.set_nocheck('kbd_en', 'on')
149 self.set_nocheck('kbd_m2', 'r3_c1')
Chrome Bot9a1137d2011-07-19 14:35:00 -0700150 time.sleep(Servo.SERVO_SEND_SIGNAL_DELAY)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700151 self.set_nocheck('kbd_en', 'off')
152
153
Craig Harrison6b36b122011-06-28 17:58:43 -0700154 def enable_recovery_mode(self):
155 """Enable recovery mode on device."""
156 self.set('rec_mode', 'on')
157
158
159 def disable_recovery_mode(self):
160 """Disable recovery mode on device."""
161 self.set('rec_mode', 'off')
162
163
164 def enable_development_mode(self):
165 """Enable development mode on device."""
166 self.set('dev_mode', 'on')
167
168
169 def disable_development_mode(self):
170 """Disable development mode on device."""
171 self.set('dev_mode', 'off')
172
173
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700174 def boot_devmode(self):
175 """Boot a dev-mode device that is powered off."""
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700176 self.power_normal_press()
Craig Harrison48997262011-06-27 14:31:10 -0700177 self.pass_devmode()
178
179
180 def pass_devmode(self):
181 """Pass through boot screens in dev-mode."""
Chrome Bot9a1137d2011-07-19 14:35:00 -0700182 time.sleep(Servo.BOOT_DELAY)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700183 self.ctrl_d()
Chrome Bot9a1137d2011-07-19 14:35:00 -0700184 time.sleep(Servo.BOOT_DELAY)
Craig Harrison48997262011-06-27 14:31:10 -0700185
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700186
Craig Harrison6b36b122011-06-28 17:58:43 -0700187 def cold_reset(self):
188 """Perform a cold reset of the EC.
189
190 Has the side effect of shutting off the device.
191 """
192 self.set('cold_reset', 'on')
Chrome Bot9a1137d2011-07-19 14:35:00 -0700193 time.sleep(Servo.SERVO_SEND_SIGNAL_DELAY)
Craig Harrison6b36b122011-06-28 17:58:43 -0700194 self.set('cold_reset', 'off')
195
196
197 def warm_reset(self):
198 """Perform a warm reset of the device.
199
200 Has the side effect of restarting the device.
201 """
202 self.set('warm_reset', 'on')
Chrome Bot9a1137d2011-07-19 14:35:00 -0700203 time.sleep(Servo.SERVO_SEND_SIGNAL_DELAY)
Craig Harrison6b36b122011-06-28 17:58:43 -0700204 self.set('warm_reset', 'off')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700205
206
207 def get(self, gpio_name):
208 """Get the value of a gpio from Servod."""
209 assert gpio_name
210 return self._server.get(gpio_name)
211
212
213 def set(self, gpio_name, gpio_value):
214 """Set and check the value of a gpio using Servod."""
Chrome Bot9a1137d2011-07-19 14:35:00 -0700215 self.set_nocheck(gpio_name, gpio_value)
216 assert gpio_value == self.get(gpio_name), \
217 'Servo failed to set %s to %s' % (gpio_name, gpio_value)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700218
219
220 def set_nocheck(self, gpio_name, gpio_value):
221 """Set the value of a gpio using Servod."""
222 assert gpio_name and gpio_value
Chrome Bot9a1137d2011-07-19 14:35:00 -0700223 logging.info('Setting %s to %s' % (gpio_name, gpio_value))
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700224 self._server.set(gpio_name, gpio_value)
225
226
Craig Harrison6b36b122011-06-28 17:58:43 -0700227 def _init_seq_cold_reset_devmode(self):
228 """Cold reset, init device, and boot in dev-mode."""
229 self.cold_reset()
230 self._init_seq()
231 self.set('dev_mode', 'on')
232 self.boot_devmode()
233
234
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700235 def __del__(self):
236 """Kill the Servod process."""
237 assert self._servod
238 # kill servod one way or another
239 try:
240 # won't work without superuser privileges
241 self._servod.terminate()
242 except:
243 # should work without superuser privileges
244 assert subprocess.call(['sudo', 'kill', str(self._servod.pid)])
245
246
Todd Broch5fd6bc02011-07-20 15:53:37 -0700247 def _launch_servod(self, servo_port, xml_config, servo_vid, servo_pid,
248 servo_serial):
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700249 """Launch the servod process.
250
251 Args:
252 servo_port: Port to start servod listening on.
253 xml_config: XML configuration file for servod.
Todd Broch5fd6bc02011-07-20 15:53:37 -0700254 servo_vid: USB vendor id of servo.
255 servo_pid: USB product id of servo.
256 servo_serial: USB serial id in device descriptor to host to
257 distinguish and control multiple servos. Note servo's EEPROM must
258 be programmed to use this feature.
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700259 """
Todd Broch5fd6bc02011-07-20 15:53:37 -0700260 cmdlist = ['sudo', 'servod', '-c', str(xml_config), '--host=localhost',
261 '--port=' + str(servo_port)]
262 if servo_vid is not None:
263 cmdlist.append('--vendor=%s' % str(servo_vid))
264 if servo_pid is not None:
265 cmdlist.append('--product=%s' % str(servo_pid))
266 if servo_serial is not None:
267 cmdlist.append('--serialname=%s' % str(servo_serial))
268 logging.info('starting servod w/ cmd :: %s' % ' '.join(cmdlist))
269 self._servod = subprocess.Popen(cmdlist, 0, None, None, None,
270 subprocess.PIPE)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700271 # wait for servod to initialize
Chrome Bot9a1137d2011-07-19 14:35:00 -0700272 timeout = Servo.MAX_SERVO_STARTUP_DELAY
273 while ('Listening' not in self._servod.stderr.readline() and
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700274 self._servod.returncode is None and timeout > 0):
275 time.sleep(1)
276 timeout -= 1
277 assert self._servod.returncode is None and timeout
278
279
280 def _init_seq(self):
281 """Initiate starting state for servo."""
282 self.set('tx_dir', 'input')
283 self.set('servo_dut_tx', 'off')
284 self.set('lid_open', 'yes')
285 self.set('rec_mode', 'off')
286
287
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700288 def _connect_servod(self, servo_port=''):
289 """Connect to the Servod process with XMLRPC.
290
291 Args:
292 servo_port: Port the Servod process is listening on.
293 """
294 remote = 'http://localhost:%s' % servo_port
295 self._server = xmlrpclib.ServerProxy(remote)