faft: Improvements to PDConsoleUtils class

Added two methods to the PDConsoleUtils class. First, added a method
which sends PD control messages and mointors the console for the
control message reply from the other side of the connection. Second,
a method to implement a power role swap.

BRANCH=none
BUG=chrome-os-partner:50176
TEST=Manual
Tested these methods using the soft reset USB PD test.

Change-Id: I26a9f817c84b4f3d3b2a3174caf1e4b5fdcff4f0
Signed-off-by: Scott <scollyer@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/326840
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_console.py b/server/cros/servo/pd_console.py
index 6885d32..0a0aeca 100644
--- a/server/cros/servo/pd_console.py
+++ b/server/cros/servo/pd_console.py
@@ -90,6 +90,25 @@
         """
         return self.console.send_command_get_output(cmd, regexp)
 
+    def send_pd_command_get_reply_msg(self, cmd):
+        """Send PD protocol msg, get PD control msg reply
+
+        The PD console debug mode is enabled prior to sending
+        a pd protocol message. This allows the
+        control message reply to be extracted. The debug mode
+        is disabled prior to exiting.
+
+        @param cmd: pd command to issue to the UART console
+
+        @returns: PD control header message
+        """
+        # Enable PD console debug mode to show control messages
+        self.enable_pd_console_debug()
+        m = self.send_pd_command_get_output(cmd, ['RECV\s([\w]+)'])
+        ctrl_msg = int(m[0][1], 16) & self.PD_CONTROL_MSG_MASK
+        self.disable_pd_console_debug()
+        return ctrl_msg
+
     def verify_pd_console(self):
         """Verify that PD commands exist on UART console
 
@@ -234,6 +253,37 @@
 
         return status
 
+    def swap_power_role(self, port):
+        """Attempt a power role swap
+
+        This method attempts to execute a power role swap. A check
+        is made to ensure that dualrole mode is enabled and that
+        a PD contract is currently established. If both checks pass,
+        then the power role swap command is issued. After a delay,
+        if a PD contract is established and the current state does
+        not equal the starting state, then it was successful.
+
+        @param port: pd port number
+
+        @returns: True if power swap is successful, False otherwise.
+        """
+        # Get starting state
+        if self.is_pd_dual_role_enabled() == False:
+            logging.info('Dualrole Mode not enabled!')
+            return False
+        if self.is_pd_connected(port) == False:
+            logging.info('PD contract not established!')
+            return False
+        current_pr = self.get_pd_state(port)
+        swap_cmd = 'pd %d swap power' % port
+        self.send_pd_command(swap_cmd)
+        time.sleep(self.CONNECT_TIME)
+        new_pr = self.get_pd_state(port)
+        logging.info('Power swap: %s -> %s', current_pr, new_pr)
+        if self.is_pd_connected(port) == False:
+            return False
+        return bool(current_pr != new_pr)
+
     def disable_pd_console_debug(self):
         """Turn off PD console debug
 
@@ -328,7 +378,8 @@
                 # Wait for disconnect timer and give time to reconnect
                 time.sleep(self.dut_console.CONNECT_TIME + DISCONNECT_TIME_SEC)
                 if self.dut_console.is_pd_connected(port):
-                    logging.info('Plankton connection verfied on port %d', port)
+                    logging.info('Plankton connection verified on port %d',
+                                 port)
                     return True
             else:
                 # Could have disconnected other port, allow it to reconnect