Home | History | Annotate | Download | only in servo
      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 
      5 import re
      6 import time
      7 
      8 from autotest_lib.client.bin import utils
      9 from autotest_lib.server.cros.servo import chrome_ec
     10 
     11 
     12 class PlanktonError(Exception):
     13     pass
     14 
     15 
     16 class 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