blob: 2f38cfd0917464240c09dc56684a0bd832c73710 [file] [log] [blame]
Rong Chang42ea8de2015-03-09 15:19:20 +08001# Copyright 2015 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
Rong Chang42ea8de2015-03-09 15:19:20 +08005import re
6import time
Rong Chang42ea8de2015-03-09 15:19:20 +08007
Johny Lind5c46fa2015-03-26 17:24:40 +08008from autotest_lib.client.bin import utils
Scottfe06ed82015-11-05 17:15:01 -08009from autotest_lib.server.cros.servo import chrome_ec
Johny Lind5c46fa2015-03-26 17:24:40 +080010
Rong Chang42ea8de2015-03-09 15:19:20 +080011
12class PlanktonError(Exception):
13 pass
14
15
Scott07a848f2016-01-12 15:04:52 -080016class Plankton(chrome_ec.ChromeEC):
17 """Manages control of a Plankton PD console.
Rong Chang42ea8de2015-03-09 15:19:20 +080018
19 Plankton is a testing board developed to aid in USB type C debug and
20 control of various type C host devices. Plankton's features include the
21 simulation of charger, USB 2.0 pass through, USB 3.0 hub, and display port
Scott07a848f2016-01-12 15:04:52 -080022 pass through.
Rong Chang42ea8de2015-03-09 15:19:20 +080023
Scott07a848f2016-01-12 15:04:52 -080024 We control the PD console via the UART of a Servo board. Plankton
25 provides many interfaces that access the servo directly. It can
26 also be passed into the PDConsoleUtils as a console which then
27 provides methods to access the pd console.
28
29 This class is to abstract these interfaces.
30 """
Rong Chang42ea8de2015-03-09 15:19:20 +080031 # USB charging command delays in seconds.
32 USBC_COMMAND_DELAY = 0.5
33 # Plankton USBC commands.
34 USBC_ROLE = 'usbc_role'
Rong Chang4408fec2015-03-10 19:29:08 +080035 USBC_MUX = 'usbc_mux'
Scott07a848f2016-01-12 15:04:52 -080036 RE_USBC_ROLE_VOLTAGE = r'src(\d+)v'
Rong Chang42ea8de2015-03-09 15:19:20 +080037 USBC_CHARGING_VOLTAGES = {
38 0: 'sink',
39 5: 'src5v',
40 12: 'src12v',
41 20: 'src20v'}
42 VBUS_VOLTAGE_MV = 'vbus_voltage'
43 VBUS_CURRENT_MA = 'vbus_current'
44 VBUS_POWER_MW = 'vbus_power'
Johny Lind5c46fa2015-03-26 17:24:40 +080045 # USBC PD states.
46 USBC_PD_STATES = {
47 'sink': 'SNK_READY',
48 'source': 'SRC_READY'}
49 POLL_STATE_SECS = 2
Rong Chang42ea8de2015-03-09 15:19:20 +080050
Scott07a848f2016-01-12 15:04:52 -080051 def __init__(self, servo, servod_proxy):
52 """Initialize and keep the servo object.
Rong Chang42ea8de2015-03-09 15:19:20 +080053
Scott07a848f2016-01-12 15:04:52 -080054 @param servo: A Servo object
55 @param servod_proxy: Servod proxy for plankton host
Rong Chang42ea8de2015-03-09 15:19:20 +080056 """
Scott07a848f2016-01-12 15:04:52 -080057 super(Plankton, self).__init__(servo)
58 # save servod proxy for methods that access Plankton servod
59 self._server = servod_proxy
Johny Lin1f255912015-03-12 12:38:11 +080060 self.init_io_expander()
61
62
63 def init_io_expander(self):
64 """Initializes Plankton IO expander register settings."""
65 if not int(self.get('debug_usb_sel')):
66 raise PlanktonError('debug_usb_sel (SW3) should be ON!! '
67 'Please use CN15 to connect Plankton.')
68 self.set('typec_to_hub_sw', '0')
69 self.set('usb2_mux_sw', '1')
70 self.set('usb_dn_pwren', 'on')
Rong Chang42ea8de2015-03-09 15:19:20 +080071
72
73 def set(self, control_name, value):
Scottfe06ed82015-11-05 17:15:01 -080074 """Sets the value of a control using servod.
75
76 @param control_name: plankton servo control item
77 @param value: value to set plankton servo control item
78 """
Rong Chang42ea8de2015-03-09 15:19:20 +080079 assert control_name
80 self._server.set(control_name, value)
81
82
83 def get(self, control_name):
Scottfe06ed82015-11-05 17:15:01 -080084 """Gets the value of a control from servod.
85
86 @param control_name: plankton servo control item
87 """
Rong Chang42ea8de2015-03-09 15:19:20 +080088 assert control_name
89 return self._server.get(control_name)
90
91
92 @property
93 def vbus_voltage(self):
94 """Gets Plankton VBUS voltage in volts."""
95 return float(self.get(self.VBUS_VOLTAGE_MV)) / 1000.0
96
97
98 @property
99 def vbus_current(self):
100 """Gets Plankton VBUS current in amps."""
101 return float(self.get(self.VBUS_CURRENT_MA)) / 1000.0
102
103
104 @property
105 def vbus_power(self):
106 """Gets Plankton charging power in watts."""
107 return float(self.get(self.VBUS_POWER_MW)) / 1000.0
108
109
110 def get_charging_voltages(self):
111 """Gets the lists of available charging voltages."""
112 return self.USBC_CHARGING_VOLTAGES.keys()
113
114
115 def charge(self, voltage):
116 """Sets Plankton to provide power at specific voltage.
117
118 @param voltage: Specified charging voltage in volts.
119 """
120 if voltage not in self.USBC_CHARGING_VOLTAGES:
121 raise PlanktonError('Invalid charging voltage: %s' % voltage)
122
123 self.set(self.USBC_ROLE, self.USBC_CHARGING_VOLTAGES[voltage])
124 time.sleep(self.USBC_COMMAND_DELAY)
125
126
127 @property
128 def charging_voltage(self):
129 """Gets current charging voltage."""
130 usbc_role = self.get(self.USBC_ROLE)
Scott07a848f2016-01-12 15:04:52 -0800131 m = re.match(self.RE_USBC_ROLE_VOLTAGE, usbc_role)
132 if m:
133 return int(m.group(1))
Rong Chang42ea8de2015-03-09 15:19:20 +0800134
135 if usbc_role == self.USBC_CHARGING_VOLTAGES[0]:
136 return 0
137
138 raise PlanktonError('Invalid USBC role: %s' % usbc_role)
Johny Lind5c46fa2015-03-26 17:24:40 +0800139
140
141 def poll_pd_state(self, state):
142 """Polls until Plankton pd goes to the specific state.
143
144 @param state: Specified pd state name.
145 """
146 if state not in self.USBC_PD_STATES:
147 raise PlanktonError('Invalid state name: %s' % state)
148 utils.poll_for_condition(
149 lambda: self.get('pd_state') == self.USBC_PD_STATES[state],
150 exception=utils.TimeoutError('Plankton not in %s state '
151 'after %s seconds.' %
152 (self.USBC_PD_STATES[state],
153 self.POLL_STATE_SECS)),
154 timeout=self.POLL_STATE_SECS)
Rong Chang4408fec2015-03-10 19:29:08 +0800155
156
157 def set_usbc_mux(self, mux):
158 """Sets Plankton usbc_mux.
159
160 @param mux: Specified mux state name.
161 """
162 if mux not in ['dp', 'usb']:
163 raise PlanktonError('Invalid mux name: %s, '
164 'should be either \'dp\' or \'usb\'.' % mux)
165 self.set(self.USBC_MUX, mux)
166 time.sleep(self.USBC_COMMAND_DELAY)