generate_datatypes.py 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532
  1. # This Source Code Form is subject to the terms of the Mozilla Public
  2. # License, v. 2.0. If a copy of the MPL was not distributed with this
  3. # file, You can obtain one at http://mozilla.org/MPL/2.0/.
  4. from __future__ import print_function
  5. import sys
  6. import time
  7. import platform
  8. import getpass
  9. from collections import OrderedDict
  10. import re
  11. import xml.etree.ElementTree as etree
  12. import itertools
  13. import argparse
  14. types = OrderedDict() # contains types that were already parsed
  15. typedescriptions = {} # contains type nodeids
  16. excluded_types = ["NodeIdType", "InstanceNode", "TypeNode", "Node", "ObjectNode",
  17. "ObjectTypeNode", "VariableNode", "VariableTypeNode", "ReferenceTypeNode",
  18. "MethodNode", "ViewNode", "DataTypeNode",
  19. "UA_ServerDiagnosticsSummaryDataType", "UA_SamplingIntervalDiagnosticsDataType",
  20. "UA_SessionSecurityDiagnosticsDataType", "UA_SubscriptionDiagnosticsDataType",
  21. "UA_SessionDiagnosticsDataType"]
  22. builtin_types = ["Boolean", "SByte", "Byte", "Int16", "UInt16", "Int32", "UInt32",
  23. "Int64", "UInt64", "Float", "Double", "String", "DateTime", "Guid",
  24. "ByteString", "XmlElement", "NodeId", "ExpandedNodeId", "StatusCode",
  25. "QualifiedName", "LocalizedText", "ExtensionObject", "DataValue",
  26. "Variant", "DiagnosticInfo"]
  27. # If the type does not contain pointers, it can be copied with memcpy
  28. # (internally, not into the protocol message). This dict contains the sizes of
  29. # fixed-size types. Parsed types are added if they apply.
  30. builtin_fixed_size = ["Boolean", "SByte", "Byte", "Int16", "UInt16", "Int32", "UInt32",
  31. "Int64", "UInt64", "Float", "Double", "DateTime", "Guid", "StatusCode"]
  32. # Some types can be memcpy'd off the binary stream. That's especially important
  33. # for arrays. But we need to check if they contain padding and whether the
  34. # endianness is correct. This dict gives the C-statement that must be true for the
  35. # type to be overlayable. Parsed types are added if they apply.
  36. builtin_overlayable = {"Boolean": "true", "SByte": "true", "Byte": "true",
  37. "Int16": "UA_BINARY_OVERLAYABLE_INTEGER", "UInt16": "UA_BINARY_OVERLAYABLE_INTEGER",
  38. "Int32": "UA_BINARY_OVERLAYABLE_INTEGER", "UInt32": "UA_BINARY_OVERLAYABLE_INTEGER",
  39. "Int64": "UA_BINARY_OVERLAYABLE_INTEGER", "UInt64": "UA_BINARY_OVERLAYABLE_INTEGER",
  40. "Float": "UA_BINARY_OVERLAYABLE_FLOAT", "Double": "UA_BINARY_OVERLAYABLE_FLOAT",
  41. "DateTime": "UA_BINARY_OVERLAYABLE_INTEGER", "StatusCode": "UA_BINARY_OVERLAYABLE_INTEGER",
  42. "Guid": "(UA_BINARY_OVERLAYABLE_INTEGER && offsetof(UA_Guid, data2) == sizeof(UA_UInt32) && " + \
  43. "offsetof(UA_Guid, data3) == (sizeof(UA_UInt16) + sizeof(UA_UInt32)) && " + \
  44. "offsetof(UA_Guid, data4) == (2*sizeof(UA_UInt32)))"}
  45. ################
  46. # Type Classes #
  47. ################
  48. class StructMember(object):
  49. def __init__(self, name, memberType, isArray):
  50. self.name = name
  51. self.memberType = memberType
  52. self.isArray = isArray
  53. class Type(object):
  54. def __init__(self, outname, xml):
  55. self.name = xml.get("Name")
  56. self.ns0 = ("true" if outname == "ua_types" else "false")
  57. self.typeIndex = outname.upper() + "_" + self.name.upper()
  58. self.outname = outname
  59. self.description = ""
  60. self.fixed_size = "false"
  61. self.overlayable = "false"
  62. if self.name in builtin_types:
  63. self.builtin = "true"
  64. else:
  65. self.builtin = "false"
  66. self.members = [StructMember("", self, False)] # Returns one member: itself. Overwritten by some types.
  67. for child in xml:
  68. if child.tag == "{http://opcfoundation.org/BinarySchema/}Documentation":
  69. self.description = child.text
  70. break
  71. def datatype_c(self):
  72. xmlEncodingId = "0"
  73. binaryEncodingId = "0"
  74. if self.name in typedescriptions:
  75. description = typedescriptions[self.name]
  76. typeid = "{.namespaceIndex = %s, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = %s}" % (description.namespaceid, description.nodeid)
  77. xmlEncodingId = description.xmlEncodingId
  78. binaryEncodingId = description.binaryEncodingId
  79. else:
  80. typeid = "{.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = 0}"
  81. return "{ .typeId = " + typeid + \
  82. ",\n .typeIndex = " + self.typeIndex + \
  83. ",\n#ifdef UA_ENABLE_TYPENAMES\n .typeName = \"%s\",\n#endif\n" % self.name + \
  84. " .memSize = sizeof(UA_" + self.name + ")" + \
  85. ",\n .builtin = " + self.builtin + \
  86. ",\n .fixedSize = " + self.fixed_size + \
  87. ",\n .overlayable = " + self.overlayable + \
  88. ",\n .binaryEncodingId = " + binaryEncodingId + \
  89. ",\n .membersSize = " + str(len(self.members)) + \
  90. ",\n .members = %s_members" % self.name + " }"
  91. #",\n .xmlEncodingId = " + xmlEncodingId + \ Not used for now
  92. def members_c(self):
  93. if len(self.members)==0:
  94. return "#define %s_members NULL" % (self.name)
  95. members = "static UA_DataTypeMember %s_members[%s] = {" % (self.name, len(self.members))
  96. before = None
  97. for index, member in enumerate(self.members):
  98. m = "\n { .memberTypeIndex = %s_%s,\n" % (member.memberType.outname.upper(), member.memberType.name.upper())
  99. m += "#ifdef UA_ENABLE_TYPENAMES\n .memberName = \"%s\",\n#endif\n" % member.name
  100. m += " .namespaceZero = %s,\n" % member.memberType.ns0
  101. m += " .padding = "
  102. if not before:
  103. m += "0,\n"
  104. else:
  105. if member.isArray:
  106. m += "offsetof(UA_%s, %sSize)" % (self.name, member.name)
  107. else:
  108. m += "offsetof(UA_%s, %s)" % (self.name, member.name)
  109. m += " - offsetof(UA_%s, %s)" % (self.name, before.name)
  110. if before.isArray:
  111. m += " - sizeof(void*),\n"
  112. else:
  113. m += " - sizeof(UA_%s),\n" % before.memberType.name
  114. m += " .isArray = " + ("true" if member.isArray else "false")
  115. members += m + "\n },"
  116. before = member
  117. return members + "};"
  118. def datatype_ptr(self):
  119. return "&" + self.outname.upper() + "[" + self.outname.upper() + "_" + self.name.upper() + "]"
  120. def functions_c(self):
  121. funcs = "static UA_INLINE void\nUA_%s_init(UA_%s *p) {\n memset(p, 0, sizeof(UA_%s));\n}\n\n" % (self.name, self.name, self.name)
  122. funcs += "static UA_INLINE UA_%s *\nUA_%s_new(void) {\n return (UA_%s*)UA_new(%s);\n}\n\n" % (self.name, self.name, self.name, self.datatype_ptr())
  123. if self.fixed_size == "true":
  124. funcs += "static UA_INLINE UA_StatusCode\nUA_%s_copy(const UA_%s *src, UA_%s *dst) {\n *dst = *src;\n return UA_STATUSCODE_GOOD;\n}\n\n" % (self.name, self.name, self.name)
  125. funcs += "static UA_INLINE void\nUA_%s_deleteMembers(UA_%s *p) { }\n\n" % (self.name, self.name)
  126. else:
  127. funcs += "static UA_INLINE UA_StatusCode\nUA_%s_copy(const UA_%s *src, UA_%s *dst) {\n return UA_copy(src, dst, %s);\n}\n\n" % (self.name, self.name, self.name, self.datatype_ptr())
  128. funcs += "static UA_INLINE void\nUA_%s_deleteMembers(UA_%s *p) {\n UA_deleteMembers(p, %s);\n}\n\n" % (self.name, self.name, self.datatype_ptr())
  129. funcs += "static UA_INLINE void\nUA_%s_delete(UA_%s *p) {\n UA_delete(p, %s);\n}" % (self.name, self.name, self.datatype_ptr())
  130. return funcs
  131. def encoding_h(self):
  132. enc = "static UA_INLINE UA_StatusCode\nUA_%s_encodeBinary(const UA_%s *src, UA_ByteString *dst, size_t *offset) {\n return UA_encodeBinary(src, %s, NULL, NULL, dst, offset);\n}\n"
  133. enc += "static UA_INLINE UA_StatusCode\nUA_%s_decodeBinary(const UA_ByteString *src, size_t *offset, UA_%s *dst) {\n return UA_decodeBinary(src, offset, dst, %s);\n}"
  134. return enc % tuple(list(itertools.chain(*itertools.repeat([self.name, self.name, self.datatype_ptr()], 2))))
  135. class BuiltinType(Type):
  136. def __init__(self, name):
  137. self.name = name
  138. self.ns0 = "true"
  139. self.typeIndex = "UA_TYPES_" + self.name.upper()
  140. self.outname = "ua_types"
  141. self.description = ""
  142. self.fixed_size = "false"
  143. if self.name in builtin_fixed_size:
  144. self.fixed_size = "true"
  145. self.overlayable = "false"
  146. if name in builtin_overlayable:
  147. self.overlayable = builtin_overlayable[name]
  148. self.builtin = "true"
  149. if self.name == "QualifiedName":
  150. self.members = [StructMember("namespaceIndex", types["Int16"], False), StructMember("name", types["String"], False)]
  151. elif self.name in ["String", "ByteString", "XmlElement"]:
  152. self.members = [StructMember("", types["Byte"], True)]
  153. else:
  154. self.members = [StructMember("", self, False)]
  155. class EnumerationType(Type):
  156. def __init__(self, outname, xml):
  157. Type.__init__(self, outname, xml)
  158. self.fixed_size = "true"
  159. self.overlayable = "UA_BINARY_OVERLAYABLE_INTEGER"
  160. self.members = [StructMember("", types["Int32"], False)] # encoded as uint32
  161. self.builtin = "true"
  162. self.typeIndex = "UA_TYPES_INT32"
  163. self.elements = OrderedDict()
  164. for child in xml:
  165. if child.tag == "{http://opcfoundation.org/BinarySchema/}EnumeratedValue":
  166. self.elements[child.get("Name")] = child.get("Value")
  167. def typedef_h(self):
  168. if sys.version_info[0] < 3:
  169. values = self.elements.iteritems()
  170. else:
  171. values = self.elements.items()
  172. return "typedef enum {\n " + ",\n ".join(map(lambda kv : "UA_" + self.name.upper() + "_" + kv[0].upper() + \
  173. " = " + kv[1], values)) + \
  174. ",\n __UA_{0}_FORCE32BIT = 0x7fffffff\n".format(self.name.upper()) + "} " +\
  175. "UA_{0};\nUA_STATIC_ASSERT(sizeof(UA_{0}) == sizeof(UA_Int32), enum_must_be_32bit);".format(self.name)
  176. class OpaqueType(Type):
  177. def __init__(self, outname, xml):
  178. Type.__init__(self, outname, xml)
  179. self.members = [StructMember("", types["ByteString"], False)] # encoded as string
  180. def typedef_h(self):
  181. return "typedef UA_ByteString UA_%s;" % self.name
  182. class StructType(Type):
  183. def __init__(self, outname, xml):
  184. Type.__init__(self, outname, xml)
  185. self.members = []
  186. lengthfields = [] # lengthfields of arrays are not included as members
  187. for child in xml:
  188. if child.get("LengthField"):
  189. lengthfields.append(child.get("LengthField"))
  190. for child in xml:
  191. if not child.tag == "{http://opcfoundation.org/BinarySchema/}Field":
  192. continue
  193. if child.get("Name") in lengthfields:
  194. continue
  195. memberName = child.get("Name")
  196. memberName = memberName[:1].lower() + memberName[1:]
  197. memberTypeName = child.get("TypeName")
  198. memberType = types[memberTypeName[memberTypeName.find(":")+1:]]
  199. isArray = True if child.get("LengthField") else False
  200. self.members.append(StructMember(memberName, memberType, isArray))
  201. self.fixed_size = "true"
  202. self.overlayable = "true"
  203. before = None
  204. for m in self.members:
  205. if m.isArray or m.memberType.fixed_size != "true":
  206. self.fixed_size = "false"
  207. self.overlayable = "false"
  208. else:
  209. self.overlayable += " && " + m.memberType.overlayable
  210. if before:
  211. self.overlayable += " && offsetof(UA_%s, %s) == (offsetof(UA_%s, %s) + sizeof(UA_%s))" % \
  212. (self.name, m.name, self.name, before.name, before.memberType.name)
  213. if "false" in self.overlayable:
  214. self.overlayable = "false"
  215. before = m
  216. def typedef_h(self):
  217. if len(self.members) == 0:
  218. return "typedef void * UA_%s;" % self.name
  219. returnstr = "typedef struct {\n"
  220. for member in self.members:
  221. if member.isArray:
  222. returnstr += " size_t %sSize;\n" % member.name
  223. returnstr += " UA_%s *%s;\n" % (member.memberType.name, member.name)
  224. else:
  225. returnstr += " UA_%s %s;\n" % (member.memberType.name, member.name)
  226. return returnstr + "} UA_%s;" % self.name
  227. #########################
  228. # Parse Typedefinitions #
  229. #########################
  230. def parseTypeDefinitions(outname, xmlDescription):
  231. def typeReady(element):
  232. "Are all member types defined?"
  233. for child in element:
  234. if child.tag == "{http://opcfoundation.org/BinarySchema/}Field":
  235. childname = child.get("TypeName")
  236. if childname[childname.find(":")+1:] not in types:
  237. return False
  238. return True
  239. def skipType(name):
  240. if name in excluded_types:
  241. return True
  242. if "Test" in name: # skip all test types
  243. return True
  244. if re.search("NodeId$", name) != None:
  245. return True
  246. return False
  247. snippets = {}
  248. for typeXml in etree.parse(xmlDescription).getroot():
  249. if not typeXml.get("Name"):
  250. continue
  251. name = typeXml.get("Name")
  252. snippets[name] = typeXml
  253. while(len(snippets) > 0):
  254. for name, typeXml in list(snippets.items()):
  255. if name in types or skipType(name):
  256. del snippets[name]
  257. continue
  258. if not typeReady(typeXml):
  259. continue
  260. if name in builtin_types:
  261. types[name] = BuiltinType(name)
  262. elif typeXml.tag == "{http://opcfoundation.org/BinarySchema/}EnumeratedType":
  263. types[name] = EnumerationType(outname, typeXml)
  264. elif typeXml.tag == "{http://opcfoundation.org/BinarySchema/}OpaqueType":
  265. types[name] = OpaqueType(outname, typeXml)
  266. elif typeXml.tag == "{http://opcfoundation.org/BinarySchema/}StructuredType":
  267. types[name] = StructType(outname, typeXml)
  268. else:
  269. raise Exception("Type not known")
  270. del snippets[name]
  271. ##########################
  272. # Parse TypeDescriptions #
  273. ##########################
  274. class TypeDescription(object):
  275. def __init__(self, name, nodeid, namespaceid):
  276. self.name = name
  277. self.nodeid = nodeid
  278. self.namespaceid = namespaceid
  279. self.xmlEncodingId = "0"
  280. self.binaryEncodingId = "0"
  281. def parseTypeDescriptions(filename, namespaceid):
  282. definitions = {}
  283. with open(filename) as f:
  284. input_str = f.read()
  285. input_str = input_str.replace('\r','')
  286. rows = map(lambda x:tuple(x.split(',')), input_str.split('\n'))
  287. for index, row in enumerate(rows):
  288. if len(row) < 3:
  289. continue
  290. if row[2] == "Object":
  291. # Check if node name ends with _Encoding_(DefaultXml|DefaultBinary) and store the node id in the corresponding DataType
  292. m = re.match('(.*?)_Encoding_Default(Xml|Binary)$',row[0])
  293. if (m):
  294. baseType = m.group(1)
  295. if baseType not in types:
  296. continue
  297. if m.group(2) == "Xml":
  298. definitions[baseType].xmlEncodingId = row[1]
  299. else:
  300. definitions[baseType].binaryEncodingId = row[1]
  301. continue
  302. if row[2] != "DataType":
  303. continue
  304. if row[0] == "BaseDataType":
  305. definitions["Variant"] = TypeDescription(row[0], row[1], namespaceid)
  306. elif row[0] == "Structure":
  307. definitions["ExtensionObject"] = TypeDescription(row[0], row[1], namespaceid)
  308. elif row[0] not in types:
  309. continue
  310. elif type(types[row[0]]) == EnumerationType:
  311. definitions[row[0]] = TypeDescription(row[0], "6", namespaceid) # enumerations look like int32 on the wire
  312. else:
  313. definitions[row[0]] = TypeDescription(row[0], row[1], namespaceid)
  314. return definitions
  315. ###############################
  316. # Parse the Command Line Input#
  317. ###############################
  318. parser = argparse.ArgumentParser()
  319. parser.add_argument('--typedescriptions', help='csv file with type descriptions')
  320. parser.add_argument('--namespace', type=int, default=0, help='namespace id of the generated type nodeids (defaults to 0)')
  321. parser.add_argument('--selected_types', help='file with list of types (among those parsed) to be generated')
  322. parser.add_argument('typexml_ns0', help='path/to/Opc.Ua.Types.bsd ...')
  323. parser.add_argument('typexml_additional', nargs='*', help='path/to/Opc.Ua.Types.bsd ...')
  324. parser.add_argument('outfile', help='output file w/o extension')
  325. args = parser.parse_args()
  326. outname = args.outfile.split("/")[-1]
  327. inname = ', '.join([args.typexml_ns0.split("/")[-1]] + list(map(lambda x:x.split("/")[-1], args.typexml_additional)))
  328. ################
  329. # Create Types #
  330. ################
  331. for builtin in builtin_types:
  332. types[builtin] = BuiltinType(builtin)
  333. with open(args.typexml_ns0) as f:
  334. parseTypeDefinitions("ua_types", f)
  335. for typexml in args.typexml_additional:
  336. with open(typexml) as f:
  337. parseTypeDefinitions(outname, f)
  338. typedescriptions = {}
  339. if args.typedescriptions:
  340. typedescriptions = parseTypeDescriptions(args.typedescriptions, args.namespace)
  341. selected_types = types.keys()
  342. if args.selected_types:
  343. with open(args.selected_types) as f:
  344. selected_types = list(filter(len, [line.strip() for line in f]))
  345. #############################
  346. # Write out the Definitions #
  347. #############################
  348. fh = open(args.outfile + "_generated.h",'w')
  349. ff = open(args.outfile + "_generated_handling.h",'w')
  350. fe = open(args.outfile + "_generated_encoding_binary.h",'w')
  351. fc = open(args.outfile + "_generated.c",'w')
  352. def printh(string):
  353. print(string, end='\n', file=fh)
  354. def printf(string):
  355. print(string, end='\n', file=ff)
  356. def printe(string):
  357. print(string, end='\n', file=fe)
  358. def printc(string):
  359. print(string, end='\n', file=fc)
  360. def iter_types(v):
  361. l = None
  362. if sys.version_info[0] < 3:
  363. l = list(v.itervalues())
  364. else:
  365. l = list(v.values())
  366. return filter(lambda t: t.name in selected_types, l)
  367. ################
  368. # Print Header #
  369. ################
  370. printh('''/* Generated from ''' + inname + ''' with script ''' + sys.argv[0] + '''
  371. * on host ''' + platform.uname()[1] + ''' by user ''' + getpass.getuser() + \
  372. ''' at ''' + time.strftime("%Y-%m-%d %I:%M:%S") + ''' */
  373. #ifndef ''' + outname.upper() + '''_GENERATED_H_
  374. #define ''' + outname.upper() + '''_GENERATED_H_
  375. #ifdef __cplusplus
  376. extern "C" {
  377. #endif
  378. #include "ua_types.h"
  379. ''' + ('#include "ua_types_generated.h"\n' if outname != "ua_types" else ''))
  380. printh('''/**
  381. * Every type is assigned an index in an array containing the type descriptions.
  382. * These descriptions are used during type handling (copying, deletion,
  383. * binary encoding, ...). */''')
  384. printh("#define " + outname.upper() + "_COUNT %s" % (str(len(selected_types))))
  385. printh("extern UA_EXPORT const UA_DataType " + outname.upper() + "[" + outname.upper() + "_COUNT];")
  386. i = 0
  387. for t in iter_types(types):
  388. printh("\n/**\n * " + t.name)
  389. printh(" * " + "^" * len(t.name))
  390. if t.description == "":
  391. printh(" */")
  392. else:
  393. printh(" * " + t.description + " */")
  394. if type(t) != BuiltinType:
  395. printh(t.typedef_h() + "\n")
  396. printh("#define " + outname.upper() + "_" + t.name.upper() + " " + str(i))
  397. i += 1
  398. printh('''
  399. #ifdef __cplusplus
  400. } // extern "C"
  401. #endif\n
  402. #endif /* %s_GENERATED_H_ */''' % outname.upper())
  403. ##################
  404. # Print Handling #
  405. ##################
  406. printf('''/* Generated from ''' + inname + ''' with script ''' + sys.argv[0] + '''
  407. * on host ''' + platform.uname()[1] + ''' by user ''' + getpass.getuser() + \
  408. ''' at ''' + time.strftime("%Y-%m-%d %I:%M:%S") + ''' */
  409. #ifndef ''' + outname.upper() + '''_GENERATED_HANDLING_H_
  410. #define ''' + outname.upper() + '''_GENERATED_HANDLING_H_
  411. #ifdef __cplusplus
  412. extern "C" {
  413. #endif
  414. #include "''' + outname + '''_generated.h"
  415. #if defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 6
  416. # pragma GCC diagnostic push
  417. # pragma GCC diagnostic ignored "-Wmissing-field-initializers"
  418. # pragma GCC diagnostic ignored "-Wmissing-braces"
  419. #endif
  420. ''')
  421. for t in iter_types(types):
  422. printf("\n/* " + t.name + " */")
  423. printf(t.functions_c())
  424. printf('''
  425. #if defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 6
  426. # pragma GCC diagnostic pop
  427. #endif
  428. #ifdef __cplusplus
  429. } // extern "C"
  430. #endif\n
  431. #endif /* %s_GENERATED_HANDLING_H_ */''' % outname.upper())
  432. ###########################
  433. # Print Description Array #
  434. ###########################
  435. printc('''/* Generated from ''' + inname + ''' with script ''' + sys.argv[0] + '''
  436. * on host ''' + platform.uname()[1] + ''' by user ''' + getpass.getuser() + \
  437. ''' at ''' + time.strftime("%Y-%m-%d %I:%M:%S") + ''' */
  438. #include "''' + outname + '''_generated.h"''')
  439. for t in iter_types(types):
  440. printc("")
  441. printc("/* " + t.name + " */")
  442. printc(t.members_c())
  443. printc("const UA_DataType %s[%s_COUNT] = {" % (outname.upper(), outname.upper()))
  444. for t in iter_types(types):
  445. printc("")
  446. printc("/* " + t.name + " */")
  447. printc(t.datatype_c() + ",")
  448. printc("};\n")
  449. ##################
  450. # Print Encoding #
  451. ##################
  452. printe('''/* Generated from ''' + inname + ''' with script ''' + sys.argv[0] + '''
  453. * on host ''' + platform.uname()[1] + ''' by user ''' + getpass.getuser() + \
  454. ''' at ''' + time.strftime("%Y-%m-%d %I:%M:%S") + ''' */
  455. #include "ua_types_encoding_binary.h"
  456. #include "''' + outname + '''_generated.h"''')
  457. for t in iter_types(types):
  458. printe("\n/* " + t.name + " */")
  459. printe(t.encoding_h())
  460. fh.close()
  461. ff.close()
  462. fc.close()
  463. fe.close()