# Copyright 2015 The Chromium OS Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import re import time from autotest_lib.client.bin import utils from autotest_lib.server.cros.servo import chrome_ec class PlanktonError(Exception): pass class Plankton(chrome_ec.ChromeEC): """Manages control of a Plankton PD console. Plankton is a testing board developed to aid in USB type C debug and control of various type C host devices. Plankton's features include the simulation of charger, USB 2.0 pass through, USB 3.0 hub, and display port pass through. We control the PD console via the UART of a Servo board. Plankton provides many interfaces that access the servo directly. It can also be passed into the PDConsoleUtils as a console which then provides methods to access the pd console. This class is to abstract these interfaces. """ # USB charging command delays in seconds. USBC_COMMAND_DELAY = 0.5 # Plankton USBC commands. USBC_ROLE = 'usbc_role' USBC_MUX = 'usbc_mux' RE_USBC_ROLE_VOLTAGE = r'src(\d+)v' USBC_CHARGING_VOLTAGES = { 0: 'sink', 5: 'src5v', 12: 'src12v', 20: 'src20v'} VBUS_VOLTAGE_MV = 'vbus_voltage' VBUS_CURRENT_MA = 'vbus_current' VBUS_POWER_MW = 'vbus_power' # USBC PD states. USBC_PD_STATES = { 'sink': 'SNK_READY', 'source': 'SRC_READY'} POLL_STATE_SECS = 2 def __init__(self, servo, servod_proxy): """Initialize and keep the servo object. @param servo: A Servo object @param servod_proxy: Servod proxy for plankton host """ super(Plankton, self).__init__(servo) # save servod proxy for methods that access Plankton servod self._server = servod_proxy self.init_io_expander() def init_io_expander(self): """Initializes Plankton IO expander register settings.""" if not int(self.get('debug_usb_sel')): raise PlanktonError('debug_usb_sel (SW3) should be ON!! ' 'Please use CN15 to connect Plankton.') self.set('typec_to_hub_sw', '0') self.set('usb2_mux_sw', '1') self.set('usb_dn_pwren', 'on') def set(self, control_name, value): """Sets the value of a control using servod. @param control_name: plankton servo control item @param value: value to set plankton servo control item """ assert control_name self._server.set(control_name, value) def get(self, control_name): """Gets the value of a control from servod. @param control_name: plankton servo control item """ assert control_name return self._server.get(control_name) @property def vbus_voltage(self): """Gets Plankton VBUS voltage in volts.""" return float(self.get(self.VBUS_VOLTAGE_MV)) / 1000.0 @property def vbus_current(self): """Gets Plankton VBUS current in amps.""" return float(self.get(self.VBUS_CURRENT_MA)) / 1000.0 @property def vbus_power(self): """Gets Plankton charging power in watts.""" return float(self.get(self.VBUS_POWER_MW)) / 1000.0 def get_charging_voltages(self): """Gets the lists of available charging voltages.""" return self.USBC_CHARGING_VOLTAGES.keys() def charge(self, voltage): """Sets Plankton to provide power at specific voltage. @param voltage: Specified charging voltage in volts. """ if voltage not in self.USBC_CHARGING_VOLTAGES: raise PlanktonError('Invalid charging voltage: %s' % voltage) self.set(self.USBC_ROLE, self.USBC_CHARGING_VOLTAGES[voltage]) time.sleep(self.USBC_COMMAND_DELAY) @property def charging_voltage(self): """Gets current charging voltage.""" usbc_role = self.get(self.USBC_ROLE) m = re.match(self.RE_USBC_ROLE_VOLTAGE, usbc_role) if m: return int(m.group(1)) if usbc_role == self.USBC_CHARGING_VOLTAGES[0]: return 0 raise PlanktonError('Invalid USBC role: %s' % usbc_role) def poll_pd_state(self, state): """Polls until Plankton pd goes to the specific state. @param state: Specified pd state name. """ if state not in self.USBC_PD_STATES: raise PlanktonError('Invalid state name: %s' % state) utils.poll_for_condition( lambda: self.get('pd_state') == self.USBC_PD_STATES[state], exception=utils.TimeoutError('Plankton not in %s state ' 'after %s seconds.' % (self.USBC_PD_STATES[state], self.POLL_STATE_SECS)), timeout=self.POLL_STATE_SECS) def set_usbc_mux(self, mux): """Sets Plankton usbc_mux. @param mux: Specified mux state name. """ if mux not in ['dp', 'usb']: raise PlanktonError('Invalid mux name: %s, ' 'should be either \'dp\' or \'usb\'.' % mux) self.set(self.USBC_MUX, mux) time.sleep(self.USBC_COMMAND_DELAY)