faft: Added USB PD soft reset test
Created a test which executes USB PD soft resets initiated by
both of the port partners. If the connection supports a power
role swap, the power role is swapped, and the test is repeated.
BRANCH=none
BUG=chrome-os-partner:50178
TEST=Manual
Tested with Samus to Plankton. Verfied that soft resets are initiated
and the state transition history can be used to verify expected operation.
Change-Id: Ia0119bd3f9e4dce4cddaf8f91e232a8571439c80
Signed-off-by: Scott <scollyer@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/326785
Commit-Ready: Scott Collyer <scollyer@chromium.org>
Tested-by: Scott Collyer <scollyer@chromium.org>
Reviewed-by: Todd Broch <tbroch@chromium.org>
diff --git a/server/cros/servo/pd_device.py b/server/cros/servo/pd_device.py
index 209eb87..f0fb2fe 100644
--- a/server/cros/servo/pd_device.py
+++ b/server/cros/servo/pd_device.py
@@ -91,9 +91,10 @@
raise NotImplementedError(
'vbus_request should be implemented in derived class')
- def soft_reset(self):
+ def soft_reset(self, states_list=None):
"""Initates a PD soft reset sequence
+ @param states_list: list of expected PD state transitions
"""
raise NotImplementedError(
'drp_set should be implemented in derived class')
@@ -276,6 +277,59 @@
val = 'off'
return bool(val == m[0][1])
+ def soft_reset(self, states_list=None):
+ """Initates a PD soft reset sequence
+
+ To verify that a soft reset sequence was initiated, the
+ reply message is checked to verify that the reset command
+ was acknowledged by its port pair. The connect state should
+ be same as it was prior to issuing the reset command.
+
+ @param states_list: list of expected PD state transitions
+
+ @returns True if the port pair acknowledges the the reset message
+ and if following the command, the device returns to the same
+ connected state. False otherwise.
+ """
+ RESET_DELAY = 0.5
+ cmd = 'pd %d soft' % self.port
+ state_before = self.utils.get_pd_state(self.port)
+ reply = self.utils.send_pd_command_get_reply_msg(cmd)
+ if reply != self.utils.PD_CONTROL_MSG_DICT['Accept']:
+ return False
+ time.sleep(RESET_DELAY)
+ state_after = self.utils.get_pd_state(self.port)
+ return state_before == state_after
+
+ def pr_swap(self):
+ """Attempts a power role swap
+
+ In order to attempt a power role swap the device must be
+ connected and support dualrole mode. Once these two criteria
+ are checked a power role command is issued. Following a delay
+ to allow for a reconnection the new power role is checked
+ against the power role prior to issuing the command.
+
+ @returns True if the device has swapped power roles, False otherwise.
+ """
+ # Get starting state
+ if not self.is_drp() and not self.drp_set('on'):
+ logging.warn('Dualrole Mode not enabled!')
+ return False
+ if self.is_connected() == False:
+ logging.warn('PD contract not established!')
+ return False
+ current_pr = self.utils.get_pd_state(self.port)
+ swap_cmd = 'pd %d swap power' % self.port
+ self.utils.send_pd_command(swap_cmd)
+ time.sleep(self.utils.CONNECT_TIME)
+ new_pr = self.utils.get_pd_state(self.port)
+ logging.info('Power swap: %s -> %s', current_pr, new_pr)
+ if self.is_connected() == False:
+ logging.warn('Device not connected following PR swap attempt.')
+ return False
+ return current_pr != new_pr
+
class PDPlanktonDevice(PDConsoleDevice):
"""Class for PD Plankton devices
@@ -325,6 +379,22 @@
logging.error('Plankton DRP mode set failure')
return False
+ def _verify_state_sequence(self, states_list, console_log):
+ """Compare PD state transitions to expected values
+
+ @param states_list: list of expected PD state transitions
+ @param console_log: console output which contains state names
+ @returns True if the sequence matches, False otherwise
+ """
+ # For each state in the expected state transiton table, build
+ # the regexp and search for it in the state transition log.
+ for state in states_list:
+ state_regx = r'C{0}\s+[\w]+:\s({1})'.format(self.port,
+ state)
+ if re.search(state_regx, console_log) is None:
+ return False
+ return True
+
def cc_disconnect_connect(self, disc_time_sec):
"""Disconnect/reconnect using Plankton
@@ -365,6 +435,23 @@
# With drp_enable flag off, can set to desired setting
return self.utils.set_pd_dualrole(mode)
+ def soft_reset(self, states_list):
+ """Initates a PD soft reset sequence
+
+ Plankton device has state names available on the console. When
+ a soft reset is issued the console log is extracted and then
+ compared against the expected state transisitons.
+
+ @param states_list: list of expected PD state transitions
+
+ @returns True if state transitions match, False otherwise
+ """
+ cmd = 'pd %d soft' % self.port
+ # Want to grab all output until either SRC_READY or SNK_READY
+ reply_exp = ['(.*)(C\d)\s+[\w]+:\s([\w]+_READY)']
+ m = self.utils.send_pd_command_get_output(cmd, reply_exp)
+ return self._verify_state_sequence(states_list, m[0][0])
+
class PDPortPartner(object):
"""Methods used to instantiate PD device objects