You've already forked slimbootloader
mirror of
https://github.com/Dasharo/slimbootloader.git
synced 2026-03-06 15:26:20 -08:00
Fix loading and saving issues with SblSetup payload when Config Data layout differs from ConfigDataDef.json file. ConfigDataDef.json used by setup payload has config data order based on defaults, while actual binary config values retrieved from ConfigLib can have order changes triggered by board deltas. Signed-off-by: Bejean Mosher <bejean.mosher@intel.com>
2041 lines
70 KiB
Python
2041 lines
70 KiB
Python
## @ GenCfgData.py
|
|
#
|
|
# Copyright (c) 2020 - 2023, Intel Corporation. All rights reserved.<BR>
|
|
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
#
|
|
##
|
|
|
|
import os
|
|
import sys
|
|
import re
|
|
import struct
|
|
import marshal
|
|
import pprint
|
|
import string
|
|
import operator as op
|
|
import ast
|
|
import binascii
|
|
import fnmatch
|
|
from datetime import date
|
|
from collections import OrderedDict
|
|
|
|
from CommonUtility import *
|
|
|
|
# Generated file copyright header
|
|
__copyright_tmp__ = """/** @file
|
|
|
|
Platform Configuration %s File.
|
|
|
|
Copyright (c) %4d, Intel Corporation. All rights reserved.<BR>
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
|
This file is automatically generated. Please do NOT modify !!!
|
|
|
|
**/
|
|
"""
|
|
|
|
def get_copyright_header (file_type, allow_modify = False):
|
|
file_description = {
|
|
'yaml': 'Boot Setting',
|
|
'dlt' : 'Delta',
|
|
'inc' : 'C Binary Blob',
|
|
'h' : 'C Struct Header'
|
|
}
|
|
if file_type in ['yaml', 'dlt']:
|
|
comment_char = '#'
|
|
else:
|
|
comment_char = ''
|
|
lines = __copyright_tmp__.split('\n')
|
|
if allow_modify:
|
|
lines = [line for line in lines if 'Please do NOT modify' not in line]
|
|
copyright_hdr = '\n'.join('%s%s' % (comment_char, line) for line in lines)[:-1] + '\n'
|
|
return copyright_hdr % (file_description[file_type], date.today().year)
|
|
|
|
def check_quote (text):
|
|
if (text[0] == "'" and text[-1] == "'") or (text[0] == '"' and text[-1] == '"'):
|
|
return True
|
|
return False
|
|
|
|
def strip_quote (text):
|
|
new_text = text.strip()
|
|
if check_quote (new_text):
|
|
return new_text[1:-1]
|
|
return text
|
|
|
|
def strip_delimiter (text, delim):
|
|
new_text = text.strip()
|
|
if new_text:
|
|
if new_text[0] == delim[0] and new_text[-1] == delim[-1]:
|
|
return new_text[1:-1]
|
|
return text
|
|
|
|
def bytes_to_bracket_str (bytes):
|
|
return '{ %s }' % (', '.join('0x%02x' % i for i in bytes))
|
|
|
|
def array_str_to_value (val_str):
|
|
val_str = val_str.strip()
|
|
val_str = strip_delimiter (val_str, '{}')
|
|
val_str = strip_quote (val_str)
|
|
value = 0
|
|
for each in val_str.split(',')[::-1]:
|
|
each = each.strip()
|
|
value = (value << 8) | int(each, 0)
|
|
return value
|
|
|
|
def write_lines (lines, file):
|
|
fo = open(file, "w")
|
|
fo.write (''.join ([x[0] for x in lines]))
|
|
fo.close ()
|
|
|
|
def read_lines (file):
|
|
if not os.path.exists(file):
|
|
test_file = os.path.basename(file)
|
|
if os.path.exists(test_file):
|
|
file = test_file
|
|
fi = open (file, 'r')
|
|
lines = fi.readlines ()
|
|
fi.close ()
|
|
return lines
|
|
|
|
def expand_file_value (path, value_str):
|
|
result = bytearray()
|
|
match = re.match("\\{\\s*FILE:(.+)\\}", value_str)
|
|
if match:
|
|
file_list = match.group(1).split(',')
|
|
for file in file_list:
|
|
file = file.strip()
|
|
bin_path = os.path.join(path, file)
|
|
result.extend(bytearray(open(bin_path, 'rb').read()))
|
|
return result
|
|
|
|
class ExpressionEval(ast.NodeVisitor):
|
|
operators = {
|
|
ast.Add: op.add,
|
|
ast.Sub: op.sub,
|
|
ast.Mult: op.mul,
|
|
ast.Div: op.floordiv,
|
|
ast.Mod: op.mod,
|
|
ast.Eq: op.eq,
|
|
ast.NotEq: op.ne,
|
|
ast.Gt: op.gt,
|
|
ast.Lt: op.lt,
|
|
ast.GtE: op.ge,
|
|
ast.LtE: op.le,
|
|
ast.BitXor: op.xor,
|
|
ast.BitAnd: op.and_,
|
|
ast.BitOr: op.or_,
|
|
ast.Invert: op.invert,
|
|
ast.USub: op.neg
|
|
}
|
|
|
|
|
|
def __init__(self):
|
|
self._debug = False
|
|
self._expression = ''
|
|
self._namespace = {}
|
|
self._get_variable = None
|
|
|
|
def eval(self, expr, vars={}):
|
|
self._expression = expr
|
|
if type(vars) is dict:
|
|
self._namespace = vars
|
|
self._get_variable = None
|
|
else:
|
|
self._namespace = {}
|
|
self._get_variable = vars
|
|
node = ast.parse(self._expression, mode='eval')
|
|
result = self.visit(node.body)
|
|
if self._debug:
|
|
print ('EVAL [ %s ] = %s' % (expr, str(result)))
|
|
return result
|
|
|
|
def visit_Name(self, node):
|
|
if self._get_variable is not None:
|
|
return self._get_variable(node.id)
|
|
else:
|
|
return self._namespace[node.id]
|
|
|
|
def visit_Num(self, node):
|
|
return node.n
|
|
|
|
def visit_NameConstant(self, node):
|
|
return node.value
|
|
|
|
def visit_BoolOp(self, node):
|
|
result = False
|
|
if isinstance(node.op, ast.And):
|
|
for value in node.values:
|
|
result = self.visit(value)
|
|
if not result:
|
|
break
|
|
elif isinstance(node.op, ast.Or):
|
|
for value in node.values:
|
|
result = self.visit(value)
|
|
if result:
|
|
break
|
|
return True if result else False
|
|
|
|
def visit_UnaryOp(self, node):
|
|
val = self.visit(node.operand)
|
|
return operators[type(node.op)](val)
|
|
|
|
def visit_BinOp(self, node):
|
|
lhs = self.visit(node.left)
|
|
rhs = self.visit(node.right)
|
|
return ExpressionEval.operators[type(node.op)](lhs, rhs)
|
|
|
|
def visit_Compare(self, node):
|
|
right = self.visit(node.left)
|
|
result = True
|
|
for operation, comp in zip(node.ops, node.comparators):
|
|
if not result:
|
|
break
|
|
left = right
|
|
right = self.visit(comp)
|
|
result = ExpressionEval.operators[type(operation)](left, right)
|
|
return result
|
|
|
|
def visit_Call(self, node):
|
|
if node.func.id in ['ternary']:
|
|
condition = self.visit (node.args[0])
|
|
val_true = self.visit (node.args[1])
|
|
val_false = self.visit (node.args[2])
|
|
return val_true if condition else val_false
|
|
elif node.func.id in ['offset', 'length']:
|
|
if self._get_variable is not None:
|
|
return self._get_variable(node.args[0].s, node.func.id)
|
|
else:
|
|
raise ValueError("Unsupported function: " + repr(node))
|
|
|
|
def generic_visit(self, node):
|
|
raise ValueError("malformed node or string: " + repr(node))
|
|
|
|
|
|
class CFG_YAML():
|
|
TEMPLATE = 'template'
|
|
CONFIGS = 'configs'
|
|
VARIABLE = 'variable'
|
|
|
|
def __init__ (self):
|
|
self.log_line = False
|
|
self.allow_template = False
|
|
self.cfg_tree = None
|
|
self.tmp_tree = None
|
|
self.var_dict = None
|
|
self.def_dict = {}
|
|
self.yaml_path = ''
|
|
self.lines = []
|
|
self.full_lines = []
|
|
self.index = 0
|
|
self.re_expand = re.compile (r'(.+:\s+|\s*\-\s*)!expand\s+\{\s*(\w+_TMPL)\s*:\s*\[(.+)]\s*\}')
|
|
self.re_include = re.compile (r'(.+:\s+|\s*\-\s*)!include\s+(.+)')
|
|
|
|
@staticmethod
|
|
def count_indent (line):
|
|
return next((i for i, c in enumerate(line) if not c.isspace()), len(line))
|
|
|
|
@staticmethod
|
|
def substitue_args (text, arg_dict):
|
|
for arg in arg_dict:
|
|
text = text.replace ('$' + arg, arg_dict[arg])
|
|
return text
|
|
|
|
@staticmethod
|
|
def dprint (*args):
|
|
pass
|
|
|
|
def process_include (self, line, insert = True):
|
|
match = self.re_include.match (line)
|
|
if not match:
|
|
raise Exception ("Invalid !include format '%s' !" % line.strip())
|
|
|
|
prefix = match.group(1)
|
|
include = match.group(2)
|
|
if prefix.strip() == '-':
|
|
prefix = ''
|
|
adjust = 0
|
|
else:
|
|
adjust = 2
|
|
|
|
include = strip_quote (include)
|
|
request = CFG_YAML.count_indent (line) + adjust
|
|
|
|
if self.log_line:
|
|
# remove the include line itself
|
|
del self.full_lines[-1]
|
|
|
|
inc_path = os.path.join (self.yaml_path, include)
|
|
if not os.path.exists(inc_path):
|
|
# try relative path to project root
|
|
try_path = os.path.join(os.path.dirname (os.path.realpath(__file__)), "../..", include)
|
|
if os.path.exists(try_path):
|
|
inc_path = try_path
|
|
else:
|
|
raise Exception ("ERROR: Cannot open file '%s'." % inc_path)
|
|
|
|
lines = read_lines (inc_path)
|
|
|
|
current = 0
|
|
same_line = False
|
|
for idx, each in enumerate (lines):
|
|
start = each.lstrip()
|
|
if start == '' or start[0] == '#':
|
|
continue
|
|
|
|
if start[0] == '>':
|
|
# append the content directly at the same line
|
|
same_line = True
|
|
|
|
start = idx
|
|
current = CFG_YAML.count_indent (each)
|
|
break
|
|
|
|
lines = lines[start+1:] if same_line else lines[start:]
|
|
leading = ''
|
|
if same_line:
|
|
request = len(prefix)
|
|
leading = '>'
|
|
|
|
lines = [prefix + '%s\n' % leading] + [' ' * request + i[current:] for i in lines]
|
|
if insert:
|
|
self.lines = lines + self.lines
|
|
|
|
return lines
|
|
|
|
def process_expand (self, line):
|
|
match = self.re_expand.match(line)
|
|
if not match:
|
|
raise Exception ("Invalid !expand format '%s' !" % line.strip())
|
|
lines = []
|
|
prefix = match.group(1)
|
|
temp_name = match.group(2)
|
|
args = match.group(3)
|
|
|
|
if prefix.strip() == '-':
|
|
indent = 0
|
|
else:
|
|
indent = 2
|
|
lines = self.process_expand_template (temp_name, prefix, args, indent)
|
|
self.lines = lines + self.lines
|
|
|
|
|
|
def process_expand_template (self, temp_name, prefix, args, indent = 2):
|
|
# expand text with arg substitution
|
|
if temp_name not in self.tmp_tree:
|
|
raise Exception ("Could not find template '%s' !" % temp_name)
|
|
parts = args.split(',')
|
|
parts = [i.strip() for i in parts]
|
|
num = len(parts)
|
|
arg_dict = dict(zip( ['(%d)' % (i + 1) for i in range(num)], parts))
|
|
str_data = self.tmp_tree[temp_name]
|
|
text = DefTemplate(str_data).safe_substitute(self.def_dict)
|
|
text = CFG_YAML.substitue_args (text, arg_dict)
|
|
target = CFG_YAML.count_indent (prefix) + indent
|
|
current = CFG_YAML.count_indent (text)
|
|
padding = target * ' '
|
|
if indent == 0:
|
|
leading = []
|
|
else:
|
|
leading = [prefix + '\n']
|
|
text = leading + [(padding + i + '\n')[current:] for i in text.splitlines()]
|
|
return text
|
|
|
|
|
|
def load_file (self, yaml_file):
|
|
self.index = 0
|
|
self.lines = read_lines (yaml_file)
|
|
|
|
|
|
def peek_line (self):
|
|
if len(self.lines) == 0:
|
|
return None
|
|
else:
|
|
return self.lines[0]
|
|
|
|
|
|
def put_line (self, line):
|
|
self.lines.insert (0, line)
|
|
if self.log_line:
|
|
del self.full_lines[-1]
|
|
|
|
|
|
def get_line (self):
|
|
if len(self.lines) == 0:
|
|
return None
|
|
else:
|
|
line = self.lines.pop(0)
|
|
if self.log_line:
|
|
self.full_lines.append (line.rstrip())
|
|
return line
|
|
|
|
|
|
def get_multiple_line (self, indent):
|
|
text = ''
|
|
newind = indent + 1
|
|
while True:
|
|
line = self.peek_line ()
|
|
if line is None:
|
|
break
|
|
sline = line.strip()
|
|
if sline != '':
|
|
newind = CFG_YAML.count_indent(line)
|
|
if newind <= indent:
|
|
break
|
|
self.get_line ()
|
|
if sline != '':
|
|
text = text + line
|
|
return text
|
|
|
|
|
|
def traverse_cfg_tree (self, handler):
|
|
def _traverse_cfg_tree (root, level = 0):
|
|
# config structure
|
|
for key in root:
|
|
if type(root[key]) is OrderedDict:
|
|
level += 1
|
|
handler (key, root[key], level)
|
|
_traverse_cfg_tree (root[key], level)
|
|
level -= 1
|
|
_traverse_cfg_tree (self.cfg_tree)
|
|
|
|
|
|
def count (self):
|
|
def _count (name, cfgs, level):
|
|
num[0] += 1
|
|
num = [0]
|
|
self.traverse_cfg_tree (_count)
|
|
return num[0]
|
|
|
|
|
|
def parse (self, parent_name = '', curr = None, level = 0):
|
|
child = None
|
|
last_indent = None
|
|
temp_chk = {}
|
|
|
|
while True:
|
|
line = self.get_line ()
|
|
if line is None:
|
|
break
|
|
|
|
curr_line = line.strip()
|
|
if curr_line == '' or curr_line[0] == '#':
|
|
continue
|
|
|
|
indent = CFG_YAML.count_indent(line)
|
|
if last_indent is None:
|
|
last_indent = indent
|
|
|
|
if indent != last_indent:
|
|
# outside of current block, put the line back to queue
|
|
self.put_line (' ' * indent + curr_line)
|
|
|
|
if curr_line.endswith (': >'):
|
|
# multiline marker
|
|
old_count = len(self.full_lines)
|
|
line = self.get_multiple_line (indent)
|
|
if self.log_line and not self.allow_template and '!include ' in line:
|
|
# expand include in template
|
|
new_lines = []
|
|
lines = line.splitlines()
|
|
for idx, each in enumerate(lines):
|
|
if '!include ' in each:
|
|
new_line = ''.join(self.process_include (each, False))
|
|
new_lines.append(new_line)
|
|
else:
|
|
new_lines.append(each)
|
|
self.full_lines = self.full_lines[:old_count] + new_lines
|
|
curr_line = curr_line + line
|
|
|
|
if indent > last_indent:
|
|
# child nodes
|
|
if child is None:
|
|
raise Exception ('Unexpected format at line: %s' % (curr_line))
|
|
|
|
level += 1
|
|
self.parse (key, child, level)
|
|
level -= 1
|
|
|
|
line = self.peek_line ()
|
|
if line is not None:
|
|
curr_line = line.strip()
|
|
indent = CFG_YAML.count_indent(line)
|
|
if indent >= last_indent:
|
|
# consume the line
|
|
self.get_line ()
|
|
else:
|
|
# end of file
|
|
indent = -1
|
|
|
|
if curr is None:
|
|
curr = OrderedDict()
|
|
|
|
if indent < last_indent:
|
|
return curr
|
|
|
|
marker1 = curr_line[0]
|
|
marker2 = curr_line[-1]
|
|
start = 1 if marker1 == '-' else 0
|
|
pos = curr_line.find(': ')
|
|
if pos > 0:
|
|
child = None
|
|
key = curr_line[start:pos].strip()
|
|
if curr_line[pos + 2] == '>':
|
|
curr[key] = curr_line[pos + 3:]
|
|
else:
|
|
# XXXX: !include / !expand
|
|
if '!include ' in curr_line:
|
|
self.process_include (line)
|
|
elif '!expand ' in curr_line:
|
|
if self.allow_template and not self.log_line:
|
|
self.process_expand (line)
|
|
else:
|
|
value_str = curr_line[pos + 2:].strip()
|
|
curr[key] = value_str
|
|
if self.log_line and value_str[0] == '{':
|
|
# expand {FILE: xxxx} format in the log line
|
|
if value_str[1:].rstrip().startswith('FILE:'):
|
|
value_bytes = expand_file_value (self.yaml_path, value_str)
|
|
value_str = bytes_to_bracket_str (value_bytes)
|
|
self.full_lines[-1] = line[:indent] + curr_line[:pos + 2] + value_str
|
|
|
|
elif marker2 == ':':
|
|
child = OrderedDict()
|
|
key = curr_line[start:-1].strip()
|
|
if key == '$ACTION':
|
|
# special virtual nodes, rename to ensure unique key
|
|
key = '$ACTION_%04X' % self.index
|
|
self.index += 1
|
|
if key in curr:
|
|
if key not in temp_chk:
|
|
# check for duplicated keys at same level
|
|
temp_chk[key] = 1
|
|
else:
|
|
raise Exception ("Duplicated item '%s:%s' found !" % (parent_name, key))
|
|
|
|
curr[key] = child
|
|
if self.var_dict is None and key == CFG_YAML.VARIABLE:
|
|
self.var_dict = child
|
|
if self.tmp_tree is None and key == CFG_YAML.TEMPLATE:
|
|
self.tmp_tree = child
|
|
if self.var_dict:
|
|
for each in self.var_dict:
|
|
txt = self.var_dict[each]
|
|
if type(txt) is str:
|
|
self.def_dict['(%s)' % each] = txt
|
|
if self.tmp_tree and key == CFG_YAML.CONFIGS:
|
|
# apply template for the main configs
|
|
self.allow_template = True
|
|
else:
|
|
child = None
|
|
# - !include cfg_opt.yaml
|
|
if '!include ' in curr_line:
|
|
self.process_include (line)
|
|
|
|
return curr
|
|
|
|
|
|
def load_yaml (self, opt_file):
|
|
self.var_dict = None
|
|
self.yaml_path = os.path.dirname (opt_file)
|
|
self.load_file (opt_file)
|
|
yaml_tree = self.parse ()
|
|
self.tmp_tree = yaml_tree[CFG_YAML.TEMPLATE]
|
|
self.cfg_tree = yaml_tree[CFG_YAML.CONFIGS]
|
|
return self.cfg_tree
|
|
|
|
|
|
def expand_yaml (self, opt_file):
|
|
self.log_line = True
|
|
self.load_yaml (opt_file)
|
|
self.log_line = False
|
|
text = '\n'.join (self.full_lines)
|
|
self.full_lines = []
|
|
return text
|
|
|
|
|
|
class DefTemplate(string.Template):
|
|
idpattern = '\\([_A-Z][_A-Z0-9]*\\)|[_A-Z][_A-Z0-9]*'
|
|
|
|
|
|
class CGenCfgData:
|
|
STRUCT = '$STRUCT'
|
|
PADDINGNAME = '__reserved'
|
|
bits_width = {'b':1, 'B':8, 'W':16, 'D':32, 'Q':64}
|
|
builtin_option = {'$EN_DIS' : [('0', 'Disable'), ('1', 'Enable')]}
|
|
exclude_struct = ['GPIO_GPP_*', 'GPIO_CFG_DATA', 'GpioConfPad*', 'GpioPinConfig',
|
|
'BOOT_OPTION*', 'PLATFORMID_CFG_DATA', '\\w+_Half[01]']
|
|
include_tag = ['GPIO_CFG_DATA']
|
|
keyword_set = set(['name', 'type', 'option', 'help', 'length', 'value', 'order', 'struct', 'condition', 'altpage'])
|
|
|
|
def __init__(self):
|
|
self.initialize ()
|
|
|
|
|
|
def initialize (self):
|
|
self._cfg_tree = {}
|
|
self._tmp_tree = {}
|
|
self._cfg_list = []
|
|
self._cfg_page = {'root': {'title': '', 'child': []}}
|
|
self._cur_page = ''
|
|
self._var_dict = {}
|
|
self._def_dict = {}
|
|
self._yaml_path = ''
|
|
|
|
|
|
@staticmethod
|
|
def deep_convert_dict (layer):
|
|
# convert OrderedDict to list + dict
|
|
new_list = layer
|
|
if isinstance(layer, OrderedDict):
|
|
new_list = list (layer.items())
|
|
for idx, pair in enumerate (new_list):
|
|
new_node = CGenCfgData.deep_convert_dict (pair[1])
|
|
new_list[idx] = dict({pair[0] : new_node})
|
|
return new_list
|
|
|
|
|
|
@staticmethod
|
|
def deep_convert_list (layer):
|
|
if isinstance(layer, list):
|
|
od = OrderedDict({})
|
|
for each in layer:
|
|
if isinstance(each, dict):
|
|
key = next(iter(each))
|
|
od[key] = CGenCfgData.deep_convert_list(each[key])
|
|
return od
|
|
else:
|
|
return layer
|
|
|
|
|
|
@staticmethod
|
|
def expand_include_files (file_path, cur_dir = ''):
|
|
if cur_dir == '':
|
|
cur_dir = os.path.dirname(file_path)
|
|
file_path = os.path.basename(file_path)
|
|
|
|
input_file_path = os.path.join(cur_dir, file_path)
|
|
file = open(input_file_path, "r")
|
|
lines = file.readlines()
|
|
file.close()
|
|
|
|
new_lines = []
|
|
for line_num, line in enumerate(lines):
|
|
match = re.match("^!include\\s*(.+)?$", line.strip())
|
|
if match:
|
|
inc_path = match.group(1)
|
|
tmp_path = os.path.join(cur_dir, inc_path)
|
|
org_path = tmp_path
|
|
if not os.path.exists(tmp_path):
|
|
cur_dir = os.path.join(os.path.dirname (os.path.realpath(__file__)), "..", "..")
|
|
tmp_path = os.path.join(cur_dir, inc_path)
|
|
if not os.path.exists(tmp_path):
|
|
raise Exception ("ERROR: Cannot open include file '%s'." % org_path)
|
|
else:
|
|
new_lines.append (('# Included from file: %s\n' % inc_path, tmp_path, 0))
|
|
new_lines.append (('# %s\n' % ('=' * 80), tmp_path, 0))
|
|
new_lines.extend (CGenCfgData.expand_include_files (inc_path, cur_dir))
|
|
else:
|
|
new_lines.append ((line, input_file_path, line_num))
|
|
|
|
return new_lines
|
|
|
|
|
|
@staticmethod
|
|
def format_struct_field_name (input, count = 0):
|
|
name = ''
|
|
cap = True
|
|
if '_' in input:
|
|
input = input.lower()
|
|
for each in input:
|
|
if each == '_':
|
|
cap = True
|
|
continue
|
|
elif cap:
|
|
each = each.upper()
|
|
cap = False
|
|
name = name + each
|
|
|
|
if count > 1:
|
|
name = '%s[%d]' % (name, count)
|
|
|
|
return name
|
|
|
|
def get_last_error (self):
|
|
return ''
|
|
|
|
|
|
def get_variable (self, var, attr = 'value'):
|
|
if var in self._var_dict:
|
|
var = self._var_dict[var]
|
|
return var
|
|
|
|
item = self.locate_cfg_item (var, False)
|
|
if item is None:
|
|
raise ValueError ("Cannot find variable '%s' !" % var)
|
|
|
|
if item:
|
|
if 'indx' in item:
|
|
item = self.get_item_by_index (item['indx'])
|
|
if attr == 'offset':
|
|
var = item['offset']
|
|
elif attr == 'length':
|
|
var = item['length']
|
|
elif attr == 'value':
|
|
var = self.get_cfg_item_value (item)
|
|
else:
|
|
raise ValueError ("Unsupported variable attribute '%s' !" % attr)
|
|
return var
|
|
|
|
|
|
def eval (self, expr):
|
|
def _handler (pattern):
|
|
if pattern.group(1):
|
|
target = 1
|
|
else:
|
|
target = 2
|
|
result = self.get_variable(pattern.group(target))
|
|
if result is None:
|
|
raise ValueError('Unknown variable $(%s) !' % pattern.group(target))
|
|
return hex(result)
|
|
|
|
expr_eval = ExpressionEval ()
|
|
if '$' in expr:
|
|
# replace known variable first
|
|
expr = re.sub(r'\$\(([_a-zA-Z][\w\.]*)\)|\$([_a-zA-Z][\w\.]*)', _handler, expr)
|
|
return expr_eval.eval(expr, self.get_variable)
|
|
|
|
|
|
def get_cfg_list (self, page_id = None):
|
|
if page_id is None:
|
|
# return full list
|
|
return self._cfg_list
|
|
else:
|
|
# build a new list for items under a page ID
|
|
cfgs = [i for i in self._cfg_list if i['cname'] and ((i['page'] == page_id)
|
|
or (('altpage' in i) and (i['altpage'] == page_id)))]
|
|
return cfgs
|
|
|
|
|
|
def get_cfg_page (self):
|
|
return self._cfg_page
|
|
|
|
def get_cfg_item_length (self, item):
|
|
return item['length']
|
|
|
|
def get_cfg_item_value (self, item, array = False):
|
|
value_str = item['value']
|
|
length = item['length']
|
|
return self.get_value (value_str, length, array)
|
|
|
|
|
|
def format_value_to_str (self, value, bit_length, old_value = ''):
|
|
# value is always int
|
|
length = (bit_length + 7) // 8
|
|
fmt = ''
|
|
if old_value.startswith ('0x'):
|
|
fmt = '0x'
|
|
elif old_value and (old_value[0] in ['"', "'", '{']):
|
|
fmt = old_value[0]
|
|
else:
|
|
fmt = ''
|
|
|
|
bvalue = value_to_bytearray (value, length)
|
|
if fmt in ['"', "'"]:
|
|
svalue = bvalue.rstrip(b'\x00').decode()
|
|
value_str = fmt + svalue + fmt
|
|
elif fmt == "{":
|
|
value_str = '{ ' + ', '.join(['0x%02x' % i for i in bvalue]) + ' }'
|
|
elif fmt == '0x':
|
|
hex_len = length * 2
|
|
if len(old_value) == hex_len + 2:
|
|
fstr = '0x%%0%dX' % hex_len
|
|
else:
|
|
fstr = '0x%X'
|
|
value_str = fstr % value
|
|
else:
|
|
if length <= 2:
|
|
value_str = '%d' % value
|
|
elif length <= 8:
|
|
value_str = '0x%x' % value
|
|
else:
|
|
value_str = '{ ' + ', '.join(['0x%02x' % i for i in bvalue]) + ' }'
|
|
return value_str
|
|
|
|
|
|
def reformat_value_str (self, value_str, bit_length, old_value = None):
|
|
value = self.parse_value (value_str, bit_length, False)
|
|
if old_value is None:
|
|
old_value = value_str
|
|
new_value = self.format_value_to_str (value, bit_length, old_value)
|
|
return new_value
|
|
|
|
|
|
def get_value (self, value_str, bit_length, array = True):
|
|
value_str = value_str.strip()
|
|
if len(value_str) == 0:
|
|
return 0
|
|
if value_str[0] == "'" and value_str[-1] == "'" or \
|
|
value_str[0] == '"' and value_str[-1] == '"':
|
|
value_str = value_str[1:-1]
|
|
bvalue = bytearray (value_str.encode())
|
|
if len(bvalue) == 0:
|
|
bvalue = bytearray(b'\x00')
|
|
if array:
|
|
return bvalue
|
|
else:
|
|
return bytes_to_value (bvalue)
|
|
else:
|
|
if value_str[0] in '{' :
|
|
value_str = value_str[1:-1].strip()
|
|
value = 0
|
|
for each in value_str.split(',')[::-1]:
|
|
each = each.strip()
|
|
value = (value << 8) | int(each, 0)
|
|
if array:
|
|
length = (bit_length + 7) // 8
|
|
return value_to_bytearray (value, length)
|
|
else:
|
|
return value
|
|
|
|
|
|
def parse_value (self, value_str, bit_length, array = True):
|
|
length = (bit_length + 7) // 8
|
|
if check_quote(value_str):
|
|
value_str = bytes_to_bracket_str(value_str[1:-1].encode())
|
|
elif (',' in value_str) and (value_str[0] != '{'):
|
|
value_str = '{ %s }' % value_str
|
|
if value_str[0] == '{':
|
|
result = expand_file_value (self._yaml_path, value_str)
|
|
if len(result) == 0 :
|
|
bin_list = value_str[1:-1].split(',')
|
|
value = 0
|
|
bit_len = 0
|
|
unit_len = 1
|
|
for idx, element in enumerate(bin_list):
|
|
each = element.strip()
|
|
if len(each) == 0:
|
|
continue
|
|
|
|
in_bit_field = False
|
|
if each[0] in "'" + '"':
|
|
each_value = bytearray(each[1:-1], 'utf-8')
|
|
elif ':' in each:
|
|
match = re.match("^(.+):(\\d+)([b|B|W|D|Q])$", each)
|
|
if match is None:
|
|
raise SystemExit("Exception: Invald value list format '%s' !" % each)
|
|
if match.group(1) == '0' and match.group(2) == '0':
|
|
unit_len = CGenCfgData.bits_width[match.group(3)] // 8
|
|
cur_bit_len = int(match.group(2)) * CGenCfgData.bits_width[match.group(3)]
|
|
value += ((self.eval(match.group(1)) & (1<<cur_bit_len) - 1)) << bit_len
|
|
bit_len += cur_bit_len
|
|
each_value = bytearray()
|
|
if idx + 1 < len(bin_list):
|
|
in_bit_field = True
|
|
else:
|
|
try:
|
|
each_value = value_to_bytearray(self.eval(each.strip()), unit_len)
|
|
except:
|
|
raise SystemExit("Exception: Value cannot fit into %s bytes !" % (each, unit_len))
|
|
|
|
if not in_bit_field:
|
|
if bit_len > 0:
|
|
if bit_len % 8 != 0:
|
|
raise SystemExit("Exception: Invalid bit field alignment '%s' !" % value_str)
|
|
result.extend(value_to_bytes(value, bit_len // 8))
|
|
value = 0
|
|
bit_len = 0
|
|
|
|
result.extend(each_value)
|
|
|
|
elif check_quote (value_str):
|
|
result = bytearray(value_str[1:-1], 'utf-8') # Excluding quotes
|
|
else:
|
|
result = value_to_bytearray (self.eval(value_str), length)
|
|
|
|
if len(result) < length:
|
|
result.extend(b'\x00' * (length - len(result)))
|
|
elif len(result) > length:
|
|
raise SystemExit ("Exception: Value '%s' is too big to fit into %d bytes !" % (value_str, length))
|
|
|
|
if array:
|
|
return result
|
|
else:
|
|
return bytes_to_value(result)
|
|
|
|
return result
|
|
|
|
|
|
def get_cfg_item_options (self, item):
|
|
tmp_list = []
|
|
if item['type'] == "Combo":
|
|
if item['option'] in CGenCfgData.builtin_option:
|
|
for op_val, op_str in CGenCfgData.builtin_option[item['option']]:
|
|
tmp_list.append((op_val, op_str))
|
|
else:
|
|
opt_list = item['option'].split(',')
|
|
for option in opt_list:
|
|
option = option.strip()
|
|
try:
|
|
(op_val, op_str) = option.split(':')
|
|
except:
|
|
raise SystemExit ("Exception: Invalid option format '%s' for item '%s' !" % (option, item['cname']))
|
|
tmp_list.append((op_val, op_str))
|
|
return tmp_list
|
|
|
|
|
|
def find_page_path (self, page_id):
|
|
def find_page (page_id, top):
|
|
for node in top['child']:
|
|
page_key = next(iter(node))
|
|
path[-1] = page_key
|
|
if page_id == page_key:
|
|
return True
|
|
else:
|
|
path.append ('')
|
|
result = find_page (page_id, node[page_key])
|
|
if result is not None:
|
|
return result
|
|
path.pop()
|
|
|
|
# path contains a page id list from top level to leaf
|
|
path = ['']
|
|
find_page (page_id, self.get_cfg_page()['root'])
|
|
return path
|
|
|
|
|
|
def get_page_title(self, page_id, top = None):
|
|
if top is None:
|
|
top = self.get_cfg_page()['root']
|
|
for node in top['child']:
|
|
page_key = next(iter(node))
|
|
if page_id == page_key:
|
|
return node[page_key]['title']
|
|
else:
|
|
result = self.get_page_title (page_id, node[page_key])
|
|
if result is not None:
|
|
return result
|
|
return None
|
|
|
|
|
|
def print_pages(self, top=None, level=0):
|
|
if top is None:
|
|
top = self.get_cfg_page()['root']
|
|
for node in top['child']:
|
|
page_id = next(iter(node))
|
|
print('%s%s: %s' % (' ' * level, page_id, node[page_id]['title']))
|
|
level += 1
|
|
self.print_pages(node[page_id], level)
|
|
level -= 1
|
|
|
|
|
|
def get_item_by_index (self, index):
|
|
return self._cfg_list[index]
|
|
|
|
|
|
def get_item_by_path (self, path):
|
|
node = self.locate_cfg_item (path)
|
|
if node:
|
|
return self.get_item_by_index (node['indx'])
|
|
else:
|
|
return None
|
|
|
|
def locate_cfg_path (self, item):
|
|
def _locate_cfg_path (root, level = 0):
|
|
# config structure
|
|
if item is root:
|
|
return path
|
|
for key in root:
|
|
if type(root[key]) is OrderedDict:
|
|
level += 1
|
|
path.append(key)
|
|
ret = _locate_cfg_path (root[key], level)
|
|
if ret:
|
|
return ret
|
|
path.pop()
|
|
return None
|
|
path = []
|
|
return _locate_cfg_path (self._cfg_tree)
|
|
|
|
|
|
def locate_cfg_item (self, path, allow_exp = True):
|
|
def _locate_cfg_item (root, path, level = 0):
|
|
if len(path) == level:
|
|
return root
|
|
next_root = root.get(path[level], None)
|
|
if next_root is None:
|
|
if allow_exp:
|
|
raise Exception ('Not a valid CFG config option path: %s' % '.'.join(path[:level+1]))
|
|
else:
|
|
return None
|
|
return _locate_cfg_item (next_root, path, level + 1)
|
|
|
|
path_nodes = path.split('.')
|
|
return _locate_cfg_item (self._cfg_tree, path_nodes)
|
|
|
|
|
|
def traverse_cfg_tree (self, handler, top = None):
|
|
def _traverse_cfg_tree (root, level = 0):
|
|
# config structure
|
|
for key in root:
|
|
if type(root[key]) is OrderedDict:
|
|
level += 1
|
|
handler (key, root[key], level)
|
|
_traverse_cfg_tree (root[key], level)
|
|
level -= 1
|
|
|
|
if top is None:
|
|
top = self._cfg_tree
|
|
_traverse_cfg_tree (top)
|
|
|
|
|
|
def print_cfgs(self, root = None, short = True, print_level = 256):
|
|
def _print_cfgs (name, cfgs, level):
|
|
|
|
if 'indx' in cfgs:
|
|
act_cfg = self.get_item_by_index (cfgs['indx'])
|
|
else:
|
|
offset = 0
|
|
length = 0
|
|
value = ''
|
|
path=''
|
|
if CGenCfgData.STRUCT in cfgs:
|
|
cfg = cfgs[CGenCfgData.STRUCT]
|
|
offset = int(cfg['offset'])
|
|
length = int(cfg['length'])
|
|
if 'value' in cfg:
|
|
value = cfg['value']
|
|
if length == 0:
|
|
return
|
|
act_cfg = dict({'value' : value, 'offset' : offset, 'length' : length})
|
|
value = act_cfg['value']
|
|
bit_len = act_cfg['length']
|
|
offset = (act_cfg['offset'] + 7) // 8
|
|
if value != '':
|
|
try:
|
|
value = self.reformat_value_str (act_cfg['value'], act_cfg['length'])
|
|
except:
|
|
value = act_cfg['value']
|
|
length = bit_len // 8
|
|
bit_len = '(%db)' % bit_len if bit_len % 8 else '' * 4
|
|
if level <= print_level:
|
|
if short and len(value) > 40:
|
|
value = '%s ... %s' % (value[:20] , value[-20:])
|
|
print('%04X:%04X%-6s %s%s : %s' % (offset, length, bit_len, ' ' * level, name, value))
|
|
|
|
self.traverse_cfg_tree (_print_cfgs)
|
|
|
|
|
|
def find_item_by_name (self, find_name, key = 0):
|
|
def _find_cfgs (name, cfgs, level):
|
|
if 'indx' in cfgs:
|
|
act_cfg = self.get_item_by_index (cfgs['indx'])
|
|
cfg_name = act_cfg['name'].lower()
|
|
if cfg_name:
|
|
if wildcard:
|
|
found = fnmatch.fnmatch(cfg_name, find_name)
|
|
else:
|
|
found = find_name in cfg_name
|
|
if found:
|
|
if instance[0] == key:
|
|
result.append (act_cfg)
|
|
instance[0] += 1
|
|
|
|
result = []
|
|
instance = [0]
|
|
find_name = find_name.lower()
|
|
if '*' in find_name or '?' in find_name:
|
|
wildcard = True
|
|
else:
|
|
wildcard = False
|
|
|
|
self.traverse_cfg_tree (_find_cfgs)
|
|
if len(result) == 0:
|
|
return None
|
|
else:
|
|
return result[0]
|
|
|
|
|
|
def build_var_dict (self):
|
|
def _build_var_dict (name, cfgs, level):
|
|
if level <= 2:
|
|
if CGenCfgData.STRUCT in cfgs:
|
|
struct_info = cfgs[CGenCfgData.STRUCT]
|
|
self._var_dict['_LENGTH_%s_' % name] = struct_info['length'] // 8
|
|
self._var_dict['_OFFSET_%s_' % name] = struct_info['offset'] // 8
|
|
|
|
self._var_dict = {}
|
|
self.traverse_cfg_tree (_build_var_dict)
|
|
self._var_dict['_LENGTH_'] = self._cfg_tree[CGenCfgData.STRUCT]['length'] // 8
|
|
return 0
|
|
|
|
|
|
def add_cfg_page(self, child, parent, title=''):
|
|
def _add_cfg_page(cfg_page, child, parent):
|
|
key = next(iter(cfg_page))
|
|
if parent == key:
|
|
cfg_page[key]['child'].append({child: {'title': title,
|
|
'child': []}})
|
|
return True
|
|
else:
|
|
result = False
|
|
for each in cfg_page[key]['child']:
|
|
if _add_cfg_page(each, child, parent):
|
|
result = True
|
|
break
|
|
return result
|
|
|
|
return _add_cfg_page(self._cfg_page, child, parent)
|
|
|
|
|
|
def set_cur_page(self, page_str):
|
|
if not page_str:
|
|
return
|
|
|
|
if ',' in page_str:
|
|
page_list = page_str.split(',')
|
|
else:
|
|
page_list = [page_str]
|
|
for page_str in page_list:
|
|
parts = page_str.split(':')
|
|
if len(parts) in [1, 3]:
|
|
page = parts[0].strip()
|
|
if len(parts) == 3:
|
|
# it is a new page definition, add it into tree
|
|
parent = parts[1] if parts[1] else 'root'
|
|
parent = parent.strip()
|
|
if parts[2][0] == '"' and parts[2][-1] == '"':
|
|
parts[2] = parts[2][1:-1]
|
|
|
|
if not self.add_cfg_page(page, parent, parts[2]):
|
|
raise SystemExit("Error: Cannot find parent page '%s'!" % parent)
|
|
else:
|
|
raise SystemExit("Error: Invalid page format '%s' !" % page_str)
|
|
self._cur_page = page
|
|
|
|
|
|
def extend_variable (self, line):
|
|
# replace all variables
|
|
if line == '':
|
|
return line
|
|
loop = 2
|
|
while loop > 0:
|
|
line_after = DefTemplate(line).safe_substitute(self._def_dict)
|
|
if line == line_after:
|
|
break
|
|
loop -= 1
|
|
line = line_after
|
|
return line_after
|
|
|
|
def reformat_number_per_type (self, itype, value):
|
|
if check_quote(value) or value.startswith('{'):
|
|
return value
|
|
parts = itype.split(',')
|
|
if len(parts) > 3 and parts[0] == 'EditNum':
|
|
num_fmt = parts[1].strip()
|
|
else:
|
|
num_fmt = ''
|
|
if num_fmt == 'HEX' and not value.startswith('0x'):
|
|
value = '0x%X' % int(value, 10)
|
|
elif num_fmt == 'DEC' and value.startswith('0x'):
|
|
value = '%d' % int(value, 16)
|
|
return value
|
|
|
|
def add_cfg_item(self, name, item, offset, path):
|
|
|
|
self.set_cur_page (item.get('page', ''))
|
|
|
|
if name[0] == '$':
|
|
# skip all virtual node
|
|
return 0
|
|
|
|
|
|
if not set(item).issubset(CGenCfgData.keyword_set):
|
|
for each in list(item):
|
|
if each not in CGenCfgData.keyword_set:
|
|
raise Exception ("Invalid attribute '%s' for '%s'!" % (each, '.'.join(path)))
|
|
|
|
length = item.get('length', 0)
|
|
if type(length) is str:
|
|
match = re.match("^(\\d+)([b|B|W|D|Q])([B|W|D|Q]?)\\s*$", length)
|
|
if match:
|
|
unit_len = CGenCfgData.bits_width[match.group(2)]
|
|
length = int(match.group(1), 10) * unit_len
|
|
else:
|
|
try:
|
|
length = int(length, 0) * 8
|
|
except:
|
|
raise Exception ("Invalid length field '%s' for '%s' !" % (length, '.'.join(path)))
|
|
|
|
if offset % 8 > 0:
|
|
raise Exception ("Invalid alignment for field '%s' for '%s' !" % (name, '.'.join(path)))
|
|
else:
|
|
# define is length in bytes
|
|
length = length * 8
|
|
|
|
if not name.isidentifier():
|
|
raise Exception ("Invalid config name '%s' for '%s' !" % (name, '.'.join(path)))
|
|
|
|
|
|
itype = str(item.get('type', 'Reserved'))
|
|
value = str(item.get('value', ''))
|
|
if value:
|
|
if not (check_quote(value) or value.startswith('{')):
|
|
if ',' in value:
|
|
value = '{ %s }' % value
|
|
else:
|
|
value = self.reformat_number_per_type (itype, value)
|
|
|
|
help = str(item.get('help', ''))
|
|
if '\n' in help:
|
|
help = ' '.join ([i.strip() for i in help.splitlines()])
|
|
|
|
option = str(item.get('option', ''))
|
|
if '\n' in option:
|
|
option = ' '.join ([i.strip() for i in option.splitlines()])
|
|
|
|
# extend variables for value and condition
|
|
condition = str(item.get('condition', ''))
|
|
if condition:
|
|
condition = self.extend_variable (condition)
|
|
value = self.extend_variable (value)
|
|
|
|
order = str(item.get('order', ''))
|
|
if order:
|
|
if '.' in order:
|
|
(major, minor) = order.split('.')
|
|
order = int (major, 16)
|
|
else:
|
|
order = int (order, 16)
|
|
else:
|
|
order = offset
|
|
|
|
cfg_item = dict()
|
|
if name == 'CfgHeader':
|
|
cfg_item['tag'] = self.get_cfg_hdr_tag(item)
|
|
cfg_item['length'] = length
|
|
cfg_item['offset'] = offset
|
|
cfg_item['value'] = value
|
|
cfg_item['type'] = itype
|
|
cfg_item['cname'] = str(name)
|
|
cfg_item['name'] = str(item.get('name', ''))
|
|
cfg_item['help'] = help
|
|
cfg_item['option'] = option
|
|
cfg_item['page'] = self._cur_page
|
|
cfg_item['order'] = order
|
|
cfg_item['path'] = '.'.join(path)
|
|
cfg_item['condition'] = condition
|
|
altpage = item.get('altpage', '')
|
|
if altpage:
|
|
cfg_item['altpage'] = str(altpage)
|
|
if 'struct' in item:
|
|
cfg_item['struct'] = item['struct']
|
|
self._cfg_list.append(cfg_item)
|
|
|
|
item['indx'] = len(self._cfg_list) - 1
|
|
|
|
# remove used info for reducing pkl size
|
|
item.pop('option', None)
|
|
item.pop('condition', None)
|
|
item.pop('help', None)
|
|
item.pop('name', None)
|
|
item.pop('page', None)
|
|
|
|
return length
|
|
|
|
def get_cfg_hdr_tag(self, cfg_hdr):
|
|
cfg_hdr_yaml_vals = strip_delimiter(cfg_hdr['value'],'{}').split(',')
|
|
cfg_id_str = cfg_hdr_yaml_vals[-1]
|
|
tag_id_str = cfg_id_str.strip().split(':')[0]
|
|
tag_id = eval(tag_id_str)
|
|
return tag_id
|
|
|
|
def build_cfg_list (self, cfg_name ='', top = None, path = [], info = {'offset': 0}):
|
|
if top is None:
|
|
top = self._cfg_tree
|
|
# reset the offset for a fresh load_yaml()
|
|
info['offset'] = 0
|
|
|
|
start = info['offset']
|
|
is_leaf = True
|
|
for key in top:
|
|
path.append(key)
|
|
if type(top[key]) is OrderedDict:
|
|
is_leaf = False
|
|
self.build_cfg_list(key, top[key], path, info)
|
|
path.pop()
|
|
|
|
if is_leaf:
|
|
length = self.add_cfg_item(cfg_name, top, info['offset'], path)
|
|
info['offset'] += length
|
|
elif cfg_name == '' or (cfg_name and cfg_name[0] != '$'):
|
|
# check first element for struct
|
|
first = next(iter(top))
|
|
struct_str = CGenCfgData.STRUCT
|
|
if first != struct_str:
|
|
struct_node = OrderedDict({})
|
|
top[struct_str] = struct_node
|
|
top.move_to_end (struct_str, False)
|
|
else:
|
|
struct_node = top[struct_str]
|
|
struct_node['offset'] = start
|
|
struct_node['length'] = info['offset'] - start
|
|
if struct_node['length'] % 8 != 0:
|
|
raise SystemExit("Error: Bits length not aligned for %s !" % str(path))
|
|
# Ensure Cfg struct is 4-byte aligned
|
|
if 'CfgHeader' in top and (struct_node['length']//8)%4:
|
|
padding = 4 - (struct_node['length']//8)%4
|
|
pad_bytes = OrderedDict({})
|
|
pad_bytes['length'] = str(padding)
|
|
pad_bytes['value'] = str(0)
|
|
top[CGenCfgData.PADDINGNAME] = pad_bytes
|
|
path.append(CGenCfgData.PADDINGNAME)
|
|
self.build_cfg_list(CGenCfgData.PADDINGNAME,pad_bytes,path,info)
|
|
path.pop()
|
|
struct_node['length'] = info['offset'] - start
|
|
|
|
def get_field_value (self, top = None):
|
|
def _get_field_value (name, cfgs, level):
|
|
if 'indx' in cfgs:
|
|
act_cfg = self.get_item_by_index (cfgs['indx'])
|
|
if act_cfg['length'] == 0:
|
|
return
|
|
value = self.get_value (act_cfg['value'], act_cfg['length'], False)
|
|
set_bits_to_bytes (result, act_cfg['offset'] - struct_info['offset'], act_cfg['length'], value)
|
|
|
|
if top is None:
|
|
top = self._cfg_tree
|
|
struct_info = top[CGenCfgData.STRUCT]
|
|
result = bytearray ((struct_info['length'] + 7) // 8)
|
|
self.traverse_cfg_tree (_get_field_value, top)
|
|
return result
|
|
|
|
|
|
def set_field_value (self, top, value_bytes, force = False):
|
|
def _set_field_value (name, cfgs, level):
|
|
if 'indx' not in cfgs:
|
|
return
|
|
act_cfg = self.get_item_by_index (cfgs['indx'])
|
|
if force or act_cfg['value'] == '':
|
|
value = get_bits_from_bytes (full_bytes, act_cfg['offset'] - struct_info['offset'], act_cfg['length'])
|
|
act_val = act_cfg['value']
|
|
if act_val == '':
|
|
act_val = '%d' % value
|
|
act_val = self.reformat_number_per_type (act_cfg['type'], act_val)
|
|
act_cfg['value'] = self.format_value_to_str (value, act_cfg['length'], act_val)
|
|
|
|
if 'indx' in top:
|
|
# it is config option
|
|
value = bytes_to_value (value_bytes)
|
|
act_cfg = self.get_item_by_index (top['indx'])
|
|
act_cfg['value'] = self.format_value_to_str (value, act_cfg['length'], act_cfg['value'])
|
|
else:
|
|
# it is structure
|
|
struct_info = top[CGenCfgData.STRUCT]
|
|
length = struct_info['length'] // 8
|
|
full_bytes = bytearray(value_bytes[:length])
|
|
if len(full_bytes) < length:
|
|
full_bytes.extend(bytearray(length - len(value_bytes)))
|
|
self.traverse_cfg_tree (_set_field_value, top)
|
|
|
|
|
|
def update_def_value (self):
|
|
def _update_def_value (name, cfgs, level):
|
|
if 'indx' in cfgs:
|
|
act_cfg = self.get_item_by_index (cfgs['indx'])
|
|
if act_cfg['value'] != '' and act_cfg['length'] > 0:
|
|
try:
|
|
act_cfg['value'] = self.reformat_value_str (act_cfg['value'], act_cfg['length'])
|
|
except:
|
|
raise Exception ("Invalid value expression '%s' for '%s' !" % (act_cfg['value'], act_cfg['path']))
|
|
else:
|
|
if CGenCfgData.STRUCT in cfgs and 'value' in cfgs[CGenCfgData.STRUCT]:
|
|
curr = cfgs[CGenCfgData.STRUCT]
|
|
value_bytes = value_to_bytearray (self.eval(curr['value']), (curr['length'] + 7) // 8)
|
|
self.set_field_value (cfgs, value_bytes)
|
|
|
|
self.traverse_cfg_tree (_update_def_value, self._cfg_tree)
|
|
|
|
|
|
def evaluate_condition (self, item):
|
|
expr = item['condition']
|
|
result = self.parse_value (expr, 1, False)
|
|
return result
|
|
|
|
|
|
def load_default_from_bin (self, bin_data):
|
|
self.set_field_value(self._cfg_tree, bin_data, True)
|
|
|
|
|
|
def generate_binary_array (self):
|
|
return self.get_field_value()
|
|
|
|
def generate_binary (self, bin_file_name):
|
|
bin_file = open(bin_file_name, "wb")
|
|
bin_file.write (self.generate_binary_array ())
|
|
bin_file.close()
|
|
return 0
|
|
|
|
def write_delta_file (self, out_file, platform_id, out_lines):
|
|
dlt_fd = open (out_file, "w")
|
|
dlt_fd.write ("%s\n" % get_copyright_header('dlt', True))
|
|
dlt_fd.write ('#\n')
|
|
dlt_fd.write ('# Delta configuration values for platform ID 0x%04X\n' % platform_id)
|
|
dlt_fd.write ('#\n\n')
|
|
for line in out_lines:
|
|
dlt_fd.write ('%s\n' % line)
|
|
dlt_fd.close()
|
|
|
|
|
|
def override_default_value(self, dlt_file):
|
|
error = 0
|
|
dlt_lines = CGenCfgData.expand_include_files(dlt_file)
|
|
|
|
platform_id = None
|
|
for line, file_path, line_num in dlt_lines:
|
|
line = line.strip()
|
|
if not line or line.startswith('#'):
|
|
continue
|
|
match = re.match("\\s*([\\w\\.]+)\\s*\\|\\s*(.+)", line)
|
|
if not match:
|
|
raise Exception("Unrecognized line '%s' (File:'%s' Line:%d) !" %
|
|
(line, file_path, line_num + 1))
|
|
|
|
path = match.group(1)
|
|
value_str = match.group(2)
|
|
top = self.locate_cfg_item (path)
|
|
if not top:
|
|
raise Exception(
|
|
"Invalid configuration '%s' (File:'%s' Line:%d) !" %
|
|
(path, file_path, line_num + 1))
|
|
|
|
if 'indx' in top:
|
|
act_cfg = self.get_item_by_index (top['indx'])
|
|
bit_len = act_cfg['length']
|
|
else:
|
|
struct_info = top[CGenCfgData.STRUCT]
|
|
bit_len = struct_info['length']
|
|
|
|
value_bytes = self.parse_value (value_str, bit_len)
|
|
self.set_field_value (top, value_bytes, True)
|
|
|
|
if path == 'PLATFORMID_CFG_DATA.PlatformId':
|
|
platform_id = value_str
|
|
|
|
if platform_id is None:
|
|
raise Exception(
|
|
"PLATFORMID_CFG_DATA.PlatformId is missing in file '%s' !" %
|
|
(dlt_file))
|
|
|
|
return error
|
|
|
|
|
|
def generate_delta_file_from_bin (self, delta_file, old_data, new_data, full=False):
|
|
self.load_default_from_bin (new_data)
|
|
lines = []
|
|
tag_name = ''
|
|
level = 0
|
|
platform_id = None
|
|
def_platform_id = 0
|
|
|
|
for item in self._cfg_list:
|
|
old_val = get_bits_from_bytes (old_data, item['offset'], item['length'])
|
|
new_val = get_bits_from_bytes (new_data, item['offset'], item['length'])
|
|
|
|
full_name = item['path']
|
|
if 'PLATFORMID_CFG_DATA.PlatformId' == full_name:
|
|
def_platform_id = old_val
|
|
platform_id = new_val
|
|
elif item['type'] != 'Reserved' and ((new_val != old_val) or full):
|
|
val_str = self.reformat_value_str (item['value'], item['length'])
|
|
text = '%-40s | %s' % (full_name, val_str)
|
|
lines.append(text)
|
|
|
|
if platform_id is None or def_platform_id == platform_id:
|
|
platform_id = def_platform_id
|
|
|
|
lines.insert(0, '%-40s | %s\n\n' %
|
|
('PLATFORMID_CFG_DATA.PlatformId', '0x%04X' % platform_id))
|
|
|
|
self.write_delta_file (delta_file, platform_id, lines)
|
|
return 0
|
|
|
|
|
|
def generate_delta_file(self, delta_file, bin_file, bin_file2, full=False):
|
|
fd = open (bin_file, 'rb')
|
|
new_data = bytearray(fd.read())
|
|
fd.close()
|
|
|
|
if bin_file2 == '':
|
|
old_data = self.generate_binary_array()
|
|
else:
|
|
old_data = new_data
|
|
fd = open (bin_file2, 'rb')
|
|
new_data = bytearray(fd.read())
|
|
fd.close()
|
|
|
|
return self.generate_delta_file_from_bin (delta_file, old_data, new_data, full)
|
|
|
|
|
|
def prepare_marshal (self, is_save):
|
|
if is_save:
|
|
# Ordered dict is not marshallable, convert to list
|
|
self._cfg_tree = CGenCfgData.deep_convert_dict (self._cfg_tree)
|
|
else:
|
|
# Revert it back
|
|
self._cfg_tree = CGenCfgData.deep_convert_list (self._cfg_tree)
|
|
|
|
def generate_yml_file (self, in_file, out_file):
|
|
cfg_yaml = CFG_YAML()
|
|
text = cfg_yaml.expand_yaml (in_file)
|
|
yml_fd = open(out_file, "w")
|
|
yml_fd.write (text)
|
|
yml_fd.close ()
|
|
return 0
|
|
|
|
|
|
def write_cfg_header_file (self, hdr_file_name, tag_mode, tag_dict, struct_list):
|
|
lines = []
|
|
lines.append ('\n\n')
|
|
tag_list = sorted(list(tag_dict.items()), key=lambda x: x[1])
|
|
for tagname, tagval in tag_list:
|
|
if (tag_mode == 0 and tagval >= 0x100) or (tag_mode == 1 and tagval < 0x100):
|
|
continue
|
|
lines.append ('#define %-30s 0x%03X\n' % ('CDATA_%s_TAG' % tagname[:-9], tagval))
|
|
lines.append ('\n\n')
|
|
|
|
name_dict = {}
|
|
new_dict = {}
|
|
for each in struct_list:
|
|
if (tag_mode == 0 and each['tag'] >= 0x100) or (tag_mode == 1 and each['tag'] < 0x100):
|
|
continue
|
|
new_dict[each['name']] = (each['alias'], each['count'])
|
|
if each['alias'] not in name_dict:
|
|
name_dict[each['alias']] = 1
|
|
lines.extend(self.create_struct (each['alias'], each['node'], new_dict))
|
|
|
|
|
|
self.write_header_file (lines, hdr_file_name)
|
|
|
|
|
|
def write_header_file (self, txt_body, file_name, type = 'h'):
|
|
file_name_def = os.path.basename(file_name).replace ('.', '_')
|
|
file_name_def = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', file_name_def)
|
|
file_name_def = re.sub('([a-z0-9])([A-Z])', r'\1_\2', file_name_def).upper()
|
|
|
|
lines = []
|
|
lines.append ("%s\n" % get_copyright_header(type))
|
|
lines.append ("#ifndef __%s__\n" % file_name_def)
|
|
lines.append ("#define __%s__\n\n" % file_name_def)
|
|
if type == 'h':
|
|
lines.append ("#pragma pack(1)\n\n")
|
|
lines.extend (txt_body)
|
|
if type == 'h':
|
|
lines.append ("#pragma pack()\n\n")
|
|
lines.append ("#endif\n")
|
|
|
|
# Don't rewrite if the contents are the same
|
|
create = True
|
|
if os.path.exists(file_name):
|
|
hdr_file = open(file_name, "r")
|
|
org_txt = hdr_file.read()
|
|
hdr_file.close()
|
|
|
|
new_txt = ''.join(lines)
|
|
if org_txt == new_txt:
|
|
create = False
|
|
|
|
if create:
|
|
hdr_file = open(file_name, "w")
|
|
hdr_file.write (''.join(lines))
|
|
hdr_file.close()
|
|
|
|
|
|
def generate_data_inc_file (self, dat_inc_file_name, bin_file = None):
|
|
# Put a prefix GUID before CFGDATA so that it can be located later on
|
|
prefix = b'\xa7\xbd\x7f\x73\x20\x1e\x46\xd6\xbe\x8f\x64\x12\x05\x8d\x0a\xa8'
|
|
if bin_file:
|
|
fin = open (bin_file, 'rb')
|
|
bin_dat = prefix + bytearray(fin.read())
|
|
fin.close()
|
|
else:
|
|
bin_dat = prefix + self.generate_binary_array ()
|
|
|
|
file_name = os.path.basename(dat_inc_file_name).upper()
|
|
file_name = file_name.replace('.', '_')
|
|
|
|
txt_lines = []
|
|
|
|
txt_lines.append ("UINT8 mConfigDataBlob[%d] = {\n" % len(bin_dat))
|
|
count = 0
|
|
line = [' ']
|
|
for each in bin_dat:
|
|
line.append('0x%02X, ' % each)
|
|
count = count + 1
|
|
if (count & 0x0F) == 0:
|
|
line.append('\n')
|
|
txt_lines.append (''.join(line))
|
|
line = [' ']
|
|
if len(line) > 1:
|
|
txt_lines.append (''.join(line) + '\n')
|
|
|
|
txt_lines.append ("};\n\n")
|
|
|
|
self.write_header_file (txt_lines, dat_inc_file_name, 'inc')
|
|
|
|
return 0
|
|
|
|
|
|
def get_struct_array_info (self, input):
|
|
parts = input.split(':')
|
|
if len(parts) > 1:
|
|
var = parts[1]
|
|
input = parts[0]
|
|
else:
|
|
var = ''
|
|
array_str = input.split('[')
|
|
name = array_str[0]
|
|
if len(array_str) > 1:
|
|
num_str = ''.join(c for c in array_str[-1] if c.isdigit())
|
|
num_str = '1000' if len(num_str) == 0 else num_str
|
|
array_num = int(num_str)
|
|
else:
|
|
array_num = 0
|
|
return name, array_num, var
|
|
|
|
|
|
def process_multilines (self, string, max_char_length):
|
|
multilines = ''
|
|
string_length = len(string)
|
|
current_string_start = 0
|
|
string_offset = 0
|
|
break_line_dict = []
|
|
if len(string) <= max_char_length:
|
|
while (string_offset < string_length):
|
|
if string_offset >= 1:
|
|
if string[string_offset - 1] == '\\' and string[string_offset] == 'n':
|
|
break_line_dict.append (string_offset + 1)
|
|
string_offset += 1
|
|
if break_line_dict != []:
|
|
for each in break_line_dict:
|
|
multilines += " %s\n" % string[current_string_start:each].lstrip()
|
|
current_string_start = each
|
|
if string_length - current_string_start > 0:
|
|
multilines += " %s\n" % string[current_string_start:].lstrip()
|
|
else:
|
|
multilines = " %s\n" % string
|
|
else:
|
|
new_line_start = 0
|
|
new_line_count = 0
|
|
found_space_char = False
|
|
while (string_offset < string_length):
|
|
if string_offset >= 1:
|
|
if new_line_count >= max_char_length - 1:
|
|
if string[string_offset] == ' ' and string_length - string_offset > 10:
|
|
break_line_dict.append (new_line_start + new_line_count)
|
|
new_line_start = new_line_start + new_line_count
|
|
new_line_count = 0
|
|
found_space_char = True
|
|
elif string_offset == string_length - 1 and found_space_char == False:
|
|
break_line_dict.append (0)
|
|
if string[string_offset - 1] == '\\' and string[string_offset] == 'n':
|
|
break_line_dict.append (string_offset + 1)
|
|
new_line_start = string_offset + 1
|
|
new_line_count = 0
|
|
string_offset += 1
|
|
new_line_count += 1
|
|
if break_line_dict != []:
|
|
break_line_dict.sort ()
|
|
for each in break_line_dict:
|
|
if each > 0:
|
|
multilines += " %s\n" % string[current_string_start:each].lstrip()
|
|
current_string_start = each
|
|
if string_length - current_string_start > 0:
|
|
multilines += " %s\n" % string[current_string_start:].lstrip()
|
|
return multilines
|
|
|
|
|
|
def create_field (self, item, name, length, offset, struct, bsf_name, help, option, bits_length = None):
|
|
pos_name = 28
|
|
pos_comment = 30
|
|
name_line=''
|
|
help_line=''
|
|
option_line=''
|
|
|
|
if length == 0 and name == 'dummy':
|
|
return '\n'
|
|
|
|
if bits_length == 0:
|
|
return '\n'
|
|
|
|
is_array = False
|
|
if length in [1,2,4,8]:
|
|
type = "UINT%d" % (length * 8)
|
|
else:
|
|
is_array = True
|
|
type = "UINT8"
|
|
|
|
if item and item['value'].startswith('{'):
|
|
type = "UINT8"
|
|
is_array = True
|
|
|
|
if struct != '':
|
|
struct_base = struct.rstrip('*')
|
|
name = '*' * (len(struct) - len(struct_base)) + name
|
|
struct = struct_base
|
|
type = struct
|
|
if struct in ['UINT8','UINT16','UINT32','UINT64']:
|
|
is_array = True
|
|
unit = int(type[4:]) // 8
|
|
length = length / unit
|
|
else:
|
|
is_array = False
|
|
|
|
if is_array:
|
|
name = name + '[%d]' % length
|
|
|
|
if len(type) < pos_name:
|
|
space1 = pos_name - len(type)
|
|
else:
|
|
space1 = 1
|
|
|
|
if bsf_name != '':
|
|
name_line=" %s\n" % bsf_name
|
|
else:
|
|
name_line="N/A\n"
|
|
|
|
if help != '':
|
|
help_line = self.process_multilines (help, 80)
|
|
|
|
if option != '':
|
|
option_line = self.process_multilines (option, 80)
|
|
|
|
if offset is None:
|
|
offset_str = '????'
|
|
else:
|
|
offset_str = '0x%04X' % offset
|
|
|
|
if bits_length is None:
|
|
bits_length = ''
|
|
else:
|
|
bits_length = ' : %d' % bits_length
|
|
|
|
#return "\n/** %s%s%s**/\n %s%s%s%s;\n" % (name_line, help_line, option_line, type, ' ' * space1, name, bits_length)
|
|
return "\n /* %s */\n %s%s%s%s;\n" % (name_line.strip(), type, ' ' * space1, name, bits_length)
|
|
|
|
|
|
def create_struct (self, cname, top, struct_dict):
|
|
index = 0
|
|
last = ''
|
|
lines = []
|
|
lines.append ('\ntypedef struct {\n')
|
|
for field in top:
|
|
if field[0] == '$':
|
|
continue
|
|
|
|
index += 1
|
|
|
|
t_item = top[field]
|
|
if 'indx' not in t_item:
|
|
if CGenCfgData.STRUCT not in top[field]:
|
|
continue
|
|
|
|
if struct_dict[field][1] == 0:
|
|
continue
|
|
|
|
append = True
|
|
struct_info = top[field][CGenCfgData.STRUCT]
|
|
|
|
if 'struct' in struct_info:
|
|
struct, array_num, var = self.get_struct_array_info (struct_info['struct'])
|
|
if array_num > 0:
|
|
if last == struct:
|
|
append = False
|
|
last = struct
|
|
if var == '':
|
|
var = field
|
|
|
|
field = CGenCfgData.format_struct_field_name (var, struct_dict[field][1])
|
|
else:
|
|
struct = struct_dict[field][0]
|
|
field = CGenCfgData.format_struct_field_name (field, struct_dict[field][1])
|
|
|
|
if append:
|
|
line = self.create_field (None, field, 0, 0, struct, '', '', '')
|
|
lines.append (' %s' % line)
|
|
last = struct
|
|
continue
|
|
|
|
item = self.get_item_by_index (t_item['indx'])
|
|
if item['cname'] == 'CfgHeader' and index == 1 or (item['cname'] == 'CondValue' and index == 2):
|
|
continue
|
|
|
|
bit_length = None
|
|
length = (item['length'] + 7) // 8
|
|
match = re.match("^(\\d+)([b|B|W|D|Q])([B|W|D|Q]?)", t_item['length'])
|
|
if match and match.group(2) == 'b':
|
|
bit_length = int(match.group(1))
|
|
if match.group(3) != '':
|
|
length = CGenCfgData.bits_width[match.group(3)] // 8
|
|
else:
|
|
length = 4
|
|
offset = item['offset'] // 8
|
|
struct = item.get('struct', '')
|
|
name = field
|
|
prompt = item['name']
|
|
help = item['help']
|
|
option = item['option']
|
|
line = self.create_field (item, name, length, offset, struct, prompt, help, option, bit_length)
|
|
lines.append (' %s' % line)
|
|
last = struct
|
|
|
|
lines.append ('\n} %s;\n\n' % cname)
|
|
|
|
return lines
|
|
|
|
|
|
def create_header_file (self, hdr_file_name, com_hdr_file_name = ''):
|
|
def _build_header_struct (name, cfgs, level):
|
|
if CGenCfgData.STRUCT in cfgs:
|
|
if 'CfgHeader' in cfgs:
|
|
# collect CFGDATA TAG IDs
|
|
cfghdr = self.get_item_by_index (cfgs['CfgHeader']['indx'])
|
|
tag_val = array_str_to_value(cfghdr['value']) >> 20
|
|
tag_dict[name] = tag_val
|
|
if level == 1:
|
|
tag_curr[0] = tag_val
|
|
struct_dict[name] = (level, tag_curr[0], cfgs)
|
|
|
|
tag_curr = [0]
|
|
tag_dict = {}
|
|
struct_dict = {}
|
|
self.traverse_cfg_tree (_build_header_struct)
|
|
|
|
if tag_curr[0] == 0:
|
|
hdr_mode = 2
|
|
else:
|
|
hdr_mode = 1
|
|
|
|
# filter out the items to be built for tags and structures
|
|
struct_list = []
|
|
for each in struct_dict:
|
|
match = False
|
|
for check in CGenCfgData.exclude_struct:
|
|
if re.match (check, each):
|
|
match = True
|
|
if each in tag_dict:
|
|
if each not in CGenCfgData.include_tag:
|
|
del tag_dict[each]
|
|
break
|
|
if not match:
|
|
struct_list.append ({'name':each, 'alias':'', 'count' : 0, 'level':struct_dict[each][0],
|
|
'tag':struct_dict[each][1], 'node':struct_dict[each][2]})
|
|
|
|
# sort by level so that the bottom level struct will be build first to satisfy dependencies
|
|
struct_list = sorted(struct_list, key=lambda x: x['level'], reverse=True)
|
|
|
|
# Convert XXX_[0-9]+ to XXX as an array hint
|
|
for each in struct_list:
|
|
cfgs = each['node']
|
|
if 'struct' in cfgs['$STRUCT']:
|
|
each['alias'], array_num, var = self.get_struct_array_info (cfgs['$STRUCT']['struct'])
|
|
else:
|
|
match = re.match('(\\w+)(_\\d+)', each['name'])
|
|
if match:
|
|
each['alias'] = match.group(1)
|
|
else:
|
|
each['alias'] = each['name']
|
|
|
|
# count items for array build
|
|
for idx, each in enumerate(struct_list):
|
|
if idx > 0:
|
|
last_struct = struct_list[idx-1]['node']['$STRUCT']
|
|
curr_struct = each['node']['$STRUCT']
|
|
if struct_list[idx-1]['alias'] == each['alias'] and \
|
|
curr_struct['length'] == last_struct['length'] and \
|
|
curr_struct['offset'] == last_struct['offset'] + last_struct['length']:
|
|
for idx2 in range (idx-1, -1, -1):
|
|
if struct_list[idx2]['count'] > 0:
|
|
struct_list[idx2]['count'] += 1
|
|
break
|
|
continue
|
|
each['count'] = 1
|
|
|
|
# generate common header
|
|
if com_hdr_file_name:
|
|
self.write_cfg_header_file (com_hdr_file_name, 0, tag_dict, struct_list)
|
|
|
|
# generate platform header
|
|
self.write_cfg_header_file (hdr_file_name, hdr_mode, tag_dict, struct_list)
|
|
|
|
return 0
|
|
|
|
|
|
def load_yaml (self, cfg_file):
|
|
cfg_yaml = CFG_YAML()
|
|
self.initialize ()
|
|
self._cfg_tree = cfg_yaml.load_yaml (cfg_file)
|
|
self._def_dict = cfg_yaml.def_dict
|
|
self._yaml_path = os.path.dirname(cfg_file)
|
|
self.build_cfg_list()
|
|
self.build_var_dict()
|
|
self.update_def_value()
|
|
return 0
|
|
|
|
|
|
def usage():
|
|
print ('\n'.join([
|
|
"GenCfgData Version 0.50",
|
|
"Usage:",
|
|
" GenCfgData GENINC BinFile IncOutFile",
|
|
" GenCfgData GENPKL YamlFile PklOutFile",
|
|
" GenCfgData GENBIN YamlFile[;DltFile] BinOutFile",
|
|
" GenCfgData GENDLT YamlFile[;BinFile] DltOutFile",
|
|
" GenCfgData GENYML YamlFile YamlOutFile",
|
|
" GenCfgData GENHDR YamlFile HdrOutFile"
|
|
]))
|
|
|
|
|
|
def main():
|
|
# Parse the options and args
|
|
argc = len(sys.argv)
|
|
if argc < 4 or argc > 5:
|
|
usage()
|
|
return 1
|
|
|
|
gen_cfg_data = CGenCfgData()
|
|
command = sys.argv[1].upper()
|
|
out_file = sys.argv[3]
|
|
|
|
file_list = sys.argv[2].split(';')
|
|
if len(file_list) >= 2:
|
|
yml_file = file_list[0]
|
|
dlt_file = file_list[1]
|
|
elif len(file_list) == 1:
|
|
yml_file = file_list[0]
|
|
dlt_file = ''
|
|
else:
|
|
raise Exception ("ERROR: Invalid parameter '%s' !" % sys.argv[2])
|
|
|
|
if command == "GENDLT" and yml_file.endswith('.dlt'):
|
|
# It needs to expand an existing DLT file
|
|
dlt_file = yml_file
|
|
lines = gen_cfg_data.expand_include_files (dlt_file)
|
|
write_lines (lines, out_file)
|
|
return 0
|
|
|
|
if command == "GENYML":
|
|
if not yml_file.lower().endswith('.yaml'):
|
|
raise Exception ('Only YAML file is supported !')
|
|
gen_cfg_data.generate_yml_file(yml_file, out_file)
|
|
return 0
|
|
|
|
bin_file = ''
|
|
if (yml_file.lower().endswith('.bin')) and (command == "GENINC"):
|
|
# It is binary file
|
|
bin_file = yml_file
|
|
yml_file = ''
|
|
|
|
if bin_file:
|
|
gen_cfg_data.generate_data_inc_file(out_file, bin_file)
|
|
return 0
|
|
|
|
cfg_bin_file = ''
|
|
cfg_bin_file2 = ''
|
|
if dlt_file:
|
|
if command == "GENDLT":
|
|
cfg_bin_file = dlt_file
|
|
dlt_file = ''
|
|
if len(file_list) >= 3:
|
|
cfg_bin_file2 = file_list[2]
|
|
|
|
if yml_file.lower().endswith('.pkl'):
|
|
with open(yml_file, "rb") as pkl_file:
|
|
gen_cfg_data.__dict__ = marshal.load(pkl_file)
|
|
gen_cfg_data.prepare_marshal (False)
|
|
else:
|
|
gen_cfg_data.load_yaml (yml_file)
|
|
if command == 'GENPKL':
|
|
gen_cfg_data.prepare_marshal (True)
|
|
with open(out_file, "wb") as pkl_file:
|
|
marshal.dump(gen_cfg_data.__dict__, pkl_file)
|
|
json_file = os.path.splitext(out_file)[0] + '.json'
|
|
fo = open (json_file, 'w')
|
|
path_list = []
|
|
cfgs = {'_cfg_page' : gen_cfg_data._cfg_page, '_cfg_list':gen_cfg_data._cfg_list, '_path_list' : path_list}
|
|
# optimize to reduce size
|
|
path = None
|
|
for each in cfgs['_cfg_list']:
|
|
new_path = each['path'][:-len(each['cname'])-1]
|
|
if path != new_path:
|
|
path = new_path
|
|
each['path'] = path
|
|
path_list.append(path)
|
|
else:
|
|
del each['path']
|
|
if each['order'] == each['offset']:
|
|
del each['order']
|
|
del each['offset']
|
|
|
|
# value is just used to indicate display type
|
|
value = each['value']
|
|
if value.startswith ('0x'):
|
|
hex_len = ((each['length'] + 7) // 8) * 2
|
|
if len(value) == hex_len:
|
|
value = 'x%d' % hex_len
|
|
else:
|
|
value = 'x'
|
|
each['value'] = value
|
|
elif value and value[0] in ['"', "'", '{']:
|
|
each['value'] = value[0]
|
|
else:
|
|
del each['value']
|
|
|
|
fo.write(repr(cfgs))
|
|
fo.close ()
|
|
return 0
|
|
|
|
if dlt_file:
|
|
gen_cfg_data.override_default_value(dlt_file)
|
|
|
|
if command == "GENBIN":
|
|
if len(file_list) == 3:
|
|
old_data = gen_cfg_data.generate_binary_array()
|
|
fi = open (file_list[2], 'rb')
|
|
new_data = bytearray (fi.read ())
|
|
fi.close ()
|
|
if len(new_data) != len(old_data):
|
|
raise Exception ("Binary file '%s' length does not match, ignored !" % file_list[2])
|
|
else:
|
|
gen_cfg_data.load_default_from_bin (new_data)
|
|
gen_cfg_data.override_default_value(dlt_file)
|
|
|
|
gen_cfg_data.generate_binary(out_file)
|
|
|
|
elif command == "GENDLT":
|
|
gen_cfg_data.generate_delta_file (out_file, cfg_bin_file, cfg_bin_file2)
|
|
|
|
elif command == "GENHDR":
|
|
out_files = out_file.split(';')
|
|
brd_out_file = out_files[0].strip()
|
|
if len(out_files) > 1:
|
|
com_out_file = out_files[1].strip()
|
|
else:
|
|
com_out_file = ''
|
|
gen_cfg_data.create_header_file(brd_out_file, com_out_file)
|
|
|
|
elif command == "GENINC":
|
|
gen_cfg_data.generate_data_inc_file(out_file)
|
|
|
|
elif command == "DEBUG":
|
|
gen_cfg_data.print_cfgs()
|
|
|
|
else:
|
|
raise Exception ("Unsuported command '%s' !" % command)
|
|
|
|
return 0
|
|
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(main())
|
|
|