123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611 |
- from __future__ import print_function
- import sys
- import time
- import platform
- import getpass
- from collections import OrderedDict
- import re
- from lxml import etree
- import itertools
- import argparse
- from pprint import pprint
- fixed_size = {"UA_Boolean": 1, "UA_SByte": 1, "UA_Byte": 1, "UA_Int16": 2, "UA_UInt16": 2,
- "UA_Int32": 4, "UA_UInt32": 4, "UA_Int64": 8, "UA_UInt64": 8, "UA_Float": 4,
- "UA_Double": 8, "UA_DateTime": 8, "UA_Guid": 16, "UA_StatusCode": 4}
- zero_copy = ["UA_Boolean", "UA_SByte", "UA_Byte", "UA_Int16", "UA_UInt16", "UA_Int32", "UA_UInt32",
- "UA_Int64", "UA_UInt64", "UA_Float", "UA_Double", "UA_DateTime", "UA_StatusCode"]
- # The order of the builtin-types is not as in the standard. We put all the
- # fixed_size types in the front, so they can be distinguished by a simple geq
- # comparison. That's ok, since we use the type-index only internally!!
- builtin_types = ["UA_Boolean", "UA_SByte", "UA_Byte", "UA_Int16", "UA_UInt16",
- "UA_Int32", "UA_UInt32", "UA_Int64", "UA_UInt64", "UA_Float",
- "UA_Double", "UA_String", "UA_DateTime", "UA_Guid", "UA_ByteString",
- "UA_XmlElement", "UA_NodeId", "UA_ExpandedNodeId", "UA_StatusCode",
- "UA_QualifiedName", "UA_LocalizedText", "UA_ExtensionObject", "UA_DataValue",
- "UA_Variant", "UA_DiagnosticInfo"]
- 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"]
- minimal_types = ["InvalidType", "Node", "NodeClass", "ReferenceNode", "ApplicationDescription", "ApplicationType",
- "ChannelSecurityToken", "OpenSecureChannelRequest", "OpenSecureChannelResponse",
- "CloseSecureChannelRequest", "CloseSecureChannelResponse", "RequestHeader", "ResponseHeader",
- "SecurityTokenRequestType", "MessageSecurityMode", "CloseSessionResponse", "CloseSessionRquest",
- "ActivateSessionRequest", "ActivateSessionResponse", "SignatureData", "SignedSoftwareCertificate",
- "CreateSessionResponse", "CreateSessionRequest", "EndpointDescription", "UserTokenPolicy", "UserTokenType",
- "GetEndpointsRequest", "GetEndpointsResponse", "PublishRequest", "PublishResponse", "FindServersRequest",
- "FindServersResponse", "SetPublishingModeResponse", "SubscriptionAcknowledgement", "NotificationMessage",
- "ExtensionObject", "Structure", "ReadRequest", "ReadResponse", "ReadValueId", "TimestampsToReturn", "WriteRequest",
- "WriteResponse", "WriteValue", "SetPublishingModeRequest", "CreateMonitoredItemsResponse",
- "MonitoredItemCreateResult", "CreateMonitoredItemsRequest", "MonitoredItemCreateRequest",
- "MonitoringMode", "MonitoringParameters", "TranslateBrowsePathsToNodeIdsRequest",
- "TranslateBrowsePathsToNodeIdsResponse", "BrowsePath", "BrowsePathResult", "RelativePath",
- "BrowsePathTarget", "RelativePathElement", "CreateSubscriptionRequest", "CreateSubscriptionResponse",
- "BrowseResponse", "BrowseResult", "ReferenceDescription", "BrowseRequest", "ViewDescription",
- "BrowseNextRequest", "BrowseNextResponse", "DeleteSubscriptionsRequest", "DeleteSubscriptionsResponse",
- "BrowseDescription", "BrowseDirection", "CloseSessionRequest", "AddNodesRequest", "AddNodesResponse",
- "AddNodesItem", "AddNodesResult", "DeleteNodesItem","AddReferencesRequest", "AddReferencesResponse",
- "AddReferencesItem","DeleteReferencesItem", "VariableNode", "MethodNode", "VariableTypeNode",
- "ViewNode", "ReferenceTypeNode", "BrowseResultMask", "ServerState", "ServerStatusDataType", "BuildInfo",
- "ObjectNode", "DataTypeNode", "ObjectTypeNode", "IdType", "NodeAttributes",
- "VariableAttributes", "ObjectAttributes", "ReferenceTypeAttributes", "ViewAttributes", "MethodAttributes",
- "ObjectTypeAttributes", "VariableTypeAttributes", "DataTypeAttributes", "NodeAttributesMask",
- "DeleteNodesItem", "DeleteNodesRequest", "DeleteNodesResponse",
- "DeleteReferencesItem", "DeleteReferencesRequest", "DeleteReferencesResponse",
- "RegisterNodesRequest", "RegisterNodesResponse", "UnregisterNodesRequest", "UnregisterNodesResponse",
- "UserIdentityToken", "UserNameIdentityToken", "AnonymousIdentityToken", "ServiceFault",
- "CallMethodRequest", "CallMethodResult", "CallResponse", "CallRequest", "Argument",
- "FilterOperator", "ContentFilterElement", "ContentFilter", "QueryDataDescription",
- "NodeTypeDescription", "QueryFirstRequest", "QueryDataSet", "ParsingResult",
- "ContentFilterElementResult", "ContentFilterResult", "QueryFirstResponse",
- "QueryNextRequest", "QueryNextResponse"]
- subscription_types = ["CreateSubscriptionRequest", "CreateSubscriptionResponse",
- "DeleteMonitoredItemsRequest", "DeleteMonitoredItemsResponse", "NotificationMessage",
- "MonitoredItemNotification", "DataChangeNotification", "ModifySubscriptionRequest",
- "ModifySubscriptionResponse", "RepublishRequest", "RepublishResponse"]
- class TypeDescription(object):
- def __init__(self, name, nodeid, namespaceid):
- self.name = name # without the UA_ prefix
- self.nodeid = nodeid
- self.namespaceid = namespaceid
- def parseTypeDescriptions(filename, namespaceid):
- definitions = {}
- f = open(filename[0])
- input_str = f.read()
- f.close()
- input_str = input_str.replace('\r','')
- rows = map(lambda x:tuple(x.split(',')), input_str.split('\n'))
- for index, row in enumerate(rows):
- if len(row) < 3:
- continue
- if row[2] != "DataType":
- continue
- if row[0] == "BaseDataType":
- definitions["UA_Variant"] = TypeDescription(row[0], row[1], namespaceid)
- elif row[0] == "Structure":
- definitions["UA_ExtensionObject"] = TypeDescription(row[0], row[1], namespaceid)
- else:
- definitions["UA_" + row[0]] = TypeDescription(row[0], row[1], namespaceid)
- return definitions
- class Type(object):
- def __init__(self, name, description = ""):
- self.name = name
- self.description = description
- def fixed_size(self):
- return self.name in fixed_size
- def mem_size(self):
- return fixed_size[self.name]
- def zero_copy(self):
- return self.name in zero_copy
- def typedef_c(self):
- pass
-
- def functions_c(self, typeTableName):
- return ('''static UA_INLINE void %s_init(%s *p) { memset(p, 0, sizeof(%s)); }
- static UA_INLINE void %s_delete(%s *p) { UA_delete(p, %s); }
- static UA_INLINE void %s_deleteMembers(%s *p) { ''' + ("UA_deleteMembers(p, &"+typeTableName+"["+typeTableName+"_"+self.name[3:].upper()+"]);" if not self.fixed_size() else "") + ''' }
- static UA_INLINE %s * %s_new(void) { return (%s*) UA_new(%s); }
- static UA_INLINE UA_StatusCode %s_copy(const %s *src, %s *dst) { ''' + \
- ("*dst = *src; return UA_STATUSCODE_GOOD;" if self.fixed_size() else "return UA_copy(src, dst, &" + typeTableName+"["+typeTableName+"_"+self.name[3:].upper() + "]);") +" }") % \
- tuple([self.name, self.name, self.name] +
- [self.name, self.name, "&"+typeTableName+"[" + typeTableName + "_" + self.name[3:].upper()+"]"] +
- [self.name, self.name] +
- [self.name, self.name, self.name, "&"+typeTableName+"[" + typeTableName + "_" + self.name[3:].upper()+"]"] +
- [self.name, self.name, self.name])
- def encoding_h(self, typeTableName):
- return '''static UA_INLINE UA_StatusCode %s_encodeBinary(const %s *src, UA_ByteString *dst, size_t *offset) { return UA_encodeBinary(src, %s, dst, offset); }
- static UA_INLINE UA_StatusCode %s_decodeBinary(const UA_ByteString *src, size_t *offset, %s *dst) { return UA_decodeBinary(src, offset, dst, %s); }''' % \
- tuple(list(itertools.chain(*itertools.repeat([self.name, self.name, "&"+typeTableName+"[" + typeTableName + "_" + self.name[3:].upper()+"]"], 2))))
- class BuiltinType(Type):
- "Generic type without members. Used for builtin types."
- def typelayout_c(self, namespace_0, description, outname):
- if description == None:
- typeid = "{.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = 0}, "
- else:
- typeid = "{.namespaceIndex = %s, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = %s}, " % \
- (description.namespaceid, description.nodeid)
- if self.name in ["UA_String", "UA_ByteString", "UA_XmlElement"]:
- return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
- ".memSize = sizeof(" + self.name + "), " + \
- ".builtin = UA_TRUE, .fixedSize = UA_FALSE, .zeroCopyable = UA_FALSE, " + \
- ".membersSize = 1,\n\t.members = {{.memberTypeIndex = UA_TYPES_BYTE, .namespaceZero = UA_TRUE, " + \
- (".memberName = \"\", " if typeintrospection else "") + \
- ".padding = 0, .isArray = UA_TRUE }}, " + \
- ".typeIndex = %s }" % (outname.upper() + "_" + self.name[3:].upper())
- if self.name == "UA_ExpandedNodeId":
- return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
- ".memSize = sizeof(UA_ExpandedNodeId), " + \
- ".builtin = UA_TRUE, .fixedSize = UA_FALSE, .zeroCopyable = UA_FALSE, " + \
- ".membersSize = 3, .members = {" + \
- "\n\t{.memberTypeIndex = UA_TYPES_NODEID, .namespaceZero = UA_TRUE, " + \
- (".memberName = \"nodeId\", " if typeintrospection else "") + \
- ".padding = 0, .isArray = UA_FALSE }," + \
- "\n\t{.memberTypeIndex = UA_TYPES_STRING, .namespaceZero = UA_TRUE, " + \
- (".memberName = \"namespaceUri\", " if typeintrospection else "") + \
- ".padding = offsetof(UA_ExpandedNodeId, namespaceUri) - sizeof(UA_NodeId), .isArray = UA_FALSE }," + \
- "\n\t{.memberTypeIndex = UA_TYPES_UINT32, .namespaceZero = UA_TRUE, " + \
- (".memberName = \"serverIndex\", " if typeintrospection else "") + \
- ".padding = offsetof(UA_ExpandedNodeId, serverIndex) - offsetof(UA_ExpandedNodeId, namespaceUri) - sizeof(UA_String), .isArray = UA_FALSE }},\n" + \
- ".typeIndex = UA_TYPES_EXPANDEDNODEID }"
- if self.name == "UA_QualifiedName":
- return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
- ".memSize = sizeof(UA_QualifiedName), " + \
- ".builtin = UA_TRUE, .fixedSize = UA_FALSE, .zeroCopyable = UA_FALSE, " + \
- ".membersSize = 2, .members = {" + \
- "\n\t{.memberTypeIndex = UA_TYPES_UINT16, .namespaceZero = UA_TRUE, " + \
- (".memberName = \"namespaceIndex\", " if typeintrospection else "") + \
- ".padding = 0, .isArray = UA_FALSE }," + \
- "\n\t{.memberTypeIndex = UA_TYPES_STRING, .namespaceZero = UA_TRUE, " + \
- (".memberName = \"name\", " if typeintrospection else "") + \
- ".padding = offsetof(UA_QualifiedName, name)-sizeof(UA_UInt16), .isArray = UA_FALSE }},\n" + \
- ".typeIndex = UA_TYPES_QUALIFIEDNAME }"
- if self.name == "UA_LocalizedText":
- return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
- ".memSize = sizeof(UA_LocalizedText), " + \
- ".builtin = UA_TRUE, .fixedSize = UA_FALSE, .zeroCopyable = UA_FALSE, " + \
- ".membersSize = 2, .members = {" + \
- "\n\t{.memberTypeIndex = UA_TYPES_STRING, .namespaceZero = UA_TRUE, " + \
- (".memberName = \"locale\", " if typeintrospection else "") + \
- ".padding = 0, .isArray = UA_FALSE }," + \
- "\n\t{.memberTypeIndex = UA_TYPES_STRING, .namespaceZero = UA_TRUE, " + \
- (".memberName = \"text\", " if typeintrospection else "") + \
- ".padding = offsetof(UA_LocalizedText, text)-sizeof(UA_String), .isArray = UA_FALSE }},\n" + \
- ".typeIndex = UA_TYPES_LOCALIZEDTEXT }"
- return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
- ".memSize = sizeof(" + self.name + "), " + \
- ".builtin = UA_TRUE, .fixedSize = " + ("UA_TRUE" if self.fixed_size() else "UA_FALSE") + \
- ", .zeroCopyable = " + ("UA_TRUE" if self.zero_copy() else "UA_FALSE") + \
- ", .membersSize = 1, .members = {" + \
- "\n\t{.memberTypeIndex = UA_TYPES_" + self.name[3:].upper() + " , .namespaceZero = UA_TRUE, " + \
- (".memberName = \"\", " if typeintrospection else "") + \
- ".padding = 0, .isArray = UA_FALSE }},\n" + \
- ".typeIndex = UA_TYPES_" + self.name[3:].upper() + " }"
- class EnumerationType(Type):
- def __init__(self, name, description = "", elements = OrderedDict()):
- self.name = name
- self.description = description
- self.elements = elements # maps a name to an integer value
- def append_enum(name, value):
- self.elements[name] = value
- def fixed_size(self):
- return True
- def mem_size(self):
- return 4
- def zero_copy(self):
- return True
- def typedef_c(self):
- if sys.version_info[0] < 3:
- values = self.elements.iteritems()
- else:
- values = self.elements.items()
- return "typedef enum { \n " + \
- ",\n ".join(map(lambda kv : kv[0].upper() + " = " + kv[1], values)) + \
- "\n} " + self.name + ";"
- def typelayout_c(self, namespace_0, description, outname):
- if description == None:
- typeid = "{.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = 0}, "
- else:
- typeid = "{.namespaceIndex = %s, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = %s}, " % (description.namespaceid, description.nodeid)
- return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
- ".memSize = sizeof(" + self.name + "), .builtin = UA_TRUE, " + \
- ".fixedSize = UA_TRUE, .zeroCopyable = UA_TRUE, " + \
- ".membersSize = 1,\n\t.members = {{.memberTypeIndex = UA_TYPES_INT32, " + \
- (".memberName = \"\", " if typeintrospection else "") + \
- ".namespaceZero = UA_TRUE, .padding = 0, .isArray = UA_FALSE }}, .typeIndex = UA_TYPES_INT32 }"
- class OpaqueType(Type):
- def fixed_size(self):
- return False
- def zero_copy(self):
- return False
- def typedef_c(self):
- return "typedef UA_ByteString " + self.name + ";"
- def typelayout_c(self, namespace_0, description, outname):
- if description == None:
- typeid = "{.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = 0}, "
- else:
- typeid = "{.namespaceIndex = %s, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = %s}, " % (description.namespaceid, description.nodeid)
- return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
- ".memSize = sizeof(" + self.name + "), .fixedSize = UA_FALSE, .zeroCopyable = UA_FALSE, " + \
- ".builtin = UA_FALSE, .membersSize = 1,\n\t.members = {{.memberTypeIndex = UA_TYPES_BYTE," + \
- (".memberName = \"\", " if typeintrospection else "") + \
- ".namespaceZero = UA_TRUE, .padding = 0, .isArray = UA_TRUE }}, .typeIndex = %s}" % (outname.upper() + "_" + self.name[3:].upper())
- class StructMember(object):
- def __init__(self, name, memberType, isArray):
- self.name = name
- self.memberType = memberType
- self.isArray = isArray
- class StructType(Type):
- def __init__(self, name, description, members = OrderedDict()):
- self.name = name
- self.description = description
- self.members = members # maps a name to a member definition
- def fixed_size(self):
- for m in self.members.values():
- if m.isArray or not m.memberType.fixed_size():
- return False
- return True
- def mem_size(self):
- total = 0
- for m in self.members.values():
- if m.isArray:
- raise Exception("Arrays have no fixed size!")
- else:
- total += m.memberType.mem_size()
- return total
- def zero_copy(self):
- for m in self.members.values():
- if m.isArray or not m.memberType.zero_copy():
- return False
- return True
- def typedef_c(self):
- if len(self.members) == 0:
- return "typedef void * " + self.name + ";"
- returnstr = "typedef struct {\n"
- if sys.version_info[0] < 3:
- values = self.members.iteritems()
- else:
- values = self.members.items()
- for name, member in values:
- if member.isArray:
- returnstr += " size_t " + name + "Size;\n"
- returnstr += " " + member.memberType.name + " *" +name + ";\n"
- else:
- returnstr += " " + member.memberType.name + " " +name + ";\n"
- return returnstr + "} " + self.name + ";"
- def typelayout_c(self, namespace_0, description, outname):
- if description == None:
- typeid = "{.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = 0}, "
- else:
- typeid = "{.namespaceIndex = %s, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = %s}, " % (description.namespaceid, description.nodeid)
- layout = (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
- ".memSize = sizeof(" + self.name + "), "+ \
- ".builtin = UA_FALSE" + \
- ", .fixedSize = " + ("UA_TRUE" if self.fixed_size() else "UA_FALSE") + \
- ", .zeroCopyable = " + ("sizeof(" + self.name + ") == " + str(self.mem_size()) if self.zero_copy() \
- else "UA_FALSE") + \
- ", .typeIndex = " + outname.upper() + "_" + self.name[3:].upper() + \
- ", .membersSize = " + str(len(self.members)) + ","
- if len(self.members) > 0:
- layout += "\n\t.members={"
- for index, member in enumerate(self.members.values()):
- layout += "\n\t{" + \
- ((".memberName = \"" + member.name[0].upper() + member.name[1:] + "\", ") if typeintrospection else "") + \
- ".memberTypeIndex = " + ("UA_TYPES_" + member.memberType.name[3:].upper() if args.namespace_id == 0 or member.memberType.name in existing_types else \
- outname.upper() + "_" + member.memberType.name[3:].upper()) + ", " + \
- ".namespaceZero = "+ \
- ("UA_TRUE, " if args.namespace_id == 0 or member.memberType.name in existing_types else "UA_FALSE, ") + \
- ".padding = "
- if not member.isArray:
- thispos = "offsetof(%s, %s)" % (self.name, member.name)
- else:
- thispos = "offsetof(%s, %sSize)" % (self.name, member.name)
- before_endpos = "0"
- if index > 0:
- if sys.version_info[0] < 3:
- before = self.members.values()[index-1]
- else:
- before = list(self.members.values())[index-1]
- before_endpos = "(offsetof(%s, %s)" % (self.name, before.name)
- if before.isArray:
- before_endpos += " + sizeof(void*))"
- else:
- before_endpos += " + sizeof(%s))" % before.memberType.name
- layout += "%s - %s" % (thispos, before_endpos)
- layout += ", .isArray = " + ("UA_TRUE" if member.isArray else "UA_FALSE") + " }, "
- layout += "}"
- return layout + "}"
- def parseTypeDefinitions(xmlDescription, existing_types = OrderedDict()):
- '''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(existing_types.items())
- # types we do not want to autogenerate
- def skipType(name):
- if name in builtin_types:
- return True
- if name in excluded_types:
- return True
- if outname == "ua_types" and not name[3:] in minimal_types:
- return True
- if "Test" in name: # skip all test types
- return True
- if re.search("NodeId$", name) != None:
- return True
- return False
- def stripTypename(tn):
- return tn[tn.find(":")+1:]
- def camlCase2CCase(item):
- "Member names begin with a lower case character"
- return item[:1].lower() + item[1:] if item else ''
- def typeReady(element):
- "Do we have the member types yet?"
- for child in element:
- if child.tag == "{http://opcfoundation.org/BinarySchema/}Field":
- if stripTypename(child.get("TypeName")) not in types:
- return False
- return True
- def parseEnumeration(typeXml):
- name = "UA_" + typeXml.get("Name")
- description = ""
- elements = OrderedDict()
- for child in typeXml:
- if child.tag == "{http://opcfoundation.org/BinarySchema/}Documentation":
- description = child.text
- if child.tag == "{http://opcfoundation.org/BinarySchema/}EnumeratedValue":
- elements[name + "_" + child.get("Name")] = child.get("Value")
- return EnumerationType(name, description, elements)
- def parseOpaque(typeXml):
- name = "UA_" + typeXml.get("Name")
- description = ""
- for child in typeXml:
- if child.tag == "{http://opcfoundation.org/BinarySchema/}Documentation":
- description = child.text
- return OpaqueType(name, description)
- def parseStructured(typeXml):
- "Returns None if we miss member descriptions"
- name = "UA_" + typeXml.get("Name")
- description = ""
- for child in typeXml:
- if child.tag == "{http://opcfoundation.org/BinarySchema/}Documentation":
- description = child.text
- # ignore lengthfields, just tag the array-members as an array
- lengthfields = []
- for child in typeXml:
- if child.get("LengthField"):
- lengthfields.append(child.get("LengthField"))
- members = OrderedDict()
- for child in typeXml:
- if not child.tag == "{http://opcfoundation.org/BinarySchema/}Field":
- continue
- if child.get("Name") in lengthfields:
- continue
- 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)
- return StructType(name, description, members)
- finished = False
- while(not finished):
- finished = True
- for typeXml in typeSnippets:
- name = "UA_" + typeXml.get("Name")
- if name in types or skipType(name):
- continue
- if typeXml.tag == "{http://opcfoundation.org/BinarySchema/}EnumeratedType":
- t = parseEnumeration(typeXml)
- types[t.name] = t
- elif typeXml.tag == "{http://opcfoundation.org/BinarySchema/}OpaqueType":
- t = parseOpaque(typeXml)
- types[t.name] = t
- elif typeXml.tag == "{http://opcfoundation.org/BinarySchema/}StructuredType":
- t = parseStructured(typeXml)
- if t == None:
- finished = False
- else:
- types[t.name] = t
- # remove the existing types
- for k in existing_types.keys():
- types.pop(k)
- return types
- parser = argparse.ArgumentParser()
- parser.add_argument('--ns0-types-xml', nargs=1, help='xml-definition of the ns0 types that are assumed to already exist')
- parser.add_argument('--enable-subscription-types', nargs=1, help='Generate datatypes necessary for Montoring and Subscriptions.')
- parser.add_argument('--typedescriptions', nargs=1, help='csv file with type descriptions')
- parser.add_argument('--typeintrospection', help='add the type and member names to the idatatype structures', action='store_true')
- parser.add_argument('namespace_id', type=int, help='the id of the target namespace')
- parser.add_argument('types_xml', help='path/to/Opc.Ua.Types.bsd')
- parser.add_argument('outfile', help='output file w/o extension')
- args = parser.parse_args()
- outname = args.outfile.split("/")[-1]
- inname = args.types_xml.split("/")[-1]
- typeintrospection = args.typeintrospection
- existing_types = OrderedDict()
- if args.enable_subscription_types:
- minimal_types = minimal_types + subscription_types
- if args.namespace_id == 0 or args.ns0_types_xml:
- existing_types = OrderedDict([(t, BuiltinType(t)) for t in builtin_types])
- if args.ns0_types_xml:
- if sys.version_info[0] < 3:
- OrderedDict(existing_types.items() + parseTypeDefinitions(args.ns0_types_xml[0], existing_types).items())
- else:
- OrderedDict(list(existing_types.items()) + list(parseTypeDefinitions(args.ns0_types_xml[0], existing_types).items()))
- types = parseTypeDefinitions(args.types_xml, existing_types)
- if args.namespace_id == 0:
- if sys.version_info[0] < 3:
- types = OrderedDict(existing_types.items() + types.items())
- else:
- types = OrderedDict(list(existing_types.items()) + list(types.items()))
- typedescriptions = {}
- if args.typedescriptions:
- typedescriptions = parseTypeDescriptions(args.typedescriptions, args.namespace_id)
- fh = open(args.outfile + "_generated.h",'w')
- fe = open(args.outfile + "_generated_encoding_binary.h",'w')
- fc = open(args.outfile + "_generated.c",'w')
- def printh(string):
- print(string, end='\n', file=fh)
- def printe(string):
- print(string, end='\n', file=fe)
- 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_
- #ifdef __cplusplus
- extern "C" {
- #endif
- #include "ua_types.h"
- #ifdef UA_INTERNAL
- #include "ua_types_encoding_binary.h"
- #endif'''
- + ('\n#include "ua_types_generated.h"\n' if args.namespace_id != 0 else '') + '''
- /**
- * @ingroup types
- *
- * @defgroup ''' + outname + '''_generated Autogenerated ''' + outname + ''' Types
- *
- * @brief Data structures that are autogenerated from an XML-Schema.
- *
- * @{
- */
- ''')
- printh("#define " + outname.upper() + "_COUNT %s\n" % (str(len(types))))
- printh("extern UA_EXPORT const UA_DataType *" + outname.upper() + ";\n")
- i = 0
- if sys.version_info[0] < 3:
- values = types.itervalues()
- else:
- values = types.values()
- for t in values:
- printh("")
- if type(t) != BuiltinType:
- if t.description != "":
- printh("/** @brief " + t.description + " */")
- printh(t.typedef_c())
- printh("#define " + outname.upper() + "_" + t.name[3:].upper() + " " + str(i))
- printh(t.functions_c(outname.upper()))
- i += 1
- printh('''
- /// @} /* end of group */\n
- #ifdef __cplusplus
- } // extern "C"
- #endif\n
- #endif /* %s_GENERATED_H_ */''' % outname.upper())
- printe('''/**
- * @file ''' + outname + '''_generated_encoding_binary.h
- *
- * @brief Binary encoding for 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") + '''
- */\n
- #include "ua_types_encoding_binary.h"
- #include "''' + outname + '''_generated.h"''')
- 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") + '''
- */\n
- #include "stddef.h"
- #include "ua_types.h"
- #include "''' + outname + '''_generated.h"\n
- const UA_DataType *''' + outname.upper() + ''' = (UA_DataType[]){''')
- if sys.version_info[0] < 3:
- values = types.itervalues()
- else:
- values = types.values()
- for t in values:
- printc("")
- printc("/* " + t.name + " */")
- if args.typedescriptions:
- td = typedescriptions[t.name]
- else:
- td = None
- printc(t.typelayout_c(args.namespace_id == 0, td, outname) + ",")
- printe("")
- printe("/* " + t.name + " */")
- printe(t.encoding_h(outname.upper()))
- printc("};\n")
- fh.close()
- fe.close()
- fc.close()
|