Refactoring FAFT keypress code and adding usbkm232 interface.

Cleaned up code to breakout keyboard handlers into thier own classes.
And added support to send keystrokes via usbkm232 cable, which is
required for devices that do not have an internal keyboard.
BUG=None
TEST=Manual testing at desk

Change-Id: Iae13632447695e16e1fa1ce7d29deb41dc48a7fb
Reviewed-on: https://chromium-review.googlesource.com/182539
Reviewed-by: Wai-Hong Tam <waihong@chromium.org>
Tested-by: Yusuf Mohsinally <mohsinally@chromium.org>
Commit-Queue: Yusuf Mohsinally <mohsinally@chromium.org>
diff --git a/server/cros/faft/config/DEFAULTS.py b/server/cros/faft/config/DEFAULTS.py
index c740188..fc09683 100644
--- a/server/cros/faft/config/DEFAULTS.py
+++ b/server/cros/faft/config/DEFAULTS.py
@@ -25,7 +25,6 @@
     ec_capability = list()
     gbb_version = 1.1
     wp_voltage = 'pp1800'
-    key_matrix_layout = 0
     key_checker = [[0x29, 'press'],
                    [0x32, 'press'],
                    [0x32, 'release'],
diff --git a/server/cros/faft/config/parrot.py b/server/cros/faft/config/parrot.py
index 17a4dff..a8557de 100644
--- a/server/cros/faft/config/parrot.py
+++ b/server/cros/faft/config/parrot.py
@@ -14,7 +14,6 @@
     dev_screen = 8
     broken_warm_reset = True
     dark_resume_capable = True
-    key_matrix_layout = 1
     key_checker = [[0x29, 'press'],
                    [0x32, 'press'],
                    [0x32, 'release'],
diff --git a/server/cros/faft/config/stout.py b/server/cros/faft/config/stout.py
index ffd9733..f96c3f9 100644
--- a/server/cros/faft/config/stout.py
+++ b/server/cros/faft/config/stout.py
@@ -8,7 +8,6 @@
 class Values():
     broken_warm_reset = True
     broken_rec_mode = True
-    key_matrix_layout = 2
     key_checker = [[0x29, 'press'],
                    [0x32, 'press'],
                    [0x32, 'release'],
diff --git a/server/cros/faft/faft_classes.py b/server/cros/faft/faft_classes.py
index 7c9390d..cb0c38a 100644
--- a/server/cros/faft/faft_classes.py
+++ b/server/cros/faft/faft_classes.py
@@ -67,6 +67,13 @@
         @param orig_boot_id: A string containing the original boot id.
         @raise ConnectionError: Failed to connect DUT.
         """
+        # When running against panther, we see that sometimes
+        # ping_wait_down() does not work correctly. There needs to
+        # be some investigation to the root cause.
+        # If we sleep for 120s before running get_boot_id(), it
+        # does succeed. But if we change this to ping_wait_down()
+        # there are implications on the wait time when running
+        # commands at the fw screens.
         if not self._client.ping_wait_down(timeout):
             if orig_boot_id and self._client.get_boot_id() != orig_boot_id:
                 logging.warn('Reboot done very quickly.')
@@ -228,17 +235,6 @@
         if self.faft_config.chrome_ec:
             self.ec = chrome_ec.ChromeEC(self.servo)
 
-        if not self.faft_config.has_keyboard:
-            # The environment variable USBKM232_UART_DEVICE should point
-            # to the USB-KM232 UART device.
-            if ('USBKM232_UART_DEVICE' not in os.environ or
-                    not os.path.exists(os.environ['USBKM232_UART_DEVICE'])):
-                raise error.TestError('Must set a valid environment '
-                        'variable USBKM232_UART_DEVICE.')
-
-        # Setting up key matrix mapping
-        self.servo.set_key_matrix(self.faft_config.key_matrix_layout)
-
         self.setup_uart_capture()
         self.setup_servo_log()
         self.install_test_image(self._install_image_path, self._firmware_update)
@@ -843,13 +839,12 @@
                 'firmware_action': self.wait_dev_screen_and_ctrl_d,
             })
 
-    def press_ctrl_d(self):
-        """Send Ctrl-D key to DUT."""
-        if not self.faft_config.has_keyboard:
-            logging.info('Running usbkm232-ctrld...')
-            os.system('usbkm232-ctrld')
-        else:
-            self.servo.ctrl_d()
+    def press_ctrl_d(self, press_secs=''):
+        """Send Ctrl-D key to DUT.
+
+        @param press_secs : Str. Time to press key.
+        """
+        self.servo.ctrl_d(press_secs)
 
     def press_ctrl_u(self):
         """Send Ctrl-U key to DUT.
@@ -858,8 +853,7 @@
                           on a no-build-in-keyboard device.
         """
         if not self.faft_config.has_keyboard:
-            logging.info('Running usbkm232-ctrlu...')
-            os.system('usbkm232-ctrlu')
+            self.servo.ctrl_u()
         elif self.check_ec_capability(['keyboard'], suppress_warning=True):
             self.ec.key_down('<ctrl_l>')
             self.ec.key_down('u')
@@ -872,16 +866,12 @@
             raise error.TestError(
                     "Should specify the ctrl_u_cmd argument.")
 
-    def press_enter(self, press_secs=None):
+    def press_enter(self, press_secs=''):
         """Send Enter key to DUT.
 
         @param press_secs: Seconds of holding the key.
         """
-        if not self.faft_config.has_keyboard:
-            logging.info('Running usbkm232-enter...')
-            os.system('usbkm232-enter')
-        else:
-            self.servo.enter_key(press_secs)
+        self.servo.enter_key(press_secs)
 
     def wait_dev_screen_and_ctrl_d(self):
         """Wait for firmware warning screen and press Ctrl-D."""
diff --git a/server/cros/servo/servo.py b/server/cros/servo/servo.py
index 13d0cd6..b6fb96f 100644
--- a/server/cros/servo/servo.py
+++ b/server/cros/servo/servo.py
@@ -40,12 +40,9 @@
     # TODO(jrbarnette) Being generous is the right thing to do for
     # existing platforms, but if this code is to be used for
     # qualification of new hardware, we should be less generous.
-    LONG_DELAY = 8.5
     SHORT_DELAY = 0.1
-    NORMAL_TRANSITION_DELAY = 1.2
 
     # Maximum number of times to re-read power button on release.
-    RELEASE_RETRY_MAX = 5
     GET_RETRY_MAX = 10
 
     # Delays to deal with DUT state transitions.
@@ -64,41 +61,6 @@
     # Time to wait before timing out on servo initialization.
     INIT_TIMEOUT_SECS = 10
 
-    KEY_MATRIX_ALT_0 = {
-        'ctrl_refresh':  ['0', '0', '0', '1'],
-        'ctrl_d':        ['0', '1', '0', '0'],
-        'd':             ['0', '1', '1', '1'],
-        'ctrl_enter':    ['1', '0', '0', '0'],
-        'enter':         ['1', '0', '1', '1'],
-        'ctrl':          ['1', '1', '0', '0'],
-        'refresh':       ['1', '1', '0', '1'],
-        'unused':        ['1', '1', '1', '0'],
-        'none':          ['1', '1', '1', '1']}
-
-    KEY_MATRIX_ALT_1 = {
-        'ctrl_d':        ['0', '0', '1', '0'],
-        'd':             ['0', '0', '1', '1'],
-        'ctrl_enter':    ['0', '1', '1', '0'],
-        'enter':         ['0', '1', '1', '1'],
-        'ctrl_refresh':  ['1', '0', '0', '1'],
-        'unused':        ['1', '1', '0', '0'],
-        'refresh':       ['1', '1', '0', '1'],
-        'ctrl':          ['1', '1', '1', '0'],
-        'none':          ['1', '1', '1', '1']}
-
-    KEY_MATRIX_ALT_2 = {
-        'ctrl_d':        ['0', '0', '0', '1'],
-        'd':             ['0', '0', '1', '1'],
-        'unused':        ['0', '1', '1', '1'],
-        'rec_mode':      ['1', '0', '0', '0'],
-        'ctrl_enter':    ['1', '0', '0', '1'],
-        'enter':         ['1', '0', '1', '1'],
-        'ctrl':          ['1', '1', '0', '1'],
-        'refresh':       ['1', '1', '1', '0'],
-        'ctrl_refresh':  ['1', '1', '1', '1'],
-        'none':          ['1', '1', '1', '1']}
-
-    KEY_MATRIX = [KEY_MATRIX_ALT_0, KEY_MATRIX_ALT_1, KEY_MATRIX_ALT_2]
 
     def __init__(self, servo_host):
         """Sets up the servo communication infrastructure.
@@ -106,7 +68,6 @@
         @param servo_host: A ServoHost object representing
                            the host running servod.
         """
-        self._key_matrix = 0
         # TODO(fdeng): crbug.com/298379
         # We should move servo_host object out of servo object
         # to minimize the dependencies on the rest of Autotest.
@@ -175,40 +136,25 @@
         # button press (at least on Alex).  To guarantee that this
         # won't happen, we need to allow the EC one second to
         # collect itself.
-        self.power_key(Servo.LONG_DELAY)
-        time.sleep(1.0)
+        self._server.power_long_press()
 
 
     def power_normal_press(self):
         """Simulate a normal power button press."""
-        self.power_key()
+        self._server.power_normal_press()
 
 
     def power_short_press(self):
         """Simulate a short power button press."""
-        self.power_key(Servo.SHORT_DELAY)
+        self._server.power_short_press()
 
 
-    def power_key(self, secs=NORMAL_TRANSITION_DELAY):
+    def power_key(self, press_secs=''):
         """Simulate a power button press.
 
-        Args:
-          secs: Time in seconds to simulate the keypress.
+        @param press_secs : Str. Time to press key.
         """
-        self.set_get_all(['pwr_button:press',
-                          'sleep:%.4f' % secs,
-                          'pwr_button:release'])
-        # TODO(tbroch) Different systems have different release times on the
-        # power button that this loop addresses.  Longer term we may want to
-        # make this delay platform specific.
-        retry = 1
-        while True:
-            value = self.get('pwr_button')
-            if value == 'release' or retry > Servo.RELEASE_RETRY_MAX:
-                break
-            logging.info('Waiting for pwr_button to release, retry %d.', retry)
-            retry += 1
-            time.sleep(Servo.SHORT_DELAY)
+        self._server.power_key(press_secs)
 
 
     def lid_open(self):
@@ -225,84 +171,80 @@
         time.sleep(Servo.SLEEP_DELAY)
 
 
-    def _press_keys(self, key):
-        """Simulate button presses.
+    def ctrl_d(self, press_secs=''):
+        """Simulate Ctrl-d simultaneous button presses.
 
-        Note, key presses will remain on indefinitely. See
-            _press_and_release_keys for release procedure.
+        @param press_secs : Str. Time to press key.
         """
-        (m1_a1_n, m1_a0_n, m2_a1_n, m2_a0_n) = (
-                self.KEY_MATRIX[self._key_matrix]['none'])
-        (m1_a1, m1_a0, m2_a1, m2_a0) = self.KEY_MATRIX[self._key_matrix][key]
-        self.set_get_all(['kbd_m2_a0:%s' % m2_a0_n,
-                          'kbd_m2_a1:%s' % m2_a1_n,
-                          'kbd_m1_a0:%s' % m1_a0_n,
-                          'kbd_m1_a1:%s' % m1_a1_n,
-                          'kbd_en:on',
-                          'kbd_m2_a0:%s' % m2_a0,
-                          'kbd_m2_a1:%s' % m2_a1,
-                          'kbd_m1_a0:%s' % m1_a0,
-                          'kbd_m1_a1:%s' % m1_a1])
+        self._server.ctrl_d(press_secs)
 
 
-    def _press_and_release_keys(self, key, press_secs=None):
-        """Simulate button presses and release."""
-        if press_secs is None:
-            press_secs = self.SERVO_KEY_PRESS_DELAY
-        self._press_keys(key)
-        time.sleep(press_secs)
-        self.set_nocheck('kbd_en', 'off')
+    def ctrl_u(self):
+        """Simulate Ctrl-u simultaneous button presses.
+
+        @param press_secs : Str. Time to press key.
+        """
+        self._server.ctrl_u()
 
 
-    def set_key_matrix(self, matrix=0):
-        """Set keyboard mapping"""
-        self._key_matrix = matrix
+    def ctrl_enter(self, press_secs=''):
+        """Simulate Ctrl-enter simultaneous button presses.
+
+        @param press_secs : Str. Time to press key.
+        """
+        self._server.ctrl_enter(press_secs)
 
 
-    def ctrl_d(self, press_secs=None):
-        """Simulate Ctrl-d simultaneous button presses."""
-        self._press_and_release_keys('ctrl_d', press_secs)
+    def d_key(self, press_secs=''):
+        """Simulate Enter key button press.
+
+        @param press_secs : Str. Time to press key.
+        """
+        self._server.d_key(press_secs)
 
 
-    def ctrl_enter(self, press_secs=None):
-        """Simulate Ctrl-enter simultaneous button presses."""
-        self._press_and_release_keys('ctrl_enter', press_secs)
+    def ctrl_key(self, press_secs=''):
+        """Simulate Enter key button press.
+
+        @param press_secs : Str. Time to press key.
+        """
+        self._server.ctrl_key(press_secs)
 
 
-    def d_key(self, press_secs=None):
-        """Simulate Enter key button press."""
-        self._press_and_release_keys('d', press_secs)
+    def enter_key(self, press_secs=''):
+        """Simulate Enter key button press.
+
+        @param press_secs : Str. Time to press key.
+        """
+        self._server.enter_key(press_secs)
 
 
-    def ctrl_key(self, press_secs=None):
-        """Simulate Enter key button press."""
-        self._press_and_release_keys('ctrl', press_secs)
+    def refresh_key(self, press_secs=''):
+        """Simulate Refresh key (F3) button press.
+
+        @param press_secs : Str. Time to press key.
+        """
+        self._server.refresh_key(press_secs)
 
 
-    def enter_key(self, press_secs=None):
-        """Simulate Enter key button press."""
-        self._press_and_release_keys('enter', press_secs)
-
-
-    def refresh_key(self, press_secs=None):
-        """Simulate Refresh key (F3) button press."""
-        self._press_and_release_keys('refresh', press_secs)
-
-
-    def ctrl_refresh_key(self, press_secs=None):
+    def ctrl_refresh_key(self, press_secs=''):
         """Simulate Ctrl and Refresh (F3) simultaneous press.
 
         This key combination is an alternative of Space key.
+
+        @param press_secs : Str. Time to press key.
         """
-        self._press_and_release_keys('ctrl_refresh', press_secs)
+        self._server.ctrl_refresh_key(press_secs)
 
 
-    def imaginary_key(self, press_secs=None):
+    def imaginary_key(self, press_secs=''):
         """Simulate imaginary key button press.
 
         Maps to a key that doesn't physically exist.
+
+        @param press_secs : Str. Time to press key.
         """
-        self._press_and_release_keys('unused', press_secs)
+        self._server.imaginary_key(press_secs)
 
 
     def enable_recovery_mode(self):