generate_datatypes.py 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571
  1. from __future__ import print_function
  2. import sys
  3. import time
  4. import platform
  5. import getpass
  6. from collections import OrderedDict
  7. import re
  8. from lxml import etree
  9. import itertools
  10. import argparse
  11. from pprint import pprint
  12. fixed_size = {"UA_Boolean": 1, "UA_SByte": 1, "UA_Byte": 1, "UA_Int16": 2, "UA_UInt16": 2,
  13. "UA_Int32": 4, "UA_UInt32": 4, "UA_Int64": 8, "UA_UInt64": 8, "UA_Float": 4,
  14. "UA_Double": 8, "UA_DateTime": 8, "UA_Guid": 16, "UA_StatusCode": 4}
  15. zero_copy = ["UA_Boolean", "UA_SByte", "UA_Byte", "UA_Int16", "UA_UInt16", "UA_Int32", "UA_UInt32",
  16. "UA_Int64", "UA_UInt64", "UA_Float", "UA_Double", "UA_DateTime", "UA_StatusCode"]
  17. # The order of the builtin-types is not as in the standard. We put all the
  18. # fixed_size types in the front, so they can be distinguished by a simple geq
  19. # comparison. That's ok, since we use the type-index only internally!!
  20. builtin_types = ["UA_Boolean", "UA_SByte", "UA_Byte", "UA_Int16", "UA_UInt16",
  21. "UA_Int32", "UA_UInt32", "UA_Int64", "UA_UInt64", "UA_Float",
  22. "UA_Double", "UA_String", "UA_DateTime", "UA_Guid", "UA_ByteString",
  23. "UA_XmlElement", "UA_NodeId", "UA_ExpandedNodeId", "UA_StatusCode",
  24. "UA_QualifiedName", "UA_LocalizedText", "UA_ExtensionObject", "UA_DataValue",
  25. "UA_Variant", "UA_DiagnosticInfo"]
  26. excluded_types = ["UA_NodeIdType", "UA_InstanceNode", "UA_TypeNode", "UA_Node", "UA_ObjectNode",
  27. "UA_ObjectTypeNode", "UA_VariableNode", "UA_VariableTypeNode", "UA_ReferenceTypeNode",
  28. "UA_MethodNode", "UA_ViewNode", "UA_DataTypeNode", "UA_ServerDiagnosticsSummaryDataType",
  29. "UA_SamplingIntervalDiagnosticsDataType", "UA_SessionSecurityDiagnosticsDataType",
  30. "UA_SubscriptionDiagnosticsDataType", "UA_SessionDiagnosticsDataType"]
  31. minimal_types = ["InvalidType", "Node", "NodeClass", "ReferenceNode", "ApplicationDescription", "ApplicationType",
  32. "ChannelSecurityToken", "OpenSecureChannelRequest", "OpenSecureChannelResponse",
  33. "CloseSecureChannelRequest", "CloseSecureChannelResponse", "RequestHeader", "ResponseHeader",
  34. "SecurityTokenRequestType", "MessageSecurityMode", "CloseSessionResponse", "CloseSessionRquest",
  35. "ActivateSessionRequest", "ActivateSessionResponse", "SignatureData", "SignedSoftwareCertificate",
  36. "CreateSessionResponse", "CreateSessionRequest", "EndpointDescription", "UserTokenPolicy", "UserTokenType",
  37. "GetEndpointsRequest", "GetEndpointsResponse", "PublishRequest", "PublishResponse", "FindServersRequest", "FindServersResponse",
  38. "SetPublishingModeResponse", "SubscriptionAcknowledgement", "NotificationMessage", "ExtensionObject",
  39. "Structure", "ReadRequest", "ReadResponse", "ReadValueId", "TimestampsToReturn", "WriteRequest",
  40. "WriteResponse", "WriteValue", "SetPublishingModeRequest", "CreateMonitoredItemsResponse",
  41. "MonitoredItemCreateResult", "CreateMonitoredItemsRequest", "MonitoredItemCreateRequest",
  42. "MonitoringMode", "MonitoringParameters", "TranslateBrowsePathsToNodeIdsRequest",
  43. "TranslateBrowsePathsToNodeIdsResponse", "BrowsePath", "BrowsePathResult", "RelativePath",
  44. "BrowsePathTarget", "RelativePathElement", "CreateSubscriptionRequest", "CreateSubscriptionResponse",
  45. "BrowseResponse", "BrowseResult", "ReferenceDescription", "BrowseRequest", "ViewDescription",
  46. "BrowseNextRequest", "BrowseNextResponse", "DeleteSubscriptionsRequest", "DeleteSubscriptionsResponse",
  47. "BrowseDescription", "BrowseDirection", "CloseSessionRequest", "AddNodesRequest", "AddNodesResponse",
  48. "AddNodesItem", "AddNodesResult", "DeleteNodesItem","AddReferencesRequest", "AddReferencesResponse",
  49. "AddReferencesItem","DeleteReferencesItem", "VariableNode", "MethodNode", "VariableTypeNode",
  50. "ViewNode", "ReferenceTypeNode", "BrowseResultMask", "ServerState", "ServerStatusDataType", "BuildInfo",
  51. "ObjectNode", "DataTypeNode", "ObjectTypeNode", "IdType", "VariableAttributes", "ObjectAttributes",
  52. "NodeAttributes","ReferenceTypeAttributes", "ViewAttributes", "ObjectTypeAttributes",
  53. "NodeAttributesMask","DeleteNodesItem", "DeleteNodesRequest", "DeleteNodesResponse",
  54. "DeleteReferencesItem", "DeleteReferencesRequest", "DeleteReferencesResponse",
  55. "RegisterNodesRequest", "RegisterNodesResponse", "UnregisterNodesRequest", "UnregisterNodesResponse",
  56. "UserIdentityToken", "UserNameIdentityToken", "AnonymousIdentityToken" ];
  57. subscription_types = [ "DeleteMonitoredItemsRequest", "DeleteMonitoredItemsResponse", "NotificationMessage",
  58. "MonitoredItemNotification", "DataChangeNotification", "ModifySubscriptionRequest", "ModifySubscriptionResponse" ];
  59. class TypeDescription(object):
  60. def __init__(self, name, nodeid, namespaceid):
  61. self.name = name # without the UA_ prefix
  62. self.nodeid = nodeid
  63. self.namespaceid = namespaceid
  64. def parseTypeDescriptions(filename, namespaceid):
  65. definitions = {}
  66. f = open(filename[0])
  67. input_str = f.read()
  68. f.close()
  69. input_str = input_str.replace('\r','')
  70. rows = map(lambda x:tuple(x.split(',')), input_str.split('\n'))
  71. for index, row in enumerate(rows):
  72. if len(row) < 3:
  73. continue
  74. if row[2] != "DataType":
  75. continue
  76. if row[0] == "BaseDataType":
  77. definitions["UA_Variant"] = TypeDescription(row[0], row[1], namespaceid)
  78. elif row[0] == "Structure":
  79. definitions["UA_ExtensionObject"] = TypeDescription(row[0], row[1], namespaceid)
  80. else:
  81. definitions["UA_" + row[0]] = TypeDescription(row[0], row[1], namespaceid)
  82. return definitions
  83. class BuiltinType(object):
  84. "Generic type without members. Used for builtin types."
  85. def __init__(self, name, description = ""):
  86. self.name = name
  87. self.description = description
  88. def fixed_size(self):
  89. return self.name in fixed_size
  90. def mem_size(self):
  91. return fixed_size[self.name]
  92. def zero_copy(self):
  93. return self.name in zero_copy
  94. def typedef_c(self):
  95. pass
  96. def typelayout_c(self, namespace_0, description, outname):
  97. if description == None:
  98. typeid = "{.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = 0}, "
  99. else:
  100. typeid = "{.namespaceIndex = %s, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = %s}, " % \
  101. (description.namespaceid, description.nodeid)
  102. if self.name in ["UA_String", "UA_ByteString", "UA_XmlElement"]:
  103. return "{.typeId = " + typeid + \
  104. ".memSize = sizeof(" + self.name + "), " + \
  105. ".namespaceZero = UA_TRUE, .fixedSize = UA_FALSE, .zeroCopyable = UA_FALSE, " + \
  106. ".membersSize = 1,\n\t.members = {{.memberTypeIndex = UA_TYPES_BYTE, .namespaceZero = UA_TRUE, " + \
  107. ".padding = offsetof(UA_String, data) - sizeof(UA_Int32), .isArray = UA_TRUE }}, " + \
  108. ".typeIndex = %s }" % (outname.upper() + "_" + self.name[3:].upper())
  109. if self.name == "UA_QualifiedName":
  110. return "{.typeId = " + typeid + \
  111. ".memSize = sizeof(UA_QualifiedName), " + \
  112. ".namespaceZero = UA_TRUE, .fixedSize = UA_FALSE, .zeroCopyable = UA_FALSE, " + \
  113. ".membersSize = 2, .members = {" + \
  114. "\n\t{.memberTypeIndex = UA_TYPES_UINT16, .namespaceZero = UA_TRUE, " + \
  115. ".padding = 0, .isArray = UA_FALSE }," + \
  116. "\n\t{.memberTypeIndex = UA_TYPES_STRING, .namespaceZero = UA_TRUE, " + \
  117. ".padding = offsetof(UA_QualifiedName, name) - sizeof(UA_UInt16), .isArray = UA_FALSE }},\n" + \
  118. ".typeIndex = UA_TYPES_QUALIFIEDNAME }"
  119. return "{.typeId = " + typeid + \
  120. ".memSize = sizeof(" + self.name + "), " + \
  121. ".namespaceZero = UA_TRUE, " + \
  122. ".fixedSize = " + ("UA_TRUE" if self.fixed_size() else "UA_FALSE") + \
  123. ", .zeroCopyable = " + ("UA_TRUE" if self.zero_copy() else "UA_FALSE") + \
  124. ", .membersSize = 1,\n\t.members = {{.memberTypeIndex = UA_TYPES_" + self.name[3:].upper() + "," + \
  125. ".namespaceZero = UA_TRUE, .padding = 0, .isArray = UA_FALSE }}, " + \
  126. ".typeIndex = %s }" % (outname.upper() + "_" + self.name[3:].upper())
  127. class EnumerationType(object):
  128. def __init__(self, name, description = "", elements = OrderedDict()):
  129. self.name = name
  130. self.description = description
  131. self.elements = elements # maps a name to an integer value
  132. def append_enum(name, value):
  133. self.elements[name] = value
  134. def fixed_size(self):
  135. return True
  136. def mem_size(self):
  137. return 4
  138. def zero_copy(self):
  139. return True
  140. def typedef_c(self):
  141. if sys.version_info[0] < 3:
  142. values = self.elements.iteritems()
  143. else:
  144. values = self.elements.items()
  145. return "typedef enum { \n " + \
  146. ",\n ".join(map(lambda kv : kv[0].upper() + " = " + kv[1], values)) + \
  147. "\n} " + self.name + ";"
  148. def typelayout_c(self, namespace_0, description, outname):
  149. if description == None:
  150. typeid = "{.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = 0}, "
  151. else:
  152. typeid = "{.namespaceIndex = %s, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = %s}, " % (description.namespaceid, description.nodeid)
  153. return "{.typeId = " + typeid + \
  154. ".memSize = sizeof(" + self.name + "), " +\
  155. ".namespaceZero = UA_TRUE, " + \
  156. ".fixedSize = UA_TRUE, .zeroCopyable = UA_TRUE, " + \
  157. ".membersSize = 1,\n\t.members = {{.memberTypeIndex = UA_TYPES_INT32," + \
  158. ".namespaceZero = UA_TRUE, .padding = 0, .isArray = UA_FALSE }}, .typeIndex = UA_TYPES_INT32 }"
  159. def functions_c(self, typeTableName):
  160. return '''#define %s_new (%s*)UA_Int32_new
  161. #define %s_init(p) UA_Int32_init((UA_Int32*)p)
  162. #define %s_delete(p) UA_Int32_delete((UA_Int32*)p)
  163. #define %s_deleteMembers(p) UA_Int32_deleteMembers((UA_Int32*)p)
  164. #define %s_copy(src, dst) UA_Int32_copy((const UA_Int32*)src, (UA_Int32*)dst)
  165. #define %s_calcSizeBinary(p) UA_Int32_calcSizeBinary((UA_Int32*)p)
  166. #define %s_encodeBinary(src, dst, offset) UA_Int32_encodeBinary((UA_Int32*)src, dst, offset)
  167. #define %s_decodeBinary(src, offset, dst) UA_Int32_decodeBinary(src, offset, (UA_Int32*)dst)''' % tuple(itertools.repeat(self.name, 9))
  168. class OpaqueType(object):
  169. def __init__(self, name, description = ""):
  170. self.name = name
  171. self.description = description
  172. def fixed_size(self):
  173. return False
  174. def zero_copy(self):
  175. return False
  176. def typedef_c(self):
  177. return "typedef UA_ByteString " + self.name + ";"
  178. def typelayout_c(self, namespace_0, description, outname):
  179. if description == None:
  180. typeid = "{.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = 0}, "
  181. else:
  182. typeid = "{.namespaceIndex = %s, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = %s}, " % (description.namespaceid, description.nodeid)
  183. return "{.typeId = " + typeid + \
  184. ".memSize = sizeof(" + self.name + "), .fixedSize = UA_FALSE, .zeroCopyable = UA_FALSE, " + \
  185. ".namespaceZero = UA_TRUE, .membersSize = 1,\n\t.members = {{.memberTypeIndex = UA_TYPES_BYTESTRING," + \
  186. ".namespaceZero = UA_TRUE, .padding = 0, .isArray = UA_FALSE }}, .typeIndex = UA_TYPES_BYTESTRING }"
  187. def functions_c(self, typeTableName):
  188. return '''#define %s_new UA_ByteString_new
  189. #define %s_init UA_ByteString_init
  190. #define %s_delete UA_ByteString_delete
  191. #define %s_deleteMembers UA_ByteString_deleteMembers
  192. #define %s_copy UA_ByteString_copy
  193. #define %s_calcSizeBinary UA_ByteString_calcSizeBinary
  194. #define %s_encodeBinary UA_ByteString_encodeBinary
  195. #define %s_decodeBinary UA_ByteString_decodeBinary''' % tuple(itertools.repeat(self.name, 8))
  196. class StructMember(object):
  197. def __init__(self, name, memberType, isArray):
  198. self.name = name
  199. self.memberType = memberType
  200. self.isArray = isArray
  201. class StructType(object):
  202. def __init__(self, name, description, members = OrderedDict()):
  203. self.name = name
  204. self.description = description
  205. self.members = members # maps a name to a member definition
  206. def fixed_size(self):
  207. for m in self.members.values():
  208. if m.isArray or not m.memberType.fixed_size():
  209. return False
  210. return True
  211. def mem_size(self):
  212. total = 0
  213. for m in self.members.values():
  214. if m.isArray:
  215. raise Exception("Arrays have no fixed size!")
  216. else:
  217. total += m.memberType.mem_size()
  218. return total
  219. def zero_copy(self):
  220. for m in self.members.values():
  221. if m.isArray or not m.memberType.zero_copy():
  222. return False
  223. return True
  224. def typedef_c(self):
  225. if len(self.members) == 0:
  226. return "typedef void * " + self.name + ";"
  227. returnstr = "typedef struct {\n"
  228. if sys.version_info[0] < 3:
  229. values = self.members.iteritems()
  230. else:
  231. values = self.members.items()
  232. for name, member in values:
  233. if member.isArray:
  234. returnstr += " UA_Int32 " + name + "Size;\n"
  235. returnstr += " " + member.memberType.name + " *" +name + ";\n"
  236. else:
  237. returnstr += " " + member.memberType.name + " " +name + ";\n"
  238. return returnstr + "} " + self.name + ";"
  239. def typelayout_c(self, namespace_0, description, outname):
  240. if description == None:
  241. typeid = "{.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = 0}, "
  242. else:
  243. typeid = "{.namespaceIndex = %s, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = %s}, " % (description.namespaceid, description.nodeid)
  244. layout = "{.typeId = "+ typeid + \
  245. ".memSize = sizeof(" + self.name + "), "+ \
  246. ".namespaceZero = " + ("UA_TRUE" if namespace_0 else "UA_FALSE") + \
  247. ", .fixedSize = " + ("UA_TRUE" if self.fixed_size() else "UA_FALSE") + \
  248. ", .zeroCopyable = " + ("sizeof(" + self.name + ") == " + str(self.mem_size()) if self.zero_copy() \
  249. else "UA_FALSE") + \
  250. ", .typeIndex = " + outname.upper() + "_" + self.name[3:].upper() + \
  251. ", .membersSize = " + str(len(self.members)) + ","
  252. if len(self.members) > 0:
  253. layout += "\n\t.members={"
  254. for index, member in enumerate(self.members.values()):
  255. layout += "\n\t{" + \
  256. ".memberTypeIndex = " + ("UA_TYPES_" + member.memberType.name[3:].upper() if args.namespace_id == 0 or member.memberType.name in existing_types else \
  257. outname.upper() + "_" + member.memberType.name[3:].upper()) + ", " + \
  258. ".namespaceZero = "+ \
  259. ("UA_TRUE, " if args.namespace_id == 0 or member.memberType.name in existing_types else "UA_FALSE, ") + \
  260. ".padding = "
  261. before_endpos = "0"
  262. thispos = "offsetof(%s, %s)" % (self.name, member.name)
  263. if index > 0:
  264. if sys.version_info[0] < 3:
  265. before = self.members.values()[index-1]
  266. else:
  267. before = list(self.members.values())[index-1]
  268. before_endpos = "(offsetof(%s, %s)" % (self.name, before.name)
  269. if before.isArray:
  270. before_endpos += " + sizeof(void*))"
  271. else:
  272. before_endpos += " + sizeof(%s))" % before.memberType.name
  273. if member.isArray:
  274. # the first two bytes are padding for the length index, the last three for the pointer
  275. length_pos = "offsetof(%s, %sSize)" % (self.name, member.name)
  276. if index != 0:
  277. layout += "((%s - %s) << 3) + " % (length_pos, before_endpos)
  278. layout += "(%s - sizeof(UA_Int32) - %s)" % (thispos, length_pos)
  279. else:
  280. layout += "%s - %s" % (thispos, before_endpos)
  281. layout += ", .isArray = " + ("UA_TRUE" if member.isArray else "UA_FALSE") + " }, "
  282. layout += "}"
  283. return layout + "}"
  284. def functions_c(self, typeTableName):
  285. return '''#define %s_new() (%s*)UA_new(%s)
  286. #define %s_init(p) UA_init(p, %s)
  287. #define %s_delete(p) UA_delete(p, %s)
  288. #define %s_deleteMembers(p) UA_deleteMembers(p, %s)
  289. #define %s_copy(src, dst) UA_copy(src, dst, %s)
  290. #define %s_calcSizeBinary(p) UA_calcSizeBinary(p, %s)
  291. #define %s_encodeBinary(src, dst, offset) UA_encodeBinary(src, %s, dst, offset)
  292. #define %s_decodeBinary(src, offset, dst) UA_decodeBinary(src, offset, dst, %s)''' % \
  293. tuple([self.name] + list(itertools.chain(*itertools.repeat([self.name, "&"+typeTableName+"[" + typeTableName + "_" + self.name[3:].upper()+"]"], 8))))
  294. def parseTypeDefinitions(xmlDescription, existing_types = OrderedDict()):
  295. '''Returns an ordered dict that maps names to types. The order is such that
  296. every type depends only on known types. '''
  297. ns = {"opc": "http://opcfoundation.org/BinarySchema/"}
  298. tree = etree.parse(xmlDescription)
  299. typeSnippets = tree.xpath("/opc:TypeDictionary/*[not(self::opc:Import)]", namespaces=ns)
  300. types = OrderedDict(existing_types.items())
  301. # types we do not want to autogenerate
  302. def skipType(name):
  303. if name in builtin_types:
  304. return True
  305. if name in excluded_types:
  306. return True
  307. if outname == "ua_types" and not name[3:] in minimal_types:
  308. return True
  309. if "Test" in name: # skip all test types
  310. return True
  311. if re.search("NodeId$", name) != None:
  312. return True
  313. return False
  314. def stripTypename(tn):
  315. return tn[tn.find(":")+1:]
  316. def camlCase2CCase(item):
  317. "Member names begin with a lower case character"
  318. return item[:1].lower() + item[1:] if item else ''
  319. def typeReady(element):
  320. "Do we have the member types yet?"
  321. for child in element:
  322. if child.tag == "{http://opcfoundation.org/BinarySchema/}Field":
  323. if stripTypename(child.get("TypeName")) not in types:
  324. return False
  325. return True
  326. def parseEnumeration(typeXml):
  327. name = "UA_" + typeXml.get("Name")
  328. description = ""
  329. elements = OrderedDict()
  330. for child in typeXml:
  331. if child.tag == "{http://opcfoundation.org/BinarySchema/}Documentation":
  332. description = child.text
  333. if child.tag == "{http://opcfoundation.org/BinarySchema/}EnumeratedValue":
  334. elements[name + "_" + child.get("Name")] = child.get("Value")
  335. return EnumerationType(name, description, elements)
  336. def parseOpaque(typeXml):
  337. name = "UA_" + typeXml.get("Name")
  338. description = ""
  339. for child in typeXml:
  340. if child.tag == "{http://opcfoundation.org/BinarySchema/}Documentation":
  341. description = child.text
  342. return OpaqueType(name, description)
  343. def parseStructured(typeXml):
  344. "Returns None if we miss member descriptions"
  345. name = "UA_" + typeXml.get("Name")
  346. description = ""
  347. for child in typeXml:
  348. if child.tag == "{http://opcfoundation.org/BinarySchema/}Documentation":
  349. description = child.text
  350. # ignore lengthfields, just tag the array-members as an array
  351. lengthfields = []
  352. for child in typeXml:
  353. if child.get("LengthField"):
  354. lengthfields.append(child.get("LengthField"))
  355. members = OrderedDict()
  356. for child in typeXml:
  357. if not child.tag == "{http://opcfoundation.org/BinarySchema/}Field":
  358. continue
  359. if child.get("Name") in lengthfields:
  360. continue
  361. memberTypeName = "UA_" + stripTypename(child.get("TypeName"))
  362. if not memberTypeName in types:
  363. return None
  364. memberType = types[memberTypeName]
  365. memberName = camlCase2CCase(child.get("Name"))
  366. isArray = True if child.get("LengthField") else False
  367. members[memberName] = StructMember(memberName, memberType, isArray)
  368. return StructType(name, description, members)
  369. finished = False
  370. while(not finished):
  371. finished = True
  372. for typeXml in typeSnippets:
  373. name = "UA_" + typeXml.get("Name")
  374. if name in types or skipType(name):
  375. continue
  376. if typeXml.tag == "{http://opcfoundation.org/BinarySchema/}EnumeratedType":
  377. t = parseEnumeration(typeXml)
  378. types[t.name] = t
  379. elif typeXml.tag == "{http://opcfoundation.org/BinarySchema/}OpaqueType":
  380. t = parseOpaque(typeXml)
  381. types[t.name] = t
  382. elif typeXml.tag == "{http://opcfoundation.org/BinarySchema/}StructuredType":
  383. t = parseStructured(typeXml)
  384. if t == None:
  385. finished = False
  386. else:
  387. types[t.name] = t
  388. # remove the existing types
  389. for k in existing_types.keys():
  390. types.pop(k)
  391. return types
  392. parser = argparse.ArgumentParser()
  393. parser.add_argument('--ns0-types-xml', nargs=1, help='xml-definition of the ns0 types that are assumed to already exist')
  394. parser.add_argument('--enable-subscription-types', nargs=1, help='Generate datatypes necessary for Montoring and Subscriptions.')
  395. parser.add_argument('--typedescriptions', nargs=1, help='csv file with type descriptions')
  396. parser.add_argument('namespace_id', type=int, help='the id of the target namespace')
  397. parser.add_argument('types_xml', help='path/to/Opc.Ua.Types.bsd')
  398. parser.add_argument('outfile', help='output file w/o extension')
  399. args = parser.parse_args()
  400. outname = args.outfile.split("/")[-1]
  401. inname = args.types_xml.split("/")[-1]
  402. existing_types = OrderedDict()
  403. if args.enable_subscription_types:
  404. minimal_types = minimal_types + subscription_types
  405. if args.namespace_id == 0 or args.ns0_types_xml:
  406. existing_types = OrderedDict([(t, BuiltinType(t)) for t in builtin_types])
  407. if args.ns0_types_xml:
  408. if sys.version_info[0] < 3:
  409. OrderedDict(existing_types.items() + parseTypeDefinitions(args.ns0_types_xml[0], existing_types).items())
  410. else:
  411. OrderedDict(list(existing_types.items()) + list(parseTypeDefinitions(args.ns0_types_xml[0], existing_types).items()))
  412. types = parseTypeDefinitions(args.types_xml, existing_types)
  413. if args.namespace_id == 0:
  414. if sys.version_info[0] < 3:
  415. types = OrderedDict(existing_types.items() + types.items())
  416. else:
  417. types = OrderedDict(list(existing_types.items()) + list(types.items()))
  418. typedescriptions = {}
  419. if args.typedescriptions:
  420. typedescriptions = parseTypeDescriptions(args.typedescriptions, args.namespace_id)
  421. fh = open(args.outfile + "_generated.h",'w')
  422. fc = open(args.outfile + "_generated.c",'w')
  423. def printh(string):
  424. print(string, end='\n', file=fh)
  425. def printc(string):
  426. print(string, end='\n', file=fc)
  427. printh('''/**
  428. * @file ''' + outname + '''_generated.h
  429. *
  430. * @brief Autogenerated data types
  431. *
  432. * Generated from ''' + inname + ''' with script ''' + sys.argv[0] + '''
  433. * on host ''' + platform.uname()[1] + ''' by user ''' + getpass.getuser() + ''' at ''' + time.strftime("%Y-%m-%d %I:%M:%S") + '''
  434. */
  435. #ifndef ''' + outname.upper() + '''_GENERATED_H_
  436. #define ''' + outname.upper() + '''_GENERATED_H_
  437. #ifdef __cplusplus
  438. extern "C" {
  439. #endif
  440. #include "ua_types.h" '''
  441. + ('\n#include "ua_types_generated.h"\n' if args.namespace_id != 0 else '') + '''
  442. /**
  443. * @ingroup types
  444. *
  445. * @defgroup ''' + outname + '''_generated Autogenerated ''' + outname + ''' Types
  446. *
  447. * @brief Data structures that are autogenerated from an XML-Schema.
  448. *
  449. * @{
  450. */
  451. ''')
  452. printh("#define " + outname.upper() + "_COUNT %s\n" % (str(len(types))))
  453. printh("extern UA_EXPORT const UA_DataType *" + outname.upper() + ";\n")
  454. i = 0
  455. if sys.version_info[0] < 3:
  456. values = types.itervalues()
  457. else:
  458. values = types.values()
  459. for t in values:
  460. if type(t) != BuiltinType:
  461. printh("")
  462. if t.description != "":
  463. printh("/** @brief " + t.description + " */")
  464. printh(t.typedef_c())
  465. printh("#define " + outname.upper() + "_" + t.name[3:].upper() + " " + str(i))
  466. if type(t) != BuiltinType:
  467. printh(t.functions_c(outname.upper()))
  468. i += 1
  469. printh('''
  470. /// @} /* end of group */\n
  471. #ifdef __cplusplus
  472. } // extern "C"
  473. #endif\n
  474. #endif /* %s_GENERATED_H_ */''' % outname.upper())
  475. printc('''/**
  476. * @file ''' + outname + '''_generated.c
  477. *
  478. * @brief Autogenerated data types
  479. *
  480. * Generated from ''' + inname + ''' with script ''' + sys.argv[0] + '''
  481. * on host ''' + platform.uname()[1] + ''' by user ''' + getpass.getuser() + ''' at ''' + time.strftime("%Y-%m-%d %I:%M:%S") + '''
  482. */\n
  483. #include "stddef.h"
  484. #include "ua_types.h"
  485. #include "''' + outname + '''_generated.h"\n
  486. const UA_DataType *''' + outname.upper() + ''' = (UA_DataType[]){''')
  487. if sys.version_info[0] < 3:
  488. values = types.itervalues()
  489. else:
  490. values = types.values()
  491. for t in values:
  492. printc("")
  493. printc("/* " + t.name + " */")
  494. if args.typedescriptions:
  495. td = typedescriptions[t.name]
  496. else:
  497. td = None
  498. printc(t.typelayout_c(args.namespace_id == 0, td, outname) + ",")
  499. printc("};\n")
  500. # if args.typedescriptions:
  501. # printc('const UA_UInt32 *' + outname.upper() + '_IDS = (UA_UInt32[]){')
  502. # for t in types.itervalues():
  503. # print(str(typedescriptions[t.name].nodeid) + ", ", end='', file=fc)
  504. # printc("};")
  505. fh.close()
  506. fc.close()