|
@@ -18,7 +18,9 @@ builtin_types = ["UA_Boolean", "UA_Byte", "UA_Int16", "UA_UInt16", "UA_Int32", "
|
|
|
"UA_StatusCode", "UA_QualifiedName", "UA_LocalizedText", "UA_ExtensionObject",
|
|
|
"UA_Variant", "UA_DataValue", "UA_DiagnosticInfo"]
|
|
|
|
|
|
-excluded_types = ["UA_InstanceNode", "UA_TypeNode", "UA_ServerDiagnosticsSummaryDataType",
|
|
|
+excluded_types = ["UA_NodeIdType", "UA_InstanceNode", "UA_TypeNode", "UA_Node", "UA_ObjectNode",
|
|
|
+ "UA_ObjectTypeNode", "UA_VariableNode", "UA_VariableTypeNode", "UA_ReferenceTypeNode",
|
|
|
+ "UA_MethodNode", "UA_ViewNode", "UA_DataTypeNode", "UA_ServerDiagnosticsSummaryDataType",
|
|
|
"UA_SamplingIntervalDiagnosticsDataType", "UA_SessionSecurityDiagnosticsDataType",
|
|
|
"UA_SubscriptionDiagnosticsDataType", "UA_SessionDiagnosticsDataType"]
|
|
|
|
|
@@ -33,6 +35,19 @@ class Type(object):
|
|
|
def typelayout_c(self):
|
|
|
pass
|
|
|
|
|
|
+class BuiltinType(Type):
|
|
|
+ def __init__(self, name, description = "", zeroCopyable = False):
|
|
|
+ self.name = name
|
|
|
+ self.description = description
|
|
|
+ self.zeroCopyable = zeroCopyable
|
|
|
+
|
|
|
+ def fixed_size(self):
|
|
|
+ return self.name in fixed_size
|
|
|
+
|
|
|
+ def typelayout_c(self):
|
|
|
+ return "{.memSize = sizeof(" + self.name + "), .zeroCopyable = " + \
|
|
|
+ ("UA_TRUE" if self.zeroCopyable else "UA_FALSE") + ", .membersSize = 0 }"
|
|
|
+
|
|
|
class EnumerationType(Type):
|
|
|
def __init__(self, name, description = "", elements = OrderedDict()):
|
|
|
self.name = name
|
|
@@ -42,24 +57,30 @@ class EnumerationType(Type):
|
|
|
def append_enum(name, value):
|
|
|
self.elements[name] = value
|
|
|
|
|
|
+ def fixed_size(self):
|
|
|
+ return True
|
|
|
+
|
|
|
def typedef_c(self):
|
|
|
return "typedef enum { \n " + \
|
|
|
",\n ".join(map(lambda (key,value) : key.upper() + " = " + value,self.elements.iteritems())) + \
|
|
|
"\n} " + self.name + ";"
|
|
|
|
|
|
- def typelayout_c(self, tablename):
|
|
|
- return "(UA_DataTypeLayout) {.memsize = sizeof(" + self.name "), .binarySize = 4," + \
|
|
|
- ".constantSize = UA_TRUE, .binaryZeroCopy = UA_TRUE, isBuiltin = UA_FALSE," + \
|
|
|
- ".memberDetails = " + \
|
|
|
- ".membersSize = 0, .table = " + tablename + " }"
|
|
|
+ def typelayout_c(self):
|
|
|
+ return "{.memSize = sizeof(" + self.name + "), .zeroCopyable = UA_TRUE, " + \
|
|
|
+ ".membersSize = 1,\n\t.members[0] = {.memberTypeIndex = UA_INT32," + \
|
|
|
+ ".nameSpaceZero = UA_TRUE, .padding = 0, .isArray = UA_FALSE } }"
|
|
|
|
|
|
class OpaqueType(Type):
|
|
|
+ def fixed_size(self):
|
|
|
+ return False
|
|
|
+
|
|
|
def typedef_c(self):
|
|
|
return "typedef UA_ByteString " + self.name + ";"
|
|
|
- def typelayout_c(self, tablename):
|
|
|
- return "(UA_DataTypeLayout) {.memsize = sizeof(" + self.name "), .binarySize = 4," + \
|
|
|
- ".constantSize = UA_TRUE, .binaryZeroCopy = UA_TRUE, isBuiltin = UA_FALSE," + \
|
|
|
- ".membersSize = 0, .table = " + tablename + " }"
|
|
|
+
|
|
|
+ def typelayout_c(self):
|
|
|
+ return "{.memSize = sizeof(" + self.name + "), .zeroCopyable = UA_FALSE, " + \
|
|
|
+ ".membersSize = 1,\n\t.members[0] = {.memberTypeIndex = UA_BYTE," + \
|
|
|
+ ".nameSpaceZero = UA_TRUE, .padding = offsetof(UA_String, data), .isArray = UA_TRUE } }"
|
|
|
|
|
|
class StructMember(object):
|
|
|
def __init__(self, name, memberType, isArray):
|
|
@@ -76,7 +97,7 @@ class StructType(Type):
|
|
|
def fixed_size(self):
|
|
|
if self.name in fixed_size:
|
|
|
return True
|
|
|
- for m in self.members:
|
|
|
+ for m in self.members.values():
|
|
|
if m.isArray or not m.memberType.fixed_size():
|
|
|
return False
|
|
|
return True
|
|
@@ -87,19 +108,43 @@ class StructType(Type):
|
|
|
returnstr = "typedef struct {\n"
|
|
|
for name, member in self.members.iteritems():
|
|
|
if member.isArray:
|
|
|
- returnstr += " UA_Int32 noOf" + name[0].upper() + name[1:] + ";\n"
|
|
|
- returnstr += " " + member.memberType + " *" +name + ";\n"
|
|
|
+ returnstr += " UA_Int32 " + name + "Size;\n"
|
|
|
+ returnstr += " " + member.memberType.name + " *" +name + ";\n"
|
|
|
else:
|
|
|
- returnstr += " " + member.memberType + " " +name + ";\n"
|
|
|
+ returnstr += " " + member.memberType.name + " " +name + ";\n"
|
|
|
return returnstr + "} " + self.name + ";"
|
|
|
|
|
|
+ def typelayout_c(self):
|
|
|
+ layout = "{.memSize = sizeof(" + self.name + "), .zeroCopyable = " + \
|
|
|
+ ("UA_TRUE, " if self.fixed_size() else "UA_FALSE, ") + \
|
|
|
+ ".membersSize = " + str(len(self.members)) + ","
|
|
|
+ for index, member in enumerate(self.members.values()):
|
|
|
+ layout += "\n\t.members["+ str(index)+ "] = {" + \
|
|
|
+ ".memberTypeIndex = UA_" + member.memberType.name.upper()[3:] + ", " + \
|
|
|
+ ".nameSpaceZero = "+ \
|
|
|
+ ("UA_TRUE, " if args.is_ns0 or member.memberType.name in builtin_types else "UA_FALSE, ") + \
|
|
|
+ ".padding = "
|
|
|
+ if index == 0:
|
|
|
+ layout += "0, "
|
|
|
+ else:
|
|
|
+ before = self.members.values()[index-1]
|
|
|
+ layout += "offsetof(" + self.name + ", "+ member.name + ") - offsetof(" + self.name + ", " + before.name + ")"
|
|
|
+ if member.isArray:
|
|
|
+ layout += " - sizeof(UA_Int32) "
|
|
|
+ if before.isArray:
|
|
|
+ layout += " - sizeof(void *), "
|
|
|
+ else:
|
|
|
+ layout += " - sizeof(" + before.memberType.name + "), "
|
|
|
+ layout += ".isArray = " + ("UA_TRUE" if member.isArray else "UA_FALSE") + " }, "
|
|
|
+ return layout + "}"
|
|
|
+
|
|
|
def parseTypeDefinitions(xmlDescription, type_selection = None):
|
|
|
'''Returns an ordered dict that maps names to types. The order is such that
|
|
|
every type depends only on known types. '''
|
|
|
ns = {"opc": "http://opcfoundation.org/BinarySchema/"}
|
|
|
tree = etree.parse(xmlDescription)
|
|
|
typeSnippets = tree.xpath("/opc:TypeDictionary/*[not(self::opc:Import)]", namespaces=ns)
|
|
|
- types = OrderedDict()
|
|
|
+ types = OrderedDict([(t, BuiltinType(t, "", t in fixed_size)) for t in builtin_types])
|
|
|
|
|
|
# types we do not want to autogenerate
|
|
|
def skipType(name):
|
|
@@ -169,9 +214,10 @@ def parseTypeDefinitions(xmlDescription, type_selection = None):
|
|
|
continue
|
|
|
if child.get("Name") in lengthfields:
|
|
|
continue
|
|
|
- memberType = "UA_" + stripTypename(child.get("TypeName"))
|
|
|
- if not memberType in types and not memberType in builtin_types:
|
|
|
+ memberTypeName = "UA_" + stripTypename(child.get("TypeName"))
|
|
|
+ if not memberTypeName in types:
|
|
|
return None
|
|
|
+ memberType = types[memberTypeName]
|
|
|
memberName = camlCase2CCase(child.get("Name"))
|
|
|
isArray = True if child.get("LengthField") else False
|
|
|
members[memberName] = StructMember(memberName, memberType, isArray)
|
|
@@ -199,36 +245,31 @@ def parseTypeDefinitions(xmlDescription, type_selection = None):
|
|
|
types[t.name] = t
|
|
|
return types
|
|
|
|
|
|
-def main():
|
|
|
- parser = argparse.ArgumentParser()
|
|
|
- parser.add_argument('--only-needed', action='store_true', help='generate only types needed for compile')
|
|
|
- parser.add_argument('xml', help='path/to/Opc.Ua.Types.bsd')
|
|
|
- parser.add_argument('outfile', help='outfile w/o extension')
|
|
|
-
|
|
|
- args = parser.parse_args()
|
|
|
- outname = args.outfile.split("/")[-1]
|
|
|
- inname = args.xml.split("/")[-1]
|
|
|
-
|
|
|
- fh = open(args.outfile + "_generated.h",'w')
|
|
|
- def printh(string):
|
|
|
- print(string, end='\n', file=fh)
|
|
|
-
|
|
|
- # # whitelist for "only needed" profile
|
|
|
- # from type_lists import only_needed_types
|
|
|
-
|
|
|
- # # some types are omitted (pretend they exist already)
|
|
|
- # existing_types.add("NodeIdType")
|
|
|
-
|
|
|
- types = parseTypeDefinitions(args.xml)
|
|
|
-
|
|
|
- printh('''/**
|
|
|
- * @file ''' + outname + '''_generated.h
|
|
|
- *
|
|
|
- * @brief Autogenerated data types
|
|
|
- *
|
|
|
- * Generated from ''' + inname + ''' with script ''' + sys.argv[0] + '''
|
|
|
- * on host ''' + platform.uname()[1] + ''' by user ''' + getpass.getuser() + ''' at ''' + time.strftime("%Y-%m-%d %I:%M:%S") + '''
|
|
|
- */
|
|
|
+parser = argparse.ArgumentParser()
|
|
|
+parser.add_argument('--is-ns0', action='store_true', help='the builtin-types are added to namespace 0')
|
|
|
+parser.add_argument('xml', help='path/to/Opc.Ua.Types.bsd')
|
|
|
+parser.add_argument('outfile', help='outfile w/o extension')
|
|
|
+
|
|
|
+args = parser.parse_args()
|
|
|
+outname = args.outfile.split("/")[-1]
|
|
|
+inname = args.xml.split("/")[-1]
|
|
|
+types = OrderedDict(parseTypeDefinitions(args.xml).items())
|
|
|
+
|
|
|
+fh = open("ua_" + args.outfile + "_generated.h",'w')
|
|
|
+fc = open("ua_" + args.outfile + "_generated.c",'w')
|
|
|
+def printh(string):
|
|
|
+ print(string, end='\n', file=fh)
|
|
|
+def printc(string):
|
|
|
+ print(string, end='\n', file=fc)
|
|
|
+
|
|
|
+printh('''/**
|
|
|
+* @file ''' + outname + '''_generated.h
|
|
|
+*
|
|
|
+* @brief Autogenerated data types
|
|
|
+*
|
|
|
+* Generated from ''' + inname + ''' with script ''' + sys.argv[0] + '''
|
|
|
+* on host ''' + platform.uname()[1] + ''' by user ''' + getpass.getuser() + ''' at ''' + time.strftime("%Y-%m-%d %I:%M:%S") + '''
|
|
|
+*/
|
|
|
|
|
|
#ifndef ''' + outname.upper() + '''_GENERATED_H_
|
|
|
#define ''' + outname.upper() + '''_GENERATED_H_
|
|
@@ -240,21 +281,29 @@ extern "C" {
|
|
|
#include "ua_types.h"
|
|
|
|
|
|
/**
|
|
|
- * @ingroup types
|
|
|
- *
|
|
|
- * @defgroup ''' + outname + '''_generated Autogenerated ''' + outname + ''' Types
|
|
|
- *
|
|
|
- * @brief Data structures that are autogenerated from an XML-Schema.
|
|
|
- * @{
|
|
|
- */''')
|
|
|
-
|
|
|
- for t in types.itervalues():
|
|
|
+* @ingroup types
|
|
|
+*
|
|
|
+* @defgroup ''' + outname + '''_generated Autogenerated ''' + outname + ''' Types
|
|
|
+*
|
|
|
+* @brief Data structures that are autogenerated from an XML-Schema.
|
|
|
+*
|
|
|
+* @{
|
|
|
+*/
|
|
|
+
|
|
|
+extern const UA_DataTypeLayout *UA_''' + outname.upper() + ''';
|
|
|
+''')
|
|
|
+
|
|
|
+i = 0
|
|
|
+for t in types.itervalues():
|
|
|
+ if type(t) != BuiltinType:
|
|
|
printh("")
|
|
|
if t.description != "":
|
|
|
printh("/** @brief " + t.description + "*/")
|
|
|
printh(t.typedef_c())
|
|
|
+ printh("#define UA_" + t.name[3:].upper() + " " + str(i))
|
|
|
+ i += 1
|
|
|
|
|
|
- printh('''
|
|
|
+printh('''
|
|
|
/// @} /* end of group */
|
|
|
|
|
|
#ifdef __cplusplus
|
|
@@ -263,7 +312,28 @@ extern "C" {
|
|
|
|
|
|
#endif''')
|
|
|
|
|
|
- fh.close()
|
|
|
+printc('''/**
|
|
|
+* @file ''' + outname + '''_generated.c
|
|
|
+*
|
|
|
+* @brief Autogenerated data types
|
|
|
+*
|
|
|
+* Generated from ''' + inname + ''' with script ''' + sys.argv[0] + '''
|
|
|
+* on host ''' + platform.uname()[1] + ''' by user ''' + getpass.getuser() + ''' at ''' + time.strftime("%Y-%m-%d %I:%M:%S") + '''
|
|
|
+*/
|
|
|
+
|
|
|
+#include "stddef.h"
|
|
|
+#include "ua_''' + outname + '''_generated.h"
|
|
|
+
|
|
|
+const UA_DataTypeLayout *UA_TYPES = (const UA_DataTypeLayout[]){''')
|
|
|
+
|
|
|
+for t in types.itervalues():
|
|
|
+ if type(t) == BuiltinType and not args.is_ns0:
|
|
|
+ continue
|
|
|
+ printc("")
|
|
|
+ printc("/* " + t.name + "*/")
|
|
|
+ printc(t.typelayout_c() + ",")
|
|
|
+
|
|
|
+printc("};")
|
|
|
|
|
|
-if __name__ == "__main__":
|
|
|
- main()
|
|
|
+fh.close()
|
|
|
+fc.close()
|