1370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott# Copyright 2016 The Chromium OS Authors. All rights reserved. 2370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott# Use of this source code is governed by a BSD-style license that can be 3370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott# found in the LICENSE file. 4370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 5370f9ef6f3d7fe53775224ec3e8006f0300aba89Scottimport logging 6370f9ef6f3d7fe53775224ec3e8006f0300aba89Scottimport re 7370f9ef6f3d7fe53775224ec3e8006f0300aba89Scottimport time 8370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 9370f9ef6f3d7fe53775224ec3e8006f0300aba89Scottfrom autotest_lib.client.common_lib import error 10370f9ef6f3d7fe53775224ec3e8006f0300aba89Scottfrom autotest_lib.server.cros.faft.firmware_test import FirmwareTest 11370f9ef6f3d7fe53775224ec3e8006f0300aba89Scottfrom autotest_lib.server.cros.servo import pd_console 12370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 13370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 14370f9ef6f3d7fe53775224ec3e8006f0300aba89Scottclass firmware_PDDataSwap(FirmwareTest): 15370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott """ 16370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott Servo based USB PD data role swap test 17370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 18370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott Pass critera is all data role swaps complete, or 19370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott a reject control message is received from the DUT in the 20370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott cases where the swap does not complete. 21370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 22370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott """ 23370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott version = 1 24370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 25370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott PD_ROLE_DELAY = 0.5 26370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott PD_CONNECT_DELAY = 4 27370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott PLANKTON_PORT = 0 28370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott DATA_SWAP_ITERATIONS = 10 29370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # Upward facing port data role 30370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott UFP = 'UFP' 31370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # Downward facing port data role 32370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott DFP = 'DFP' 33370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # Plankton initiated data swap request 34370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott PLANKTON_SWAP_REQ = 'pd %d swap data' % PLANKTON_PORT 35370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # Swap Result Tables 36370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott swap_attempt = { 37370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott ('rx', DFP): 0, 38370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott ('rx', UFP): 0, 39370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott ('tx', DFP): 0, 40370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott ('tx', UFP): 0 41370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott } 42370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott swap_failure = { 43370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott ('rx', DFP): 0, 44370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott ('rx', UFP): 0, 45370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott ('tx', DFP): 0, 46370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott ('tx', UFP): 0 47370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott } 48370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 49370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott def _verify_plankton_connection(self, port): 50370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott """Verify if DUT to Plankton PD connection 51370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 52370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott This method checks for a Plankton PD connection for the 53370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott given port by first verifying if a PD connection is present. 54370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott If found, then it uses a Plankton feature to force a PD disconnect. 55370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott If the port is no longer in the connected state, and following 56370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott a delay, is found to be back in the connected state, then 57370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott a DUT pd to Plankton connection is verified. 58370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 59370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott @param port: DUT pd port to test 60370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 61370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott @returns True if DUT to Plankton pd connection is verified 62370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott """ 63370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott DISCONNECT_TIME_SEC = 2 64370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # plankton console command to force PD disconnect 65370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott disc_cmd = 'fake_disconnect 100 %d' % (DISCONNECT_TIME_SEC*1000) 66370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # Only check for Plankton if DUT has active PD connection 67370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott if self.dut_pd_utils.is_pd_connected(port): 68370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # Attempt to force PD disconnection 69370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott self.plankton_pd_utils.send_pd_command(disc_cmd) 70370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott time.sleep(self.PD_ROLE_DELAY) 71370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # Verify that DUT PD port is no longer connected 72370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott if self.dut_pd_utils.is_pd_connected(port) == False: 73370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # Wait for disconnect timer and give time to reconnect 74370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott time.sleep(self.PD_CONNECT_DELAY + DISCONNECT_TIME_SEC) 75370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott if self.dut_pd_utils.is_pd_connected(port): 76370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott logging.info('Plankton connection verfied on port %d', port) 77370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott return True 78370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott else: 79370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # Could have disconnected other port, allow it to reconnect 80370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # before exiting. 81370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott time.sleep(self.PD_CONNECT_DELAY + DISCONNECT_TIME_SEC) 82370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott return False 83370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 84370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott def _find_dut_to_plankton_connection(self): 85370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott """Find the PD port which is connected to Plankton 86370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 87370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott @returns DUT pd port number if found, None otherwise 88370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott """ 89370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott for port in xrange(self.dut_pd_utils.PD_MAX_PORTS): 90370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # Check for DUT to Plankton connection on port 91370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott if self._verify_plankton_connection(port): 92370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # Plankton PD connection found so exit 93370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott return port 94370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott return None 95370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 96370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott def _get_data_role(self, console, port): 97370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott """Get data role of PD connection 98370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 99370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott @param console: pd console object for uart access 100370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott @param port: 0/1 pd port of current connection 101370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 102370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott @returns: 'DFP' or 'UFP' 103370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott """ 104370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott role = console.get_pd_role(port) 105370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott m = re.search('[\w]+-([\w]+)', role) 106370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott return m.group(1) 107370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 108370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott def _get_remote_role(self, local_role): 109370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott """Invert data role 110370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 111370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott @param local_role: data role to be flipped 112370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 113370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott @returns: flipped data role value 114370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott """ 115370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott if local_role == self.DFP: 116370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott return self.UFP 117370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott else: 118370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott return self.DFP 119370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 120370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott def _change_dut_power_role(self, port): 121370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott """Force power role change via Plankton 122370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 123370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott @param port: port of DUT PD connection 124370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 125370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott @returns True is power role change is successful 126370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott """ 127370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott PLANKTON_SRC_VOLTAGE = 5 128370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott PLANKTON_SNK_VOLTAGE = 0 129370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott pd_state = self.dut_pd_utils.get_pd_state(port) 130370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott if pd_state == self.dut_pd_utils.SRC_CONNECT: 131370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # DUT is currently a SRC, so change to SNK 132370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # Use Plankton method to ensure power role change 133370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott self.plankton.charge(PLANKTON_SRC_VOLTAGE) 134370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott else: 135370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # DUT is currently a SNK, so change it to a SRC. 136370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott self.plankton.charge(PLANKTON_SNK_VOLTAGE) 137370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # Wait for change to take place 138370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott time.sleep(self.PD_CONNECT_DELAY) 139370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott plankton_state = self.plankton_pd_utils.get_pd_state(0) 140370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # Current Plankton state should equal DUT state when called 141370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott return bool(pd_state == plankton_state) 142370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 143370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott def _send_data_swap_get_reply(self, console, port): 144370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott """Send data swap request, get PD control msg reply 145370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 146370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott The PD console debug mode is enabled prior to sending 147370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott a pd data role swap request message. This allows the 148370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott control message reply to be extracted. The debug mode 149370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott is disabled prior to exiting. 150370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 151370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott @param console: pd console object for uart access 152370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 153370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott @ returns: PD control header message 154370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott """ 155370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # Enable PD console debug mode to show control messages 156370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott console.enable_pd_console_debug() 157370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott cmd = 'pd %d swap data' % port 158370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott m = console.send_pd_command_get_output(cmd, ['RECV\s([\w]+)']) 159370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott ctrl_msg = int(m[0][1], 16) & console.PD_CONTROL_MSG_MASK 160370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott console.disable_pd_console_debug() 161370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott return ctrl_msg 162370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 163370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott def _attempt_data_swap(self, pd_port, direction): 164370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott """Perform a data role swap request 165370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 166370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott Data swap requests can be either initiated by the DUT or received 167370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott by the DUT. This direction determines which PD console is used 168370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott to initiate the swap command. The data role before and after 169370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott the swap command are compared to determine if it took place. 170370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 171370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott Even if data swap capability is advertised, a PD device is allowed 172370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott to reject the request. Therefore, not swapping isn't itself a 173370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott failure. When Plankton is used to initate the request, the debug 174370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott mode is enabled which allows the control message from the DUT to 175370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott be analyzed. If the swap does not occur, but the request is rejected 176370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott by the DUT then that is not counted as a failure. 177370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 178370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott @param pd_port: DUT pd port value 0/1 179370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott @param direction: rx or tx from the DUT perspective 180370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 181370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott @returns PD control reply message for tx swaps, 0 otherwise 182370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott """ 183370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # Get starting DUT data role 184370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott dut_dr = self._get_data_role(self.dut_pd_utils, pd_port) 185370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott self.swap_attempt[(direction, dut_dr)] += 1 186370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott if direction == 'tx': 187370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # Initiate swap request from the DUT 188370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott console = self.dut_pd_utils 189370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott cmd = 'pd %d swap data' % pd_port 190370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # Send the 'swap data' command 191370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott self.dut_pd_utils.send_pd_command(cmd) 192370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # Not using debug mode, so there is no reply message 193370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott ctrl = 0 194370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott else: 195370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # Initiate swap request from Plankton 196370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott console = self.plankton_pd_utils 197370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott ctrl = self._send_data_swap_get_reply(console, self.PLANKTON_PORT) 198370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 199370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott time.sleep(self.PD_ROLE_DELAY) 200370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # Get DUT current data role 201370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott swap_dr = self._get_data_role(self.dut_pd_utils, pd_port) 202370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott logging.info('%s swap attempt: prev = %s, new = %s, msg = %s', 203370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott direction, dut_dr, swap_dr, ctrl) 204370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott if (dut_dr == swap_dr and 205370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott ctrl != self.dut_pd_utils.PD_CONTROL_MSG_DICT['Reject']): 206370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott self.swap_failure[(direction, dut_dr)] += 1 207370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott return ctrl 208370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 209370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott def _execute_data_role_swap_test(self, pd_port): 210370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott """Execute a series of data role swaps 211370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 212370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott Attempt both rx and tx data swaps, from perspective of DUT. 213370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott Even if the DUT advertises support, it can 214370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott reject swap requests when already in the desired data role. For 215370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott example many devices will not swap if already in DFP mode. 216370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott However, Plankton should always accept a request. Therefore, 217370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott when a swap failed on a rx swap, then that is followed by 218370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott a tx swap attempt. 219370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 220370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott @param pd_port: port number of DUT PD connection 221370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott """ 222370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott for attempt in xrange(self.DATA_SWAP_ITERATIONS): 223370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # Use the same direction for every 2 loop iterations 224370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott if attempt & 2: 225370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott direction = 'tx' 226370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott else: 227370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott direction = 'rx' 228370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott ctrl_msg = self._attempt_data_swap(pd_port, direction) 229370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott if (direction == 'rx' and 230370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott ctrl_msg == 231370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott self.dut_pd_utils.PD_CONTROL_MSG_DICT['Reject']): 232370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # Use plankton initated swap to change roles 233370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott self._attempt_data_swap(pd_port, 'tx') 234370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 235370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott def _test_data_swap_reject(self, pd_port): 236370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott """Verify that data swap request is rejected 237370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 238370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott This tests the case where the DUT doesn't advertise support 239370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott for data swaps. A data request is sent by Plankton, and then 240370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott the control message checked to ensure the request was rejected. 241370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott In addition, the data role and connection state are verified 242370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott to remain unchanged. 243370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 244370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott @param pd_port: port for DUT pd connection 245370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott """ 246370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # Get current DUT data role 247370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott dut_data_role = self._get_data_role(self.dut_pd_utils, pd_port) 248370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott dut_connect_state = self.dut_pd_utils.get_pd_state(pd_port) 249370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # Send swap command from Plankton and get reply 250370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott ctrl_msg = self._send_data_swap_get_reply(self.plankton_pd_utils, 251370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott self.PLANKTON_PORT) 252370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott if ctrl_msg != self.dut_pd_utils.PD_CONTROL_MSG_DICT['Reject']: 253370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott raise error.TestFail('Data Swap Req not rejected, returned %r' % 254370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott ctrl_msg) 255370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # Get DUT current state 256370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott pd_state = self.dut_pd_utils.get_pd_state(pd_port) 257370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott if pd_state != dut_connect_state: 258370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott raise error.TestFail('PD not connected! pd_state = %r' % 259370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott pd_state) 260370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # Since reject message was received, verify data role didn't change 261370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott curr_dr = self._get_data_role(self.dut_pd_utils, pd_port) 262370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott if curr_dr != dut_data_role: 263370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott raise error.TestFail('Unexpected PD data role change') 264370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 265370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott def initialize(self, host, cmdline_args): 266370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott super(firmware_PDDataSwap, self).initialize(host, cmdline_args) 267370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # Only run in normal mode 268370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott self.switcher.setup_mode('normal') 269370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott self.usbpd.send_command('chan 0') 270370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 271370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott def cleanup(self): 272370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott self.usbpd.send_command('chan 0xffffffff') 273370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott super(firmware_PDDataSwap, self).cleanup() 274370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 275370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott def run_once(self): 276370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott """Exectue Data Role swap test. 277370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 278370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 1. Verify that pd console is accessible 279370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 2. Verify that DUT has a valid PD contract 280370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 3. Determine if DUT advertises support for data swaps 281370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 4. Test DUT initiated and received data swaps 282370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 5. Swap power roles if supported 283370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 6. Repeat DUT received data swap requests 284370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 285370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott """ 286370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # create objects for pd utilities 287370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott self.dut_pd_utils = pd_console.PDConsoleUtils(self.usbpd) 288370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott self.plankton_pd_utils = pd_console.PDConsoleUtils(self.plankton) 289370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 290370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # Make sure PD support exists in the UART console 291370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott if self.dut_pd_utils.verify_pd_console() == False: 292370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott raise error.TestFail("pd command not present on console!") 293370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 294370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # Type C connection (PD contract) should exist at this point 295370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # For this test, the DUT must be connected to a Plankton. 296370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott pd_port = self._find_dut_to_plankton_connection() 297370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott if pd_port == None: 298370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott raise error.TestFail("DUT to Plankton PD connection not found") 299370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott dut_connect_state = self.dut_pd_utils.get_pd_state(pd_port) 300370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott logging.info('Initial DUT connect state = %s', dut_connect_state) 301370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 302370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # Determine if DUT supports data role swaps 303370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott dr_swap_allowed = self.plankton_pd_utils.is_pd_flag_set( 304370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott self.PLANKTON_PORT, 'data_swap') 305370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # Get current DUT data role 306370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott dut_data_role = self._get_data_role(self.dut_pd_utils, pd_port) 307370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott logging.info('Starting DUT Data Role = %r', dut_data_role) 308370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 309370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # If data swaps are not allowed on the DUT, then still 310370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # attempt a data swap and verify that the request is 311370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # rejected by the DUT and that it remains connected and 312370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # in the same role. 313370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott if dr_swap_allowed == False: 314370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott logging.info('Data Swap support not advertised by DUT') 315370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott self._test_data_swap_reject(pd_port) 316370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott logging.info('Data Swap request rejected by DUT as expected') 317370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott else: 318370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # Data role swap support advertised, test this feature. 319370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott self._execute_data_role_swap_test(pd_port) 320370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 321370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # If DUT supports Power Role swap then attempt to change roles. 322370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # This way, data role swaps will be tested in both configurations. 323370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott if self.plankton_pd_utils.is_pd_flag_set( 324370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott self.PLANKTON_PORT, 'power_swap'): 325370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott logging.info('\nDUT advertises Power Swap Support') 326370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # Attempt to swap power roles 327370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott power_swap = self._change_dut_power_role(pd_port) 328370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott if power_swap: 329370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott self._execute_data_role_swap_test(pd_port) 330370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott else: 331370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott logging.warn('Power swap not successful!') 332370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott logging.warn('Only tested with DUT in %s state', 333370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott dut_connect_state) 334370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott else: 335370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott logging.info('DUT does not advertise power swap support') 336370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 337370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott logging.info('***************** Swap Results ********************') 338370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott total_attempts = 0 339370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott total_failures = 0 340370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott for direction, role in self.swap_attempt.iterkeys(): 341370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott logging.info('%s %s swap attempts = %d, failures = %d', 342370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott direction, role, 343370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott self.swap_attempt[(direction, role)], 344370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott self.swap_failure[(direction, role)]) 345370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott total_attempts += self.swap_attempt[(direction, role)] 346370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott total_failures += self.swap_failure[(direction, role)] 347370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott 348370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott # If any swap attempts were not successful, flag test as failure 349370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott if total_failures: 350370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott raise error.TestFail('Data Swap Fail: Attempt = %d, Failure = %d' % 351370f9ef6f3d7fe53775224ec3e8006f0300aba89Scott (total_attempts, total_failures)) 352