blob: 1bfeec0197db770841464a14088117973e85cd67 [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."""
80 self.set('lid_open', 'yes')
81
82
83 def lid_close(self):
84 """Simulate closing the lid."""
85 self.set('lid_open', 'no')
86
87
88 def ctrl_d(self, secs=0.5):
89 """Simulate Ctrl-d simultaneous button presses.
90
91 Args:
92 secs: Time in seconds to simulate the keypress.
93 """
94 self.set_nocheck('kbd_en', 'on')
95 self.set_nocheck('kbd_m1', 'r2_c2')
96 self.set_nocheck('kbd_m2', 'r1_c1')
97 time.sleep(secs)
98 self.set_nocheck('kbd_en', 'off')
99
100
101 def enter_key(self, secs=0.5):
102 """Simulate Enter key button press.
103
104 Args:
105 secs: Time in seconds to simulate the keypress.
106 """
107 self.set_nocheck('kbd_en', 'on')
108 self.set_nocheck('kbd_m1', 'r3_c2')
109 time.sleep(secs)
110 self.set_nocheck('kbd_en', 'off')
111
112
113 def refresh_key(self, secs=0.5):
114 """Simulate Refresh key (F3) button press.
115
116 Args:
117 secs: Time in seconds to simulate the keypress.
118 """
119 self.set_nocheck('kbd_en', 'on')
120 self.set_nocheck('kbd_m2', 'r2_c1')
121 time.sleep(secs)
122 self.set_nocheck('kbd_en', 'off')
123
124
125 def imaginary_key(self, secs=0.5):
126 """Simulate imaginary key button press.
127
128 Maps to a key that doesn't physically exist.
129
130 Args:
131 secs: Time in seconds to simulate the keypress.
132 """
133 self.set_nocheck('kbd_en', 'on')
134 self.set_nocheck('kbd_m2', 'r3_c1')
135 time.sleep(secs)
136 self.set_nocheck('kbd_en', 'off')
137
138
139 def boot_devmode(self):
140 """Boot a dev-mode device that is powered off."""
141 self.set('pwr_button', 'release')
142 time.sleep(1)
143 self.power_normal_press()
144 time.sleep(8)
145 self.ctrl_d()
146 time.sleep(15)
147
148 def _init_seq_cold_reset_devmode(self):
149 """Cold reset, init device, and boot in dev-mode."""
150 self._cold_reset()
151 self._init_seq()
152 self.set('dev_mode', 'on')
153 self.boot_devmode()
154
155
156 def get(self, gpio_name):
157 """Get the value of a gpio from Servod."""
158 assert gpio_name
159 return self._server.get(gpio_name)
160
161
162 def set(self, gpio_name, gpio_value):
163 """Set and check the value of a gpio using Servod."""
164 assert gpio_name and gpio_value
165 self._server.set(gpio_name, gpio_value)
166 assert gpio_value == self.get(gpio_name)
167
168
169 def set_nocheck(self, gpio_name, gpio_value):
170 """Set the value of a gpio using Servod."""
171 assert gpio_name and gpio_value
172 self._server.set(gpio_name, gpio_value)
173
174
175 def __del__(self):
176 """Kill the Servod process."""
177 assert self._servod
178 # kill servod one way or another
179 try:
180 # won't work without superuser privileges
181 self._servod.terminate()
182 except:
183 # should work without superuser privileges
184 assert subprocess.call(['sudo', 'kill', str(self._servod.pid)])
185
186
187 def _launch_servod(self, servo_port, xml_config='servo.xml'):
188 """Launch the servod process.
189
190 Args:
191 servo_port: Port to start servod listening on.
192 xml_config: XML configuration file for servod.
193 """
194 self._servod = subprocess.Popen(['sudo', 'servod', '-c',
195 str(xml_config),
196 '--host=localhost',
197 '--port=' + str(servo_port)],
198 0, None, None, None, subprocess.PIPE)
199 # wait for servod to initialize
200 timeout = 10
201 while ("Listening" not in self._servod.stderr.readline() and
202 self._servod.returncode is None and timeout > 0):
203 time.sleep(1)
204 timeout -= 1
205 assert self._servod.returncode is None and timeout
206
207
208 def _init_seq(self):
209 """Initiate starting state for servo."""
210 self.set('tx_dir', 'input')
211 self.set('servo_dut_tx', 'off')
212 self.set('lid_open', 'yes')
213 self.set('rec_mode', 'off')
214
215
216 def _cold_reset(self):
217 """Perform a cold reset of the EC.
218
219 Has the side effect of shutting off the device.
220 """
221 self.set('cold_reset', 'on')
222 time.sleep(2)
223 self.set('cold_reset', 'off')
224
225
226 def _connect_servod(self, servo_port=''):
227 """Connect to the Servod process with XMLRPC.
228
229 Args:
230 servo_port: Port the Servod process is listening on.
231 """
232 remote = 'http://localhost:%s' % servo_port
233 self._server = xmlrpclib.ServerProxy(remote)