blob: 1372c3f91c58536307240e1f8741d8b1d1842ff9 [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):
58 """Simulate a normal (1 sec) power button press."""
59 self.power_key(1)
60
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 """
73 self.set('pwr_button', 'press')
74 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
143 def boot_devmode(self):
144 """Boot a dev-mode device that is powered off."""
145 self.set('pwr_button', 'release')
146 time.sleep(1)
147 self.power_normal_press()
Craig Harrison48997262011-06-27 14:31:10 -0700148 self.pass_devmode()
149
150
151 def pass_devmode(self):
152 """Pass through boot screens in dev-mode."""
153 time.sleep(10)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700154 self.ctrl_d()
Craig Harrison48997262011-06-27 14:31:10 -0700155 time.sleep(17)
156
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700157
158 def _init_seq_cold_reset_devmode(self):
159 """Cold reset, init device, and boot in dev-mode."""
160 self._cold_reset()
161 self._init_seq()
162 self.set('dev_mode', 'on')
163 self.boot_devmode()
164
165
166 def get(self, gpio_name):
167 """Get the value of a gpio from Servod."""
168 assert gpio_name
169 return self._server.get(gpio_name)
170
171
172 def set(self, gpio_name, gpio_value):
173 """Set and check the value of a gpio using Servod."""
174 assert gpio_name and gpio_value
175 self._server.set(gpio_name, gpio_value)
176 assert gpio_value == self.get(gpio_name)
177
178
179 def set_nocheck(self, gpio_name, gpio_value):
180 """Set the value of a gpio using Servod."""
181 assert gpio_name and gpio_value
182 self._server.set(gpio_name, gpio_value)
183
184
185 def __del__(self):
186 """Kill the Servod process."""
187 assert self._servod
188 # kill servod one way or another
189 try:
190 # won't work without superuser privileges
191 self._servod.terminate()
192 except:
193 # should work without superuser privileges
194 assert subprocess.call(['sudo', 'kill', str(self._servod.pid)])
195
196
197 def _launch_servod(self, servo_port, xml_config='servo.xml'):
198 """Launch the servod process.
199
200 Args:
201 servo_port: Port to start servod listening on.
202 xml_config: XML configuration file for servod.
203 """
204 self._servod = subprocess.Popen(['sudo', 'servod', '-c',
205 str(xml_config),
206 '--host=localhost',
207 '--port=' + str(servo_port)],
208 0, None, None, None, subprocess.PIPE)
209 # wait for servod to initialize
210 timeout = 10
211 while ("Listening" not in self._servod.stderr.readline() and
212 self._servod.returncode is None and timeout > 0):
213 time.sleep(1)
214 timeout -= 1
215 assert self._servod.returncode is None and timeout
216
217
218 def _init_seq(self):
219 """Initiate starting state for servo."""
220 self.set('tx_dir', 'input')
221 self.set('servo_dut_tx', 'off')
222 self.set('lid_open', 'yes')
223 self.set('rec_mode', 'off')
224
225
226 def _cold_reset(self):
227 """Perform a cold reset of the EC.
228
229 Has the side effect of shutting off the device.
230 """
231 self.set('cold_reset', 'on')
232 time.sleep(2)
233 self.set('cold_reset', 'off')
234
235
236 def _connect_servod(self, servo_port=''):
237 """Connect to the Servod process with XMLRPC.
238
239 Args:
240 servo_port: Port the Servod process is listening on.
241 """
242 remote = 'http://localhost:%s' % servo_port
243 self._server = xmlrpclib.ServerProxy(remote)