Source code for wlauto.utils.uboot
# Copyright 2014-2015 ARM Limited
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
import re
import time
import logging
from distutils.version import LooseVersion
from wlauto.utils.serial_port import TIMEOUT
logger = logging.getLogger('U-Boot')
[docs]class UbootMenu(object):
"""
Allows navigating Das U-boot menu over serial (it relies on a pexpect connection).
"""
option_regex = re.compile(r'^\[(\d+)\]\s+([^\r]+)\r\n', re.M)
prompt_regex = re.compile(r'^([^\r\n]+):\s*', re.M)
invalid_regex = re.compile(r'Invalid input \(max (\d+)\)', re.M)
uboot_regex = re.compile(r"U-Boot\s(\d\S*)\s")
load_delay = 1 # seconds
default_timeout = 60 # seconds
fixed_uboot_version = '2016.03' # The version on U-Boot that fixed newlines
def __init__(self, conn,
start_prompt='Hit any key to stop autoboot'):
"""
:param conn: A serial connection as returned by ``pexect.spawn()``.
:param prompt: U-Boot menu prompt
:param start_prompt: The starting prompt to wait for during ``open()``.
"""
self.conn = conn
self.conn.crlf = None
self.start_prompt = start_prompt
self.options = {}
self.prompt = None
[docs] def open(self, timeout=default_timeout):
"""
"Open" the UEFI menu by sending an interrupt on STDIN after seeing the
starting prompt (configurable upon creation of the ``UefiMenu`` object.
"""
self.conn.expect(self.start_prompt, timeout)
self._set_line_separator()
self.conn.sendline('')
time.sleep(self.load_delay)
self.conn.readline() # garbage
self.conn.sendline('')
self.prompt = self.conn.readline().strip()
[docs] def getenv(self):
output = self.enter('printenv')
result = {}
for line in output.split('\n'):
if '=' in line:
variable, value = line.split('=', 1)
result[variable.strip()] = value.strip()
return result
[docs] def setenv(self, variable, value, force=False):
force_str = ' -f' if force else ''
if value is not None:
command = 'setenv{} {} {}'.format(force_str, variable, value)
else:
command = 'setenv{} {}'.format(force_str, variable)
return self.enter(command)
[docs] def nudge(self):
"""Send a little nudge to ensure there is something to read. This is useful when you're not
sure if all out put from the serial has been read already."""
self.enter('')
[docs] def enter(self, value, delay=load_delay):
"""Like ``select()`` except no resolution is performed -- the value is sent directly
to the serial connection."""
# Empty the buffer first, so that only response to the input about to
# be sent will be processed by subsequent commands.
value = str(value)
self.empty_buffer()
self.write_characters(value)
self.conn.expect(self.prompt, timeout=delay)
return self.conn.before
[docs] def write_characters(self, line):
line = line.rstrip('\r\n')
for c in line:
self.conn.send(c)
time.sleep(0.05)
self.conn.sendline('')
[docs] def empty_buffer(self):
try:
while True:
time.sleep(0.1)
self.conn.read_nonblocking(size=1024, timeout=0.1)
except TIMEOUT:
pass
self.conn.buffer = ''
def _set_line_separator(self):
uboot_text = self.conn.before
uboot_ver = self.uboot_regex.findall(uboot_text)
if uboot_ver and LooseVersion(uboot_ver[0]) < LooseVersion(self.fixed_uboot_version):
self.conn.crlf = "\n\r"
else:
self.conn.crlf = "\r\n"