Home | History | Annotate | Download | only in utils
      1 #
      2 #    Copyright 2015 ARM Limited
      3 #
      4 # Licensed under the Apache License, Version 2.0 (the "License");
      5 # you may not use this file except in compliance with the License.
      6 # You may obtain a copy of the License at
      7 #
      8 #     http://www.apache.org/licenses/LICENSE-2.0
      9 #
     10 # Unless required by applicable law or agreed to in writing, software
     11 # distributed under the License is distributed on an "AS IS" BASIS,
     12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 # See the License for the specific language governing permissions and
     14 # limitations under the License.
     15 #
     16 import re
     17 import time
     18 import logging
     19 
     20 from devlib.utils.serial_port import TIMEOUT
     21 
     22 
     23 logger = logging.getLogger('U-Boot')
     24 
     25 
     26 class UbootMenu(object):
     27     """
     28     Allows navigating Das U-boot menu over serial (it relies on a pexpect connection).
     29 
     30     """
     31 
     32     option_regex = re.compile(r'^\[(\d+)\]\s+([^\r]+)\r\n', re.M)
     33     prompt_regex = re.compile(r'^([^\r\n]+):\s*', re.M)
     34     invalid_regex = re.compile(r'Invalid input \(max (\d+)\)', re.M)
     35 
     36     load_delay = 1  # seconds
     37     default_timeout = 60  # seconds
     38 
     39     def __init__(self, conn, start_prompt='Hit any key to stop autoboot'):
     40         """
     41         :param conn: A serial connection as returned by ``pexect.spawn()``.
     42         :param prompt: U-Boot menu prompt
     43         :param start_prompt: The starting prompt to wait for during ``open()``.
     44 
     45         """
     46         self.conn = conn
     47         self.conn.crlf = '\n\r'  # TODO: this has *got* to be a bug in U-Boot...
     48         self.start_prompt = start_prompt
     49         self.options = {}
     50         self.prompt = None
     51 
     52     def open(self, timeout=default_timeout):
     53         """
     54         "Open" the UEFI menu by sending an interrupt on STDIN after seeing the
     55         starting prompt (configurable upon creation of the ``UefiMenu`` object.
     56 
     57         """
     58         self.conn.expect(self.start_prompt, timeout)
     59         self.conn.sendline('')
     60         time.sleep(self.load_delay)
     61         self.conn.readline()  # garbage
     62         self.conn.sendline('')
     63         self.prompt = self.conn.readline().strip()
     64 
     65     def getenv(self):
     66         output = self.enter('printenv')
     67         result = {}
     68         for line in output.split('\n'):
     69             if '=' in line:
     70                 variable, value = line.split('=', 1)
     71                 result[variable.strip()] = value.strip()
     72         return result
     73 
     74     def setenv(self, variable, value, force=False):
     75         force_str = ' -f' if force else ''
     76         if value is not None:
     77             command = 'setenv{} {} {}'.format(force_str, variable, value)
     78         else:
     79             command = 'setenv{} {}'.format(force_str, variable)
     80         return self.enter(command)
     81 
     82     def boot(self):
     83         self.write_characters('boot')
     84 
     85     def nudge(self):
     86         """Send a little nudge to ensure there is something to read. This is useful when you're not
     87         sure if all out put from the serial has been read already."""
     88         self.enter('')
     89 
     90     def enter(self, value, delay=load_delay):
     91         """Like ``select()`` except no resolution is performed -- the value is sent directly
     92         to the serial connection."""
     93         # Empty the buffer first, so that only response to the input about to
     94         # be sent will be processed by subsequent commands.
     95         value = str(value)
     96         self.empty_buffer()
     97         self.write_characters(value)
     98         self.conn.expect(self.prompt, timeout=delay)
     99         return self.conn.before
    100 
    101     def write_characters(self, line):
    102         line = line.rstrip('\r\n')
    103         for c in line:
    104             self.conn.send(c)
    105             time.sleep(0.05)
    106         self.conn.sendline('')
    107 
    108     def empty_buffer(self):
    109         try:
    110             while True:
    111                 time.sleep(0.1)
    112                 self.conn.read_nonblocking(size=1024, timeout=0.1)
    113         except TIMEOUT:
    114             pass
    115         self.conn.buffer = ''
    116 
    117