1# 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 5import re 6import time 7 8from autotest_lib.client.bin import utils 9from autotest_lib.server.cros.servo import chrome_ec 10 11 12class PlanktonError(Exception): 13 pass 14 15 16class Plankton(chrome_ec.ChromeEC): 17 """Manages control of a Plankton PD console. 18 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 22 pass through. 23 24 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 """ 31 # USB charging command delays in seconds. 32 USBC_COMMAND_DELAY = 0.5 33 # Plankton USBC commands. 34 USBC_ROLE = 'usbc_role' 35 USBC_MUX = 'usbc_mux' 36 RE_USBC_ROLE_VOLTAGE = r'src(\d+)v' 37 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' 45 # USBC PD states. 46 USBC_PD_STATES = { 47 'sink': 'SNK_READY', 48 'source': 'SRC_READY'} 49 POLL_STATE_SECS = 2 50 51 def __init__(self, servo, servod_proxy): 52 """Initialize and keep the servo object. 53 54 @param servo: A Servo object 55 @param servod_proxy: Servod proxy for plankton host 56 """ 57 super(Plankton, self).__init__(servo) 58 # save servod proxy for methods that access Plankton servod 59 self._server = servod_proxy 60 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') 71 72 73 def set(self, control_name, value): 74 """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 """ 79 assert control_name 80 self._server.set(control_name, value) 81 82 83 def get(self, control_name): 84 """Gets the value of a control from servod. 85 86 @param control_name: plankton servo control item 87 """ 88 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) 131 m = re.match(self.RE_USBC_ROLE_VOLTAGE, usbc_role) 132 if m: 133 return int(m.group(1)) 134 135 if usbc_role == self.USBC_CHARGING_VOLTAGES[0]: 136 return 0 137 138 raise PlanktonError('Invalid USBC role: %s' % usbc_role) 139 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) 155 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) 167