pico430prog/test/bin2h.py

116 lines
3.5 KiB
Python
Raw Normal View History

2021-10-03 15:39:32 +00:00
#!/usr/bin/env python3
import argparse
import os, re, sys, struct
import textwrap
import traceback
def sanitize_name(name):
# replace special characters with underscores
name = re.sub('[^a-zA-Z0-9_]', '_', name)
# clean up
name = name.strip('_')
# not needed: 'DATA_' prefix
#if name[0] in "0123456789": name = '_' + name
return name
def main():
parser = argparse.ArgumentParser(
description="Convert data files into byte arrays in a C header")
2021-12-07 03:16:01 +00:00
parser.add_argument('--width', type=int, default=8, help="data width")
2021-10-03 15:39:32 +00:00
parser.add_argument('input', nargs='*', action='append',
help="Input data file to convert to a header file. If "
+"none are specified, data is read from standard input.")
parser.add_argument('--output', type=str, default=None,
help="Output header file path, standard output if none specified")
args = parser.parse_args()
#print(repr(args), file=sys.stderr)
inputfiles = args.input[0]
datafiles = {}
if len(inputfiles) == 0:
# need to read from stdio
datafiles['data'] = sys.stdin.buffer.read()
else:
for path in inputfiles:
# cannot use os.access, POSIX-only
if not os.path.exists(path) or os.path.isdir(path):
print("ERROR: input path '%s' does not exist, or is not a file" % path)
sys.exit(1)
# get base name of the path (no folder names, no extension)
name = os.path.splitext(os.path.split(path)[1])[0]
# make it usable for C code names
name = sanitize_name(name)
# now read the data
data = None
try:
with open(path, 'rb') as f:
data = f.read()
except IOError:
print("ERROR: input file '%s' not readable" % path)
traceback.print_exc()
sys.exit(1)
wlut = {8:'B',16:'H',32:'I',64:'Q'}
denom= args.width//8
data = struct.unpack('<'+((wlut[args.width])*(len(data)//denom)), data)
2021-10-03 15:39:32 +00:00
# add it to the list
datafiles[name] = data
#print(repr(datafiles), file=sys.stderr)
outname = "hardcoded_data"
if args.output is not None:
outname = os.path.splitext(os.path.split(args.output)[1])[0]
outname = sanitize_name(outname)
# generate the C source code: one uint8_t array for each data file
# variable name is "DATA_<datafile>"
# (width=84 is the equivalent of 16 bytes/line)
headersrc = '\n\n'.join(
"static uint%d_t DATA_%s[%d] = {\n%s\n};" % (args.width, name, len(data), \
textwrap.fill(', '.join(("0x%0"+str(args.width//4)+"x") % b for b in data), width=81,
2021-10-03 15:39:32 +00:00
initial_indent=" ", subsequent_indent=" ")
) for name, data in datafiles.items()
)
# a C header needs include guards
headersrc = """
#ifndef AUTOGEN_{0}_H_
#define AUTOGEN_{0}_H_
{1}
#endif
""".format(outname.upper(), headersrc)
#print(headersrc, file=sys.stderr)
if args.output is None:
# no output specified -> output to stdout
sys.stdout.write(headersrc)
else:
try:
with open(args.output, 'w') as f:
f.write(headersrc)
except IOError:
print("ERROR: output file '%s' not writable" % args.output)
traceback.print_exc()
sys.exit(1)
if __name__ == '__main__':
main()