16f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch# Copyright 2015 The Chromium OS Authors. All rights reserved. 26f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch# Use of this source code is governed by a BSD-style license that can be 36f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch# found in the LICENSE file. 46f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Brochimport logging 513f929ddf163cc7e475ed34e130e875da11c99c4Todd Brochimport re 613f929ddf163cc7e475ed34e130e875da11c99c4Todd Brochimport time 76f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch 86f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Brochfrom autotest_lib.client.bin import utils 96f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Brochfrom autotest_lib.client.common_lib import error 106f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch 11b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh# en-US key matrix (from "kb membrane pin matrix.pdf") 12b5210efc64510e1b1335b1561f3e23a99cf91053Victor HsiehKEYMATRIX = {'`': (3, 1), '1': (6, 1), '2': (6, 4), '3': (6, 2), '4': (6, 3), 13b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh '5': (3, 3), '6': (3, 6), '7': (6, 6), '8': (6, 5), '9': (6, 9), 14b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh '0': (6, 8), '-': (3, 8), '=': (0, 8), 'q': (7, 1), 'w': (7, 4), 15b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh 'e': (7, 2), 'r': (7, 3), 't': (2, 3), 'y': (2, 6), 'u': (7, 6), 16b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh 'i': (7, 5), 'o': (7, 9), 'p': (7, 8), '[': (2, 8), ']': (2, 5), 17b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh '\\': (3, 11), 'a': (4, 1), 's': (4, 4), 'd': (4, 2), 'f': (4, 3), 18b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh 'g': (1, 3), 'h': (1, 6), 'j': (4, 6), 'k': (4, 5), 'l': (4, 9), 19b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh ';': (4, 8), '\'': (1, 8), 'z': (5, 1), 'x': (5, 4), 'c': (5, 2), 20b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh 'v': (5, 3), 'b': (0, 3), 'n': (0, 6), 'm': (5, 6), ',': (5, 5), 21b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh '.': (5, 9), '/': (5, 8), ' ': (5, 11), '<right>': (6, 12), 22b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh '<alt_r>': (0, 10), '<down>': (6, 11), '<tab>': (2, 1), 23b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh '<f10>': (0, 4), '<shift_r>': (7, 7), '<ctrl_r>': (4, 0), 24b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh '<esc>': (1, 1), '<backspace>': (1, 11), '<f2>': (3, 2), 25b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh '<alt_l>': (6, 10), '<ctrl_l>': (2, 0), '<f1>': (0, 2), 26b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh '<search>': (0, 1), '<f3>': (2, 2), '<f4>': (1, 2), '<f5>': (3, 4), 27b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh '<f6>': (2, 4), '<f7>': (1, 4), '<f8>': (2, 9), '<f9>': (1, 9), 28b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh '<up>': (7, 11), '<shift_l>': (5, 7), '<enter>': (4, 11), 29b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh '<left>': (7, 12)} 30b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh 316f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch 326f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Brochdef has_ectool(): 336f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch """Determine if ectool shell command is present. 346f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch 356f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch Returns: 366f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch boolean true if avail, false otherwise. 376f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch """ 386f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch cmd = 'which ectool' 396f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch return (utils.system(cmd, ignore_status=True) == 0) 406f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch 416f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch 4213f929ddf163cc7e475ed34e130e875da11c99c4Todd Brochclass EC_Common(object): 4313f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch """Class for EC common. 4413f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 4513f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch This incredibly brief base class is intended to encapsulate common elements 4613f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch across various CrOS MCUs (ec proper, USB-PD, Sensor Hub). At the moment 4713f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch that includes only the use of ectool. 4813f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch """ 4913f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 5013f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch def __init__(self, target='cros_ec'): 5113f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch """Constructor. 526f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch 5313f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch @param target: target name of ec to communicate with. 5413f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch """ 556f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch if not has_ectool(): 566f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch ec_info = utils.system_output("mosys ec info", 576f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch ignore_status=True) 586f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch logging.warning("Ectool absent on this platform ( %s )", 596f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch ec_info) 606f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch raise error.TestNAError("Platform doesn't support ectool") 6113f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch self._target = target 626f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch 63ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch def ec_command(self, cmd, **kwargs): 646f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch """Executes ec command and returns results. 656f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch 666f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch @param cmd: string of command to execute. 67ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch @param kwargs: optional params passed to utils.system_output 686f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch 696f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch @returns: string of results from ec command. 706f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch """ 7113f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch full_cmd = 'ectool --name=%s %s' % (self._target, cmd) 72ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch result = utils.system_output(full_cmd, **kwargs) 7313f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch logging.debug('Command: %s', full_cmd) 7413f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch logging.debug('Result: %s', result) 756f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch return result 766f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch 7713f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 7813f929ddf163cc7e475ed34e130e875da11c99c4Todd Brochclass EC(EC_Common): 7913f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch """Class for CrOS embedded controller (EC).""" 8013f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch HELLO_RE = "EC says hello" 8113f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch GET_FANSPEED_RE = "Current fan RPM: ([0-9]*)" 8213f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch SET_FANSPEED_RE = "Fan target RPM set." 8313f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch TEMP_SENSOR_RE = "Reading temperature...([0-9]*)" 8413f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch TOGGLE_AUTO_FAN_RE = "Automatic fan control is now on" 8513f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch # For battery, check we can see a non-zero capacity value. 8613f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch BATTERY_RE = "Design capacity:\s+[1-9]\d*\s+mAh" 8713f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch LIGHTBAR_RE = "^ 05\s+3f\s+3f$" 8813f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 8913f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 906f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch def hello(self): 916f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch """Test EC hello command. 926f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch 936f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch @returns True if success False otherwise. 946f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch """ 956f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch response = self.ec_command('hello') 966f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch return (re.search(self.HELLO_RE, response) is not None) 976f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch 986f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch def auto_fan_ctrl(self): 996f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch """Turns auto fan ctrl on. 1006f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch 1016f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch @returns True if success False otherwise. 1026f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch """ 1036f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch response = self.ec_command('autofanctrl') 1046f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch logging.info('Turned on auto fan control.') 1056f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch return (re.search(self.TOGGLE_AUTO_FAN_RE, response) is not None) 1066f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch 1076f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch def get_fanspeed(self): 1086f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch """Gets fanspeed. 1096f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch 1106f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch @raises error.TestError if regexp fails to match. 1116f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch 1126f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch @returns integer of fan speed RPM. 1136f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch """ 1146f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch response = self.ec_command('pwmgetfanrpm') 1156f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch match = re.search(self.GET_FANSPEED_RE, response) 1166f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch if not match: 1176f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch raise error.TestError('Unable to read fan speed') 1186f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch 1196f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch rpm = int(match.group(1)) 1206f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch logging.info('Fan speed: %d', rpm) 1216f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch return rpm 1226f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch 1236f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch def set_fanspeed(self, rpm): 1246f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch """Sets fan speed. 1256f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch 12613f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch @param rpm: integer of fan speed RPM to set 1276f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch 1286f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch @returns True if success False otherwise. 1296f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch """ 1306f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch response = self.ec_command('pwmsetfanrpm %d' % rpm) 1316f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch logging.info('Set fan speed: %d', rpm) 1326f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch return (re.search(self.SET_FANSPEED_RE, response) is not None) 1336f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch 1346f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch def get_temperature(self, idx): 1356f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch """Gets temperature from idx sensor. 1366f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch 13713f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch @param idx: integer of temp sensor to read. 1386f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch 1396f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch @raises error.TestError if fails to read sensor. 1406f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch 1416f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch @returns integer of temperature reading in degrees Kelvin. 1426f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch """ 1436f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch response = self.ec_command('temps %d' % idx) 1446f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch match = re.search(self.TEMP_SENSOR_RE, response) 1456f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch if not match: 1466f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch raise error.TestError('Unable to read temperature sensor %d' % idx) 1476f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch 1486f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch return int(match.group(1)) 1496f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch 1506f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch def get_battery(self): 1516f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch """Get battery presence (design capacity found). 1526f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch 1536f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch @returns True if success False otherwise. 1546f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch """ 1556f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch response = self.ec_command('battery') 1566f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch return (re.search(self.BATTERY_RE, response) is not None) 1576f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch 1586f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch def get_lightbar(self): 1596f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch """Test lightbar. 1606f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch 1616f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch @returns True if success False otherwise. 1626f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch """ 1636f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch self.ec_command('lightbar on') 1646f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch self.ec_command('lightbar init') 1656f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch self.ec_command('lightbar 4 255 255 255') 1666f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch response = self.ec_command('lightbar') 1676f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch self.ec_command('lightbar off') 1686f893d2c9e26ef70ea3ccd2b2866388c73579670Todd Broch return (re.search(self.LIGHTBAR_RE, response, re.MULTILINE) is not None) 16913f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 170b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh def key_press(self, key): 171b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh """Emit key down and up signal of the keyboard. 172b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh 173b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh @param key: name of a key defined in KEYMATRIX. 174b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh """ 175b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh self.key_down(key) 176b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh self.key_up(key) 177b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh 178b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh def _key_action(self, key, action_type): 179b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh if not key in KEYMATRIX: 180b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh raise error.TestError('Unknown key: ' + key) 181b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh row, col = KEYMATRIX[key] 182b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh self.ec_command('kbpress %d %d %d' % (row, col, action_type)) 183b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh 184b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh def key_down(self, key): 185b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh """Emit key down signal of the keyboard. 186b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh 187b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh @param key: name of a key defined in KEYMATRIX. 188b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh """ 189b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh self._key_action(key, 1) 190b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh 191b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh def key_up(self, key): 192b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh """Emit key up signal of the keyboard. 193b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh 194b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh @param key: name of a key defined in KEYMATRIX. 195b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh """ 196b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh self._key_action(key, 0) 197b5210efc64510e1b1335b1561f3e23a99cf91053Victor Hsieh 19813f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 19913f929ddf163cc7e475ed34e130e875da11c99c4Todd Brochclass EC_USBPD_Port(EC_Common): 20013f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch """Class for CrOS embedded controller for USB-PD Port. 20113f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 202ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch Public attributes: 203ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch index: integer of USB type-C port index. 204ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch 20513f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch Public Methods: 20613f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch is_dfp: Determine if data role is Downstream Facing Port (DFP). 20713f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch is_amode_supported: Check if alternate mode is supported by port. 20813f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch is_amode_entered: Check if alternate mode is entered. 20913f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch set_amode: Set an alternate mode. 21013f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 21113f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch Private attributes: 21213f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch _port: integer of USB type-C port id. 21313f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch _port_info: holds usbpd protocol info. 21413f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch _amodes: holds alternate mode info. 21513f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 21613f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch Private methods: 21713f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch _invalidate_port_data: Remove port data to force re-eval. 21813f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch _get_port_info: Get USB-PD port info. 21913f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch _get_amodes: parse and return port's svid info. 22013f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch """ 221ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch def __init__(self, index): 22213f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch """Constructor. 22313f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 224ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch @param index: integer of USB type-C port index. 22513f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch """ 226ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch self.index = index 22713f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch # TODO(crosbug.com/p/38133) target= only works for samus 22813f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch super(EC_USBPD_Port, self).__init__(target='cros_pd') 22913f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 23013f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch # Interrogate port at instantiation. Use invalidate to force re-eval. 23113f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch self._port_info = self._get_port_info() 23213f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch self._amodes = self._get_amodes() 23313f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 23413f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch def _invalidate_port_data(self): 23513f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch """Remove port data to force re-eval.""" 23613f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch self._port_info = None 23713f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch self._amodes = None 23813f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 23913f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch def _get_port_info(self): 24013f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch """Get USB-PD port info. 24113f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 24213f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch ectool command usbpd provides the following information about the port: 24313f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch - Enabled/Disabled 24413f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch - Power & Data Role 24513f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch - Polarity 24613f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch - Protocol State 24713f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 24813f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch At time of authoring it looks like: 24913f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch Port C0 is enabled, Role:SNK UFP Polarity:CC2 State:SNK_READY 25013f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 25113f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch @raises error.TestError if ... 25213f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch port info not parseable. 25313f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 25413f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch @returns dictionary for <port> with keyval pairs: 25513f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch enabled: True | False | None 25613f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch power_role: sink | source | None 25713f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch data_role: UFP | DFP | None 25813f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch is_reversed: True | False | None 25913f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch state: various strings | None 26013f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch """ 26113f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch PORT_INFO_RE = 'Port\s+C(\d+)\s+is\s+(\w+),\s+Role:(\w+)\s+(\w+)\s+' + \ 26213f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 'Polarity:CC(\d+)\s+State:(\w+)' 26313f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 26413f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch match = re.search(PORT_INFO_RE, 265ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch self.ec_command("usbpd %s" % (self.index))) 266ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch if not match or int(match.group(1)) != self.index: 267ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch error.TestError('Unable to determine port %d info' % self.index) 26813f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 26913f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch pinfo = dict(enabled=None, power_role=None, data_role=None, 27013f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch is_reversed=None, state=None) 27113f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch pinfo['enabled'] = match.group(2) == 'enabled' 27213f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch pinfo['power_role'] = 'sink' if match.group(3) == 'SNK' else 'source' 27313f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch pinfo['data_role'] = match.group(4) 27413f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch pinfo['is_reversed'] = True if match.group(5) == '2' else False 27513f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch pinfo['state'] = match.group(6) 27613f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch logging.debug('port_info = %s', pinfo) 27713f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch return pinfo 27813f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 27913f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch def _get_amodes(self): 28013f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch """Parse alternate modes from pdgetmode. 28113f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 28213f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch Looks like ... 28313f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch *SVID:0xff01 *0x00000485 0x00000000 ... 28413f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch SVID:0x18d1 0x00000001 0x00000000 ... 28513f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 28613f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch @returns dictionary of format: 28713f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch <svid>: {active: True|False, configs: <config_list>, opos:<opos>} 28813f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch where: 28913f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch <svid> : USB-IF Standard or vendor id as 29013f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch hex string (i.e. 0xff01) 29113f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch <config_list> : list of uint32_t configs 29213f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch <opos> : integer of active object position. 29313f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch Note, this is the config list index + 1 29413f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch """ 29513f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch SVID_RE = r'(\*?)SVID:(\S+)\s+(.*)' 29613f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch svids = dict() 297ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch cmd = 'pdgetmode %d' % self.index 29813f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch for line in self.ec_command(cmd, ignore_status=True).split('\n'): 29913f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch if line.strip() == '': 30013f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch continue 30113f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch logging.debug('pdgetmode line: %s', line) 30213f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch match = re.search(SVID_RE, line) 30313f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch if not match: 30413f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch logging.warning("Unable to parse SVID line %s", line) 30513f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch continue 30613f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch active = match.group(1) == '*' 30713f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch svid = match.group(2) 30813f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch configs_str = match.group(3) 30913f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch configs = list() 31013f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch opos = None 31113f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch for i,config in enumerate(configs_str.split(), 1): 31213f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch if config.startswith('*'): 31313f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch opos = i 31413f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch config = config[1:] 31513f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch config = int(config, 16) 31613f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch # ignore unpopulated configs 31713f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch if config == 0: 31813f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch continue 31913f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch configs.append(config) 32013f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch svids[svid] = dict(active=active, configs=configs, opos=opos) 32113f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 322ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch logging.debug("Port %d svids = %s", self.index, svids) 32313f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch return svids 32413f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 32513f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch def is_dfp(self): 32613f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch """Determine if data role is Downstream Facing Port (DFP). 32713f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 32813f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch @returns True if DFP False otherwise. 32913f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch """ 33013f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch if self._port_info is None: 33113f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch self._port_info = self._get_port_info() 33213f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 33313f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch return self._port_info['data_role'] == 'DFP' 33413f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 33513f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch def is_amode_supported(self, svid): 33613f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch """Check if alternate mode is supported by port partner. 33713f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 33813f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch @param svid: alternate mode SVID hexstring (i.e. 0xff01) 33913f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch """ 34013f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch if self._amodes is None: 34113f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch self._amodes = self._get_amodes() 34213f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 34313f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch if svid in self._amodes.keys(): 34413f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch return True 34513f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch return False 34613f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 34713f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch def is_amode_entered(self, svid, opos): 34813f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch """Check if alternate mode is entered. 34913f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 35013f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch @param svid: alternate mode SVID hexstring (i.e. 0xff01). 35113f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch @param opos: object position of config to act on. 35213f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 35313f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch @returns True if entered False otherwise 35413f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch """ 35513f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch if self._amodes is None: 35613f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch self._amodes = self._get_amodes() 35713f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 35813f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch if not self.is_amode_supported(svid): 35913f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch return False 36013f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 36113f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch if self._amodes[svid]['active'] and self._amodes[svid]['opos'] == opos: 36213f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch return True 36313f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 36413f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch return False 36513f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 36613f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch def set_amode(self, svid, opos, enter, delay_secs=2): 36713f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch """Set alternate mode. 36813f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 36913f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch @param svid: alternate mode SVID hexstring (i.e. 0xff01). 37013f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch @param opos: object position of config to act on. 37113f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch @param enter: Boolean of whether to enter mode. 37213f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 37313f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch @raises error.TestError if ... 37413f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch mode not supported. 37513f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch opos is > number of configs. 37613f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 37713f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch @returns True if successful False otherwise 37813f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch """ 37913f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch if self._amodes is None: 38013f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch self._amodes = self._get_amodes() 38113f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 38213f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch if svid not in self._amodes.keys(): 38313f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch raise error.TestError("SVID %s not supported", svid) 38413f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 38513f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch if opos > len(self._amodes[svid]['configs']): 38613f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch raise error.TestError("opos > available configs") 38713f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 388ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch cmd = "pdsetmode %d %s %d %d" % (self.index, svid, opos, 38913f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 1 if enter else 0) 39013f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch self.ec_command(cmd, ignore_status=True) 39113f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch self._invalidate_port_data() 39213f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 39313f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch # allow some time for mode entry/exit 39413f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch time.sleep(delay_secs) 39513f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch return self.is_amode_entered(svid, opos) == enter 39613f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 397ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch def get_flash_info(self): 398ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch mat0_re = r'has no discovered device' 399ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch mat1_re = r'.*ptype:(\d+)\s+vid:(\w+)\s+pid:(\w+).*' 400ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch mat2_re = r'.*DevId:(\d+)\.(\d+)\s+Hash:\s*(\w+.*)\s*CurImg:(\w+).*' 401ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch flash_dict = dict.fromkeys(['ptype', 'vid', 'pid', 'dev_major', 402ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch 'dev_minor', 'rw_hash', 'image_status']) 403ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch 404ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch cmd = 'infopddev %d' % self.index 405ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch 406ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch tries = 3 407ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch while (tries): 408ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch res = self.ec_command(cmd, ignore_status=True) 409ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch if not 'has no discovered device' in res: 410ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch break 411ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch 412ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch tries -= 1 413ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch time.sleep(1) 414ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch 415ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch for ln in res.split('\n'): 416ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch mat1 = re.match(mat1_re, ln) 417ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch if mat1: 418ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch flash_dict['ptype'] = int(mat1.group(1)) 419ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch flash_dict['vid'] = mat1.group(2) 420ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch flash_dict['pid'] = mat1.group(3) 421ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch continue 422ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch 423ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch mat2 = re.match(mat2_re, ln) 424ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch if mat2: 425ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch flash_dict['dev_major'] = int(mat2.group(1)) 426ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch flash_dict['dev_minor'] = int(mat2.group(2)) 427ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch flash_dict['rw_hash'] = mat2.group(3) 428ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch flash_dict['image_status'] = mat2.group(4) 429ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch break 430ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch 431ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch return flash_dict 432ee1ba32ea5ba3bb84c1ed040dbc9a2976edcef43Todd Broch 43313f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 43413f929ddf163cc7e475ed34e130e875da11c99c4Todd Brochclass EC_USBPD(EC_Common): 43513f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch """Class for CrOS embedded controller for USB-PD. 43613f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 43713f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch Public attributes: 43813f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch ports: list EC_USBPD_Port instances 43913f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 44013f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch Public Methods: 44113f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch get_num_ports: get number of USB-PD ports device has. 44213f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 44313f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch Private attributes: 44413f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch _num_ports: integer number of USB-PD ports device has. 44513f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch """ 44613f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch def __init__(self, num_ports=None): 44713f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch """Constructor. 44813f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 44913f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch @param num_ports: total number of USB-PD ports on device. This is an 45013f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch override. If left 'None' will try to determine. 45113f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch """ 45213f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch self._num_ports = num_ports 45313f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch self.ports = list() 45413f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 45513f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch # TODO(crosbug.com/p/38133) target= only works for samus 45613f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch super(EC_USBPD, self).__init__(target='cros_pd') 45713f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 45813f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch if (self.get_num_ports() == 0): 45913f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch raise error.TestNAError("Device has no USB-PD ports") 46013f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 46113f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch for i in xrange(self._num_ports): 46213f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch self.ports.append(EC_USBPD_Port(i)) 46313f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 46413f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch def get_num_ports(self): 46513f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch """Determine the number of ports for device. 46613f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 46713f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch Uses ectool's usbpdpower command which in turn makes host command call 46813f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch to EC_CMD_USB_PD_PORTS to determine the number of ports. 46913f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 47013f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch TODO(tbroch) May want to consider adding separate ectool command to 47113f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch surface the number of ports directly instead of via usbpdpower 47213f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 47313f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch @returns number of ports. 47413f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch """ 47513f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch if (self._num_ports is not None): 47613f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch return self._num_ports 47713f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch 47813f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch self._num_ports = len(self.ec_command("usbpdpower").split(b'\n')) 47913f929ddf163cc7e475ed34e130e875da11c99c4Todd Broch return self._num_ports 480