blob: be828e4193ea465d5c47804535bef7e6b7a1ffd3 [file] [log] [blame]
# 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 PDTesterError(Exception):
"""Error object for PDTester"""
pass
class PDTester(chrome_ec.ChromeEC):
"""Manages control of a PDTester hardware.
PDTester is a general term for hardware developed to aid in USB type-C
debug and control of various type C host devices. It can be either a
Plankton board or a Servo v4 board.
We control the PDTester board via the UART and the Servod interfaces.
PDTester provides many interfaces that access the hardware. 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
# PDTester 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'}
USBC_MAX_VOLTAGE = 20
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 pdtester host
"""
self.servo_type = servo.get_servo_version()
if 'servo_v4' in self.servo_type:
uart_prefix = 'servo_v4_uart'
else:
uart_prefix = 'ec_uart'
super(PDTester, self).__init__(servo, uart_prefix)
# save servod proxy for methods that access PDTester servod
self._server = servod_proxy
self.init_hardware()
def init_hardware(self):
"""Initializes PDTester hardware."""
if self.servo_type == 'plankton':
if not int(self.get('debug_usb_sel')):
raise PDTesterError('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: pdtester servo control item
@param value: value to set pdtester 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: pdtester servo control item
"""
assert control_name
return self._server.get(control_name)
@property
def vbus_voltage(self):
"""Gets PDTester VBUS voltage in volts."""
return float(self.get(self.VBUS_VOLTAGE_MV)) / 1000.0
@property
def vbus_current(self):
"""Gets PDTester VBUS current in amps."""
return float(self.get(self.VBUS_CURRENT_MA)) / 1000.0
@property
def vbus_power(self):
"""Gets PDTester 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 PDTester to provide power at specific voltage.
@param voltage: Specified charging voltage in volts.
"""
if voltage not in self.USBC_CHARGING_VOLTAGES:
raise PDTesterError('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 PDTesterError('Invalid USBC role: %s' % usbc_role)
def poll_pd_state(self, state):
"""Polls until PDTester pd goes to the specific state.
@param state: Specified pd state name.
"""
if state not in self.USBC_PD_STATES:
raise PDTesterError('Invalid state name: %s' % state)
utils.poll_for_condition(
lambda: self.get('pd_state') == self.USBC_PD_STATES[state],
exception=utils.TimeoutError('PDTester 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 PDTester usbc_mux.
@param mux: Specified mux state name.
"""
if mux not in ['dp', 'usb']:
raise PDTesterError('Invalid mux name: %s, '
'should be either \'dp\' or \'usb\'.' % mux)
self.set(self.USBC_MUX, mux)
time.sleep(self.USBC_COMMAND_DELAY)