blob: 97b2b01bdec154364df6a9dee7717abde7864289 [file] [log] [blame]
Tom Wai-Hong Tam6019a1a2012-10-12 14:03:34 +08001# Copyright (c) 2012 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
David Hendricks548f08e2014-05-09 15:05:49 -07005import ast, logging, re, time
Tom Wai-Hong Tam6019a1a2012-10-12 14:03:34 +08006
7from autotest_lib.client.common_lib import error
Victor Hsiehb5210ef2016-04-22 15:20:02 -07008from autotest_lib.client.cros import ec
Tom Wai-Hong Tam8326bff2012-10-12 15:34:38 +08009
Tom Wai-Hong Tam665281c2012-10-30 11:55:10 +080010# Hostevent codes, copied from:
11# ec/include/ec_commands.h
12HOSTEVENT_LID_CLOSED = 0x00000001
13HOSTEVENT_LID_OPEN = 0x00000002
14HOSTEVENT_POWER_BUTTON = 0x00000004
15HOSTEVENT_AC_CONNECTED = 0x00000008
16HOSTEVENT_AC_DISCONNECTED = 0x00000010
17HOSTEVENT_BATTERY_LOW = 0x00000020
18HOSTEVENT_BATTERY_CRITICAL = 0x00000040
19HOSTEVENT_BATTERY = 0x00000080
20HOSTEVENT_THERMAL_THRESHOLD = 0x00000100
21HOSTEVENT_THERMAL_OVERLOAD = 0x00000200
22HOSTEVENT_THERMAL = 0x00000400
23HOSTEVENT_USB_CHARGER = 0x00000800
24HOSTEVENT_KEY_PRESSED = 0x00001000
25HOSTEVENT_INTERFACE_READY = 0x00002000
26# Keyboard recovery combo has been pressed
27HOSTEVENT_KEYBOARD_RECOVERY = 0x00004000
28# Shutdown due to thermal overload
29HOSTEVENT_THERMAL_SHUTDOWN = 0x00008000
30# Shutdown due to battery level too low
31HOSTEVENT_BATTERY_SHUTDOWN = 0x00010000
32HOSTEVENT_INVALID = 0x80000000
33
Aseda Aboagyeb66dea92016-10-13 19:32:13 -070034# Time to wait after sending keypress commands.
35KEYPRESS_RECOVERY_TIME = 0.5
36
Tom Wai-Hong Tam665281c2012-10-30 11:55:10 +080037
Tom Wai-Hong Tam6019a1a2012-10-12 14:03:34 +080038class ChromeEC(object):
39 """Manages control of a Chrome EC.
40
41 We control the Chrome EC via the UART of a Servo board. Chrome EC
42 provides many interfaces to set and get its behavior via console commands.
43 This class is to abstract these interfaces.
44 """
45
46 def __init__(self, servo):
47 """Initialize and keep the servo object.
48
49 Args:
50 servo: A Servo object.
51 """
52 self._servo = servo
Vic Yang0ef0c092012-11-02 15:28:54 +080053 self._cached_uart_regexp = None
54
55
56 def set_uart_regexp(self, regexp):
57 if self._cached_uart_regexp == regexp:
58 return
59 self._cached_uart_regexp = regexp
60 self._servo.set('ec_uart_regexp', regexp)
Tom Wai-Hong Tam6019a1a2012-10-12 14:03:34 +080061
62
Tom Wai-Hong Tamf65ca352013-02-27 16:29:22 +080063 def send_command(self, commands):
Tom Wai-Hong Tam6019a1a2012-10-12 14:03:34 +080064 """Send command through UART.
65
66 This function opens UART pty when called, and then command is sent
67 through UART.
68
69 Args:
Tom Wai-Hong Tamf65ca352013-02-27 16:29:22 +080070 commands: The commands to send, either a list or a string.
Tom Wai-Hong Tam6019a1a2012-10-12 14:03:34 +080071 """
Vic Yang0ef0c092012-11-02 15:28:54 +080072 self.set_uart_regexp('None')
Tom Wai-Hong Tamf65ca352013-02-27 16:29:22 +080073 if isinstance(commands, list):
74 try:
75 self._servo.set_nocheck('ec_uart_multicmd', ';'.join(commands))
76 except error.TestFail as e:
77 if 'No control named' in str(e):
78 logging.warning(
79 'The servod is too old that ec_uart_multicmd '
80 'not supported. Use ec_uart_cmd instead.')
81 for command in commands:
82 self._servo.set_nocheck('ec_uart_cmd', command)
83 else:
84 raise
85 else:
86 self._servo.set_nocheck('ec_uart_cmd', commands)
Tom Wai-Hong Tam6019a1a2012-10-12 14:03:34 +080087
88
Vadim Bendebury5c8f8672013-01-17 17:47:15 -080089 def send_command_get_output(self, command, regexp_list):
Tom Wai-Hong Tam6019a1a2012-10-12 14:03:34 +080090 """Send command through UART and wait for response.
91
92 This function waits for response message matching regular expressions.
93
94 Args:
95 command: The command sent.
96 regexp_list: List of regular expressions used to match response
97 message. Note, list must be ordered.
98
99 Returns:
100 List of tuples, each of which contains the entire matched string and
101 all the subgroups of the match. None if not matched.
102 For example:
103 response of the given command:
104 High temp: 37.2
105 Low temp: 36.4
106 regexp_list:
107 ['High temp: (\d+)\.(\d+)', 'Low temp: (\d+)\.(\d+)']
108 returns:
109 [('High temp: 37.2', '37', '2'), ('Low temp: 36.4', '36', '4')]
110
111 Raises:
112 error.TestError: An error when the given regexp_list is not valid.
113 """
114 if not isinstance(regexp_list, list):
115 raise error.TestError('Arugment regexp_list is not a list: %s' %
116 str(regexp_list))
117
Vic Yang0ef0c092012-11-02 15:28:54 +0800118 self.set_uart_regexp(str(regexp_list))
Tom Wai-Hong Tam6019a1a2012-10-12 14:03:34 +0800119 self._servo.set_nocheck('ec_uart_cmd', command)
120 return ast.literal_eval(self._servo.get('ec_uart_cmd'))
Tom Wai-Hong Tam8326bff2012-10-12 15:34:38 +0800121
122
123 def key_down(self, keyname):
124 """Simulate pressing a key.
125
126 Args:
127 keyname: Key name, one of the keys of KEYMATRIX.
128 """
129 self.send_command('kbpress %d %d 1' %
Victor Hsiehb5210ef2016-04-22 15:20:02 -0700130 (ec.KEYMATRIX[keyname][1], ec.KEYMATRIX[keyname][0]))
Tom Wai-Hong Tam8326bff2012-10-12 15:34:38 +0800131
132
133 def key_up(self, keyname):
134 """Simulate releasing a key.
135
136 Args:
137 keyname: Key name, one of the keys of KEYMATRIX.
138 """
139 self.send_command('kbpress %d %d 0' %
Victor Hsiehb5210ef2016-04-22 15:20:02 -0700140 (ec.KEYMATRIX[keyname][1], ec.KEYMATRIX[keyname][0]))
Tom Wai-Hong Tam8326bff2012-10-12 15:34:38 +0800141
142
143 def key_press(self, keyname):
144 """Press and then release a key.
145
146 Args:
147 keyname: Key name, one of the keys of KEYMATRIX.
148 """
Tom Wai-Hong Tamf65ca352013-02-27 16:29:22 +0800149 self.send_command([
150 'kbpress %d %d 1' %
Victor Hsiehb5210ef2016-04-22 15:20:02 -0700151 (ec.KEYMATRIX[keyname][1], ec.KEYMATRIX[keyname][0]),
Tom Wai-Hong Tamf65ca352013-02-27 16:29:22 +0800152 'kbpress %d %d 0' %
Victor Hsiehb5210ef2016-04-22 15:20:02 -0700153 (ec.KEYMATRIX[keyname][1], ec.KEYMATRIX[keyname][0]),
Tom Wai-Hong Tamf65ca352013-02-27 16:29:22 +0800154 ])
Aseda Aboagyeb66dea92016-10-13 19:32:13 -0700155 # Don't spam the EC console as fast as we can; leave some recovery time
156 # in between commands.
157 time.sleep(KEYPRESS_RECOVERY_TIME)
Tom Wai-Hong Tam8326bff2012-10-12 15:34:38 +0800158
159
160 def send_key_string_raw(self, string):
161 """Send key strokes consisting of only characters.
162
163 Args:
164 string: Raw string.
165 """
166 for c in string:
167 self.key_press(c)
168
169
170 def send_key_string(self, string):
171 """Send key strokes including special keys.
172
173 Args:
174 string: Character string including special keys. An example
175 is "this is an<tab>example<enter>".
176 """
177 for m in re.finditer("(<[^>]+>)|([^<>]+)", string):
178 sp, raw = m.groups()
179 if raw is not None:
180 self.send_key_string_raw(raw)
181 else:
182 self.key_press(sp)
Tom Wai-Hong Tambb92e6c2012-10-30 11:06:09 +0800183
184
185 def reboot(self, flags=''):
186 """Reboot EC with given flags.
187
188 Args:
189 flags: Optional, a space-separated string of flags passed to the
190 reboot command, including:
191 default: EC soft reboot;
192 'hard': EC hard/cold reboot;
193 'ap-off': Leave AP off after EC reboot (by default, EC turns
194 AP on after reboot if lid is open).
195
196 Raises:
197 error.TestError: If the string of flags is invalid.
198 """
199 for flag in flags.split():
200 if flag not in ('hard', 'ap-off'):
201 raise error.TestError(
202 'The flag %s of EC reboot command is invalid.' % flag)
203 self.send_command("reboot %s" % flags)
Tom Wai-Hong Tam05574ee2012-10-30 11:34:21 +0800204
205
206 def set_flash_write_protect(self, enable):
207 """Set the software write protect of EC flash.
208
209 Args:
210 enable: True to enable write protect, False to disable.
211 """
212 if enable:
213 self.send_command("flashwp enable")
214 else:
215 self.send_command("flashwp disable")
Tom Wai-Hong Tam665281c2012-10-30 11:55:10 +0800216
217
218 def set_hostevent(self, codes):
219 """Set the EC hostevent codes.
220
221 Args:
222 codes: Hostevent codes, HOSTEVENT_*
223 """
224 self.send_command("hostevent set %#x" % codes)
David Hendricks548f08e2014-05-09 15:05:49 -0700225 # Allow enough time for EC to process input and set flag.
226 # See chromium:371631 for details.
227 # FIXME: Stop importing time module if this hack becomes obsolete.
228 time.sleep(1)
Scott8f77ae82016-05-25 16:40:55 -0700229
230 def enable_console_channel(self, channel):
231 """Find console channel mask and enable that channel only
232
233 @param channel: console channel name
234 """
235 # The 'chan' command returns a list of console channels,
236 # their channel masks and channel numbers
237 regexp = r'(\d+)\s+([\w]+)\s+\*?\s+{0}'.format(channel)
238 l = self.send_command_get_output('chan', [regexp])
239 # Use channel mask and append the 0x for proper hex input value
240 cmd = 'chan 0x' + l[0][2]
241 # Set console to only output the desired channel
242 self.send_command(cmd)