1#!/usr/bin/env python3 2# SPDX-License-Identifier: GPL-2.0+ 3 4""" 5Expo utility - used for testing of expo features 6 7Copyright 2023 Google LLC 8Written by Simon Glass <sjg@chromium.org> 9""" 10 11import argparse 12import collections 13import io 14import re 15import subprocess 16import sys 17 18#from u_boot_pylib import cros_subprocess 19from u_boot_pylib import tools 20 21# Parse: 22# SCENE1 = 7, 23# or SCENE2, 24RE_ENUM = re.compile(r'(\S*)(\s*= (\d))?,') 25 26# Parse #define <name> "string" 27RE_DEF = re.compile(r'#define (\S*)\s*"(.*)"') 28 29def calc_ids(fname): 30 """Figure out the value of the enums in a C file 31 32 Args: 33 fname (str): Filename to parse 34 35 Returns: 36 OrderedDict(): 37 key (str): enum name 38 value (int or str): 39 Value of enum, if int 40 Value of #define, if string 41 """ 42 vals = collections.OrderedDict() 43 with open(fname, 'r', encoding='utf-8') as inf: 44 in_enum = False 45 cur_id = 0 46 for line in inf.readlines(): 47 line = line.strip() 48 if line == 'enum {': 49 in_enum = True 50 continue 51 if in_enum and line == '};': 52 in_enum = False 53 54 if in_enum: 55 if not line or line.startswith('/*'): 56 continue 57 m_enum = RE_ENUM.match(line) 58 if m_enum.group(3): 59 cur_id = int(m_enum.group(3)) 60 vals[m_enum.group(1)] = cur_id 61 cur_id += 1 62 else: 63 m_def = RE_DEF.match(line) 64 if m_def: 65 vals[m_def.group(1)] = tools.to_bytes(m_def.group(2)) 66 67 return vals 68 69 70def run_expo(args): 71 """Run the expo program""" 72 fname = args.enum_fname or args.layout 73 ids = calc_ids(fname) 74 if not ids: 75 print(f"Warning: No enum ID values found in file '{fname}'") 76 77 indata = tools.read_file(args.layout) 78 79 outf = io.BytesIO() 80 81 for name, val in ids.items(): 82 if isinstance(val, int): 83 outval = b'%d' % val 84 else: 85 outval = b'"%s"' % val 86 find_str = r'\b%s\b' % name 87 indata = re.sub(tools.to_bytes(find_str), outval, indata) 88 89 outf.write(indata) 90 data = outf.getvalue() 91 92 with open('/tmp/asc', 'wb') as outf: 93 outf.write(data) 94 proc = subprocess.run('dtc', input=data, capture_output=True) 95 edtb = proc.stdout 96 if proc.stderr: 97 print(f"Devicetree compiler error:\n{proc.stderr.decode('utf-8')}") 98 return 1 99 tools.write_file(args.outfile, edtb) 100 return 0 101 102 103def parse_args(argv): 104 """Parse the command-line arguments 105 106 Args: 107 argv (list of str): List of string arguments 108 109 Returns: 110 tuple: (options, args) with the command-line options and arugments. 111 options provides access to the options (e.g. option.debug) 112 args is a list of string arguments 113 """ 114 parser = argparse.ArgumentParser() 115 parser.add_argument('-D', '--debug', action='store_true', 116 help='Enable full debug traceback') 117 parser.add_argument('-e', '--enum-fname', type=str, 118 help='.dts or C file containing enum declaration for expo items') 119 parser.add_argument('-l', '--layout', type=str, required=True, 120 help='Devicetree file source .dts for expo layout (and perhaps enums)') 121 parser.add_argument('-o', '--outfile', type=str, required=True, 122 help='Filename to write expo layout dtb') 123 124 return parser.parse_args(argv) 125 126def start_expo(): 127 """Start the expo program""" 128 args = parse_args(sys.argv[1:]) 129 130 if not args.debug: 131 sys.tracebacklimit = 0 132 133 ret_code = run_expo(args) 134 sys.exit(ret_code) 135 136 137if __name__ == "__main__": 138 start_expo() 139