added - basic flatUSB_config.h concept added - example JSONs added - CDC request replies fixed
236 lines
7.4 KiB
Python
236 lines
7.4 KiB
Python
# base class for printing contents
|
|
class ContentPrinter:
|
|
def __init__(self):
|
|
pass
|
|
|
|
def print_content(self, content):
|
|
return content
|
|
|
|
|
|
# print integer-like values
|
|
class IntPrinter(ContentPrinter):
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
def print_content(self, content):
|
|
return hex(content)
|
|
|
|
|
|
# print character
|
|
class CharPrinter(ContentPrinter):
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
def print_content(self, content):
|
|
return "'{:s}'".format(content)
|
|
|
|
|
|
# print the struct
|
|
class StructPrinter(ContentPrinter):
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
def print_content(self, content):
|
|
str = "{\n"
|
|
for rec in content:
|
|
str += rec.print_content() + "\n"
|
|
str += "}"
|
|
|
|
|
|
class DummyRecord:
|
|
def __init__(self, name, ctype, content, printer, comment=None):
|
|
self.name = name
|
|
self.ctype = ctype
|
|
self.content = content
|
|
self.printer = printer
|
|
|
|
if comment is not None:
|
|
self.comment = " /* {:s} */".format(comment)
|
|
else:
|
|
self.comment = ""
|
|
|
|
def print_declaration(self, close_statment=True):
|
|
decl = "{:s} {:s}".format(self.ctype, self.name)
|
|
if close_statment:
|
|
decl += ";"
|
|
return decl
|
|
|
|
def print_content(self):
|
|
return "{:s}".format(self.printer.print_content(self.content))
|
|
|
|
|
|
# base class for a record
|
|
class Record(DummyRecord):
|
|
def __init__(self, name, ctype, content, printer, comment=None):
|
|
super().__init__(name, ctype, content, printer, comment)
|
|
|
|
self.array_like = isinstance(content, (list, set, tuple, str,))
|
|
self.type_encapsulates_arrayness = False
|
|
self.typedef = None
|
|
self.attribute = None
|
|
|
|
def print_content(self):
|
|
if not self.array_like:
|
|
return self.printer.print_content(self.content) + self.comment
|
|
else:
|
|
str = "{ "
|
|
first_line = True
|
|
for element in self.content:
|
|
if isinstance(element, DummyRecord): # printing non-primitive array-like types (e.g. struct); elements know how they get printed
|
|
if first_line:
|
|
str += self.comment
|
|
str += "\n"
|
|
str += "{:s}, //{:s}\n".format(element.print_content(), element.name)
|
|
else: # printing primitives; elements need's parent printer
|
|
str += "{:s}, ".format(self.printer.print_content(element)) + self.comment
|
|
first_line = False
|
|
str += "}"
|
|
return str
|
|
|
|
# get typename: if no typedef exists then return with ctype, if exists, return with typedef
|
|
def get_typename(self):
|
|
if self.typedef is None:
|
|
return self.ctype
|
|
else:
|
|
return self.typedef
|
|
|
|
# print variable declaration
|
|
def print_declaration(self, close_statment=True, print_comment=True):
|
|
decl = "{:s} {:s}".format(self.get_typename(), self.name)
|
|
if self.array_like and not self.type_encapsulates_arrayness:
|
|
decl += "[{:d}]".format(len(self.content))
|
|
if close_statment:
|
|
decl += ";"
|
|
if print_comment:
|
|
decl += self.comment
|
|
return decl
|
|
|
|
# print variable assigment
|
|
def print_assigment(self, close_statement=True):
|
|
declaration = self.print_declaration(close_statment=False, print_comment=False)
|
|
definition = self.print_content()
|
|
statement = "{:s} = {:s}".format(declaration, definition)
|
|
if close_statement:
|
|
statement += ";"
|
|
return statement
|
|
|
|
# print a type definition based on the contents
|
|
def print_typedef(self, tname=None):
|
|
if tname is None:
|
|
tname = self.typedef
|
|
|
|
attribute_compound = ""
|
|
if not self.attribute is None:
|
|
attribute_compound = "__attribute__(({:s}))".format(self.attribute)
|
|
|
|
tdef_clause = "typedef "
|
|
if not self.array_like:
|
|
tdef_clause += "{:s} {:s};".format(self.ctype, tname)
|
|
else:
|
|
array_of_primitives = not isinstance(self.content[0], Record)
|
|
|
|
if array_of_primitives:
|
|
tdef_clause += "{:s} {:s}[{:d}];".format(self.ctype, tname, len(self.content))
|
|
else: # array of structs (non-primitives)
|
|
tdef_clause += self.ctype + " {"
|
|
for rec in self.content:
|
|
# tdef_clause += "{:s} {:s};\n".format(rec.ctype, rec.name)
|
|
tdef_clause += rec.print_declaration(True)
|
|
tdef_clause += "} " + "{:s} {:s};\n".format(attribute_compound, tname)
|
|
|
|
return tdef_clause
|
|
|
|
|
|
# structure record
|
|
class StructRecord(Record):
|
|
def __init__(self, name, ctype, content, comment=None):
|
|
super().__init__(name, ctype, content, StructPrinter(), comment)
|
|
self.type_encapsulates_arrayness = True
|
|
|
|
# add new record to the structure
|
|
def add_record(self, rec):
|
|
self.content.append(rec)
|
|
|
|
|
|
class RecordFactory:
|
|
INT_LIKE_TYPES = ["u8", "u16", "u32", "u64", "i8", "i16", "i32", "i64"]
|
|
BOOl_TYPES = ["bool", "b8"]
|
|
STR_TYPE = "str"
|
|
PLAIN_PRINTER = ContentPrinter()
|
|
NUMERIC_PRINTER = IntPrinter()
|
|
CHARACTER_PRINTER = CharPrinter()
|
|
|
|
# Create record based on content and abbreviated type name
|
|
# (also convert non-numeric types to numeric ones being having the same size)
|
|
@staticmethod
|
|
def create(name_arg0, ctype="", content="", no_autoconvert=False):
|
|
# unpack params
|
|
if isinstance(name_arg0, (list, set, tuple,)):
|
|
name = name_arg0[0]
|
|
ctype = name_arg0[1]
|
|
content = name_arg0[2]
|
|
if len(name_arg0) > 3:
|
|
no_autoconvert = name_arg0[3]
|
|
else:
|
|
name = name_arg0
|
|
|
|
# determine standard c typename
|
|
std_type = "error_type"
|
|
printer = None
|
|
|
|
# convert bool to int
|
|
if RecordFactory.BOOl_TYPES.count(ctype) > 0:
|
|
ctype = "u8"
|
|
|
|
# convert string to character equivalent
|
|
is_string = False
|
|
if ctype == RecordFactory.STR_TYPE:
|
|
is_string = True
|
|
ctype = "u16"
|
|
printer = CharPrinter()
|
|
|
|
# auto-convert types if needed
|
|
if is_string:
|
|
content = str(content)
|
|
elif isinstance(content, str) and not no_autoconvert:
|
|
content = int(content, base=0) # auto-recognize base
|
|
|
|
if no_autoconvert:
|
|
printer = ContentPrinter()
|
|
|
|
# loop-up standard c-type
|
|
if RecordFactory.INT_LIKE_TYPES.count(ctype) > 0: # integer
|
|
storage_size_str = ctype.strip("ui")
|
|
if ctype[0] == 'u':
|
|
std_type = ctype[0] + "int" + storage_size_str + "_t"
|
|
else:
|
|
std_type = "int" + storage_size_str + "_t"
|
|
|
|
if printer is None: # if printer is not assigned yet
|
|
printer = IntPrinter()
|
|
|
|
# generate record
|
|
rec = Record(name, std_type, content, printer)
|
|
if no_autoconvert:
|
|
rec.array_like = False
|
|
return rec
|
|
|
|
@staticmethod
|
|
def createa(defs):
|
|
recs = []
|
|
for rec in defs:
|
|
recs.append(RecordFactory.create(rec))
|
|
|
|
return recs
|
|
|
|
# # integer-like record
|
|
# class IntRecord(Record):
|
|
# def __init__(self, name, ctype, content):
|
|
# super().__init__(name, ctype, content, IntPrinter())
|
|
#
|
|
#
|
|
# # string record
|
|
# class StrRecord(Record):
|
|
# def __init__(self, name, content):
|
|
# super().__init__(name, "uint16_t", content, CharPrinter)
|