blob: 5237527eca1ac2ec32fbdf497ed667b624eb3a49 [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
9import time
10import xmlrpclib
11import subprocess
12
13
14class Servo:
15 """Manages control of a Servo board.
16
17 Servo is a board developed by hardware group to aide in the debug and
18 control of various partner devices. Servo's features include the simulation
19 of pressing the power button, closing the lid, and pressing Ctrl-d. This
20 class manages setting up and communicating with a servo demon (servod)
21 process. It provides both high-level functions for common servo tasks and
22 low-level functions for directly setting and reading gpios.
23 """
24
25 _server = None
26 _servod = None
27
28
29 def __init__(self, servo_port, xml_config='servo.xml', cold_reset=False):
30 """Sets up the servo communication infrastructure.
31
32 Args:
33 servo_port: Port the servod process should listen on.
34 xml_config: Configuration XML file for servod.
35 cold_reset: If True, cold reset device and boot during init,
36 otherwise perform init with device running.
37 """
38 # launch servod
39 self._launch_servod(servo_port, xml_config)
40
41 # connect to servod
42 assert servo_port
43
44 self._connect_servod(servo_port)
45 if cold_reset:
46 self._init_seq_cold_reset_devmode()
47 else:
48 self._init_seq()
49
50
51
52 def power_long_press(self):
53 """Simulate a long (8 sec) power button press."""
54 self.power_key(8)
55
56
57 def power_normal_press(self):
Craig Harrison6b36b122011-06-28 17:58:43 -070058 """Simulate a normal (2 sec) power button press."""
59 self.power_key(2)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070060
61
62 def power_short_press(self):
63 """Simulate a short (0.1 sec) power button press."""
64 self.power_key(0.1)
65
66
67 def power_key(self, secs=1):
68 """Simulate a power button press.
69
70 Args:
71 secs: Time in seconds to simulate the keypress.
72 """
Craig Harrison6b36b122011-06-28 17:58:43 -070073 self.set_nocheck('pwr_button', 'press')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070074 time.sleep(secs)
75 self.set('pwr_button', 'release')
76
77
78 def lid_open(self):
79 """Simulate opening the lid."""
Craig Harrison48997262011-06-27 14:31:10 -070080 self.set_nocheck('lid_open', 'yes')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070081
82
83 def lid_close(self):
Craig Harrison48997262011-06-27 14:31:10 -070084 """Simulate closing the lid.
85
86 Waits 6 seconds to ensure the device is fully asleep before returning.
87 """
88 self.set_nocheck('lid_open', 'no')
89 time.sleep(6)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070090
91
92 def ctrl_d(self, secs=0.5):
93 """Simulate Ctrl-d simultaneous button presses.
94
95 Args:
96 secs: Time in seconds to simulate the keypress.
97 """
98 self.set_nocheck('kbd_en', 'on')
99 self.set_nocheck('kbd_m1', 'r2_c2')
100 self.set_nocheck('kbd_m2', 'r1_c1')
101 time.sleep(secs)
102 self.set_nocheck('kbd_en', 'off')
103
104
105 def enter_key(self, secs=0.5):
106 """Simulate Enter key button press.
107
108 Args:
109 secs: Time in seconds to simulate the keypress.
110 """
111 self.set_nocheck('kbd_en', 'on')
112 self.set_nocheck('kbd_m1', 'r3_c2')
113 time.sleep(secs)
114 self.set_nocheck('kbd_en', 'off')
115
116
117 def refresh_key(self, secs=0.5):
118 """Simulate Refresh key (F3) button press.
119
120 Args:
121 secs: Time in seconds to simulate the keypress.
122 """
123 self.set_nocheck('kbd_en', 'on')
124 self.set_nocheck('kbd_m2', 'r2_c1')
125 time.sleep(secs)
126 self.set_nocheck('kbd_en', 'off')
127
128
129 def imaginary_key(self, secs=0.5):
130 """Simulate imaginary key button press.
131
132 Maps to a key that doesn't physically exist.
133
134 Args:
135 secs: Time in seconds to simulate the keypress.
136 """
137 self.set_nocheck('kbd_en', 'on')
138 self.set_nocheck('kbd_m2', 'r3_c1')
139 time.sleep(secs)
140 self.set_nocheck('kbd_en', 'off')
141
142
Craig Harrison6b36b122011-06-28 17:58:43 -0700143 def enable_recovery_mode(self):
144 """Enable recovery mode on device."""
145 self.set('rec_mode', 'on')
146
147
148 def disable_recovery_mode(self):
149 """Disable recovery mode on device."""
150 self.set('rec_mode', 'off')
151
152
153 def enable_development_mode(self):
154 """Enable development mode on device."""
155 self.set('dev_mode', 'on')
156
157
158 def disable_development_mode(self):
159 """Disable development mode on device."""
160 self.set('dev_mode', 'off')
161
162
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700163 def boot_devmode(self):
164 """Boot a dev-mode device that is powered off."""
165 self.set('pwr_button', 'release')
166 time.sleep(1)
167 self.power_normal_press()
Craig Harrison48997262011-06-27 14:31:10 -0700168 self.pass_devmode()
169
170
171 def pass_devmode(self):
172 """Pass through boot screens in dev-mode."""
173 time.sleep(10)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700174 self.ctrl_d()
Craig Harrison48997262011-06-27 14:31:10 -0700175 time.sleep(17)
176
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700177
Craig Harrison6b36b122011-06-28 17:58:43 -0700178 def cold_reset(self):
179 """Perform a cold reset of the EC.
180
181 Has the side effect of shutting off the device.
182 """
183 self.set('cold_reset', 'on')
184 time.sleep(2)
185 self.set('cold_reset', 'off')
186
187
188 def warm_reset(self):
189 """Perform a warm reset of the device.
190
191 Has the side effect of restarting the device.
192 """
193 self.set('warm_reset', 'on')
194 time.sleep(2)
195 self.set('warm_reset', 'off')
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700196
197
198 def get(self, gpio_name):
199 """Get the value of a gpio from Servod."""
200 assert gpio_name
201 return self._server.get(gpio_name)
202
203
204 def set(self, gpio_name, gpio_value):
205 """Set and check the value of a gpio using Servod."""
206 assert gpio_name and gpio_value
207 self._server.set(gpio_name, gpio_value)
208 assert gpio_value == self.get(gpio_name)
209
210
211 def set_nocheck(self, gpio_name, gpio_value):
212 """Set the value of a gpio using Servod."""
213 assert gpio_name and gpio_value
214 self._server.set(gpio_name, gpio_value)
215
216
Craig Harrison6b36b122011-06-28 17:58:43 -0700217 def _init_seq_cold_reset_devmode(self):
218 """Cold reset, init device, and boot in dev-mode."""
219 self.cold_reset()
220 self._init_seq()
221 self.set('dev_mode', 'on')
222 self.boot_devmode()
223
224
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700225 def __del__(self):
226 """Kill the Servod process."""
227 assert self._servod
228 # kill servod one way or another
229 try:
230 # won't work without superuser privileges
231 self._servod.terminate()
232 except:
233 # should work without superuser privileges
234 assert subprocess.call(['sudo', 'kill', str(self._servod.pid)])
235
236
237 def _launch_servod(self, servo_port, xml_config='servo.xml'):
238 """Launch the servod process.
239
240 Args:
241 servo_port: Port to start servod listening on.
242 xml_config: XML configuration file for servod.
243 """
244 self._servod = subprocess.Popen(['sudo', 'servod', '-c',
245 str(xml_config),
246 '--host=localhost',
247 '--port=' + str(servo_port)],
248 0, None, None, None, subprocess.PIPE)
249 # wait for servod to initialize
250 timeout = 10
251 while ("Listening" not in self._servod.stderr.readline() and
252 self._servod.returncode is None and timeout > 0):
253 time.sleep(1)
254 timeout -= 1
255 assert self._servod.returncode is None and timeout
256
257
258 def _init_seq(self):
259 """Initiate starting state for servo."""
260 self.set('tx_dir', 'input')
261 self.set('servo_dut_tx', 'off')
262 self.set('lid_open', 'yes')
263 self.set('rec_mode', 'off')
264
265
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700266 def _connect_servod(self, servo_port=''):
267 """Connect to the Servod process with XMLRPC.
268
269 Args:
270 servo_port: Port the Servod process is listening on.
271 """
272 remote = 'http://localhost:%s' % servo_port
273 self._server = xmlrpclib.ServerProxy(remote)