hdctools: ec: Add controls to issue EC UART commands and to get its results.

Originally FAFT directly controls the UART to send EC commands. However, we
can't do it in Autotest lab. Since the servo board is not connected to the
autoserv machine. Servod should suppport these similar functions.

So three new controls are added, on the devices which have Chrome EC.
 - ec_uart_timeout:
       Timeout value for waiting EC UART response of issuing an EC command.
 - ec_uart_regexp:
       The regular expression to match the response of EC command.
 - ec_uart_cmd:
       Set: To send the command to EC UART. Its response is matched using the
            regular expression of ec_uart_regexp.
       Get: To obtain the matched results of the latest EC command.

BUG=chromium-os:34787
TEST=manaul, with the changes on Autotest side.
$ run_remote_tests.sh --remote $DUT suite:faft_ec

Change-Id: I620edc1dbdc02595a45772dbafa0d04914b2ed1b
Reviewed-on: https://gerrit.chromium.org/gerrit/34608
Commit-Ready: Tom Wai-Hong Tam <waihong@chromium.org>
Reviewed-by: Tom Wai-Hong Tam <waihong@chromium.org>
Tested-by: Tom Wai-Hong Tam <waihong@chromium.org>
diff --git a/servo/data/servo_daisy_overlay.xml b/servo/data/servo_daisy_overlay.xml
index 64ff39c..79c4690 100644
--- a/servo/data/servo_daisy_overlay.xml
+++ b/servo/data/servo_daisy_overlay.xml
@@ -51,4 +51,20 @@
     <params cmd="get" subtype="milliwatts" interface="7" drv="ec"
     clobber_ok=""></params>
   </control>
+  <control>
+    <name>ec_uart_cmd</name>
+    <doc>Set to send command to EC UART. Get to obtain the matched results with
+    the regular expression of ec_uart_regexp.</doc>
+    <params subtype="uart_cmd" interface="7" drv="ec" input_type="str"></params>
+  </control>
+  <control>
+    <name>ec_uart_regexp</name>
+    <doc>List of regular expressions which matches the response of ec_uart_cmd.</doc>
+    <params subtype="uart_regexp" interface="7" drv="ec" input_type="str"></params>
+  </control>
+  <control>
+    <name>ec_uart_timeout</name>
+    <doc>Timeout value for waiting EC UART response of issuing an EC command.</doc>
+    <params subtype="uart_timeout" interface="7" drv="ec" input_type="float"></params>
+  </control>
 </root>
diff --git a/servo/data/servo_link_overlay.xml b/servo/data/servo_link_overlay.xml
index 6b2de48..a75d123 100644
--- a/servo/data/servo_link_overlay.xml
+++ b/servo/data/servo_link_overlay.xml
@@ -85,4 +85,20 @@
     <doc>Current fan duty cycle.</doc>
     <params cmd="get" subtype="fan_duty" interface="7" drv="ec"></params>
   </control>
+  <control>
+    <name>ec_uart_cmd</name>
+    <doc>Set to send command to EC UART. Get to obtain the matched results with
+    the regular expression of ec_uart_regexp.</doc>
+    <params subtype="uart_cmd" interface="7" drv="ec" input_type="str"></params>
+  </control>
+  <control>
+    <name>ec_uart_regexp</name>
+    <doc>List of regular expressions which matches the response of ec_uart_cmd.</doc>
+    <params subtype="uart_regexp" interface="7" drv="ec" input_type="str"></params>
+  </control>
+  <control>
+    <name>ec_uart_timeout</name>
+    <doc>Timeout value for waiting EC UART response of issuing an EC command.</doc>
+    <params subtype="uart_timeout" interface="7" drv="ec" input_type="float"></params>
+  </control>
 </root>
diff --git a/servo/drv/ec.py b/servo/drv/ec.py
index 464c42c..40591a4 100644
--- a/servo/drv/ec.py
+++ b/servo/drv/ec.py
@@ -12,6 +12,7 @@
   kbd_m2_a1
   dev_mode (Temporary. See crosbug.com/p/9341)
 """
+import ast
 import fdpexpect
 import logging
 import os
@@ -25,7 +26,10 @@
                 'kbd_m1_a0': 1,
                 'kbd_m1_a1': 1,
                 'kbd_m2_a0': 1,
-                'kbd_m2_a1': 1}
+                'kbd_m2_a1': 1,
+                'uart_cmd': None,
+                'uart_regexp': None,
+                'uart_timeout': 0.3}
 
 # Key matrix row and column mapped from kbd_m*_a*
 KEY_MATRIX = [[[(0,4), (11,4)], [(2,4), None]],
@@ -117,7 +121,7 @@
     finally:
       self._close()
 
-  def _issue_cmd_get_results(self, cmd, regex_list):
+  def _issue_cmd_get_results(self, cmd, regex_list, timeout=0.3):
     """Send command to EC and wait for response.
 
     This function waits for response message matching a regular
@@ -127,6 +131,7 @@
       cmd: The command issued.
       regex_list: List of Regular expressions used to match response message.
         Note, list must be ordered.
+      timeout: Timeout value for waiting UART response.
 
     Returns:
       List of tuples, each of which contains the entire matched string and
@@ -150,7 +155,7 @@
       self._send(cmd)
       self._logger.debug("Sending cmd: %s" % cmd)
       for regex in regex_list:
-        self._child.expect(regex, timeout=0.3)
+        self._child.expect(regex, timeout)
         match = self._child.match
         lastindex = match.lastindex if match and match.lastindex else 0
         # Create a tuple which contains the entire matched string and all
@@ -466,3 +471,70 @@
     else:
       # "-1" is treated as max fan RPM in EC, so we don't need to handle that
       self._issue_cmd("fanset %d" % value)
+
+  def _Set_uart_timeout(self, timeout):
+    """Set timeout value for waiting EC UART response.
+
+    Args:
+      timeout: Timeout value in second.
+    """
+    self._dict['uart_timeout'] = timeout
+
+  def _Get_uart_timeout(self):
+    """Get timeout value for waiting EC UART response.
+
+    Returns:
+      Timeout value in second.
+    """
+    return self._dict['uart_timeout']
+
+  def _Set_uart_regexp(self, regexp):
+    """Set the list of regular expressions which matches the command response.
+
+    Args:
+      regexp: A string which contains a list of regular expressions.
+    """
+    if not isinstance(regexp, str):
+      raise ecError('The argument regexp should be a string.')
+    self._dict['uart_regexp'] = ast.literal_eval(regexp)
+
+  def _Get_uart_regexp(self):
+    """Get the list of regular expressions which matches the command response.
+
+    Returns:
+      A string which contains a list of regular expressions.
+    """
+    return str(self._dict['uart_regexp'])
+
+  def _Set_uart_cmd(self, cmd):
+    """Set the UART command and send it to EC UART.
+
+    If ec_uart_regexp is 'None', the command is just sent and it doesn't care
+    about its response.
+
+    If ec_uart_regexp is not 'None', the command is send and its response,
+    which matches the regular expression of ec_uart_regexp, will be kept.
+    Use its getter to obtain this result. If no match after ec_uart_timeout
+    seconds, a timeout error will be raised.
+
+    Args:
+      cmd: A string of UART command.
+    """
+    if self._dict['uart_regexp']:
+      self._dict['uart_cmd'] = self._issue_cmd_get_results(
+                                   cmd,
+                                   self._dict['uart_regexp'],
+                                   self._dict['uart_timeout'])
+    else:
+      self._dict['uart_cmd'] = None
+      self._issue_cmd(cmd)
+
+  def _Get_uart_cmd(self):
+    """Get the result of the latest UART command.
+
+    Returns:
+      A string which contains a list of tuples, each of which contains the
+      entire matched string and all the subgroups of the match. 'None' if
+      the ec_uart_regexp is 'None'.
+    """
+    return str(self._dict['uart_cmd'])