generate_namespace.py 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. from __future__ import print_function
  2. import inspect
  3. import sys
  4. import platform
  5. import getpass
  6. import time
  7. import re
  8. import argparse
  9. parser = argparse.ArgumentParser()
  10. parser.add_argument('--with-xml', action='store_true', help='generate xml encoding')
  11. parser.add_argument('--with-json', action='store_true', help='generate json encoding')
  12. parser.add_argument('--only-needed', action='store_true', help='generate only types needed for compile')
  13. parser.add_argument('nodeids', help='path/to/NodeIds.csv')
  14. parser.add_argument('outfile', help='outfile w/o extension')
  15. args = parser.parse_args()
  16. # whitelist for "only needed" profile
  17. from type_lists import only_needed_types
  18. # types that are to be excluded
  19. exclude_kinds = set(["Object","ObjectType","Variable","Method","ReferenceType"])
  20. exclude_types = set(["Number", "Integer", "UInteger", "Enumeration", "Image", "ImageBMP",
  21. "ImageGIF", "ImageJPG", "ImagePNG", "References", "BaseVariableType",
  22. "BaseDataVariableType", "PropertyType", "DataTypeDescriptionType",
  23. "DataTypeDictionaryType", "NamingRuleType", "IntegerId", "Counter",
  24. "Duration", "NumericRange", "Time", "Date", "UtcTime", "LocaleId",
  25. "UserTokenType", "ApplicationType", "ApplicationInstanceCertificate",
  26. "ServerVendorCapabilityType", "ServerStatusType",
  27. "ServerDiagnosticsSummaryType", "SamplingIntervalDiagnosticsArrayType",
  28. "SamplingIntervalDiagnosticsType", "SubscriptionDiagnosticsArrayType",
  29. "SubscriptionDiagnosticsType", "SessionDiagnosticsArrayType",
  30. "SessionDiagnosticsVariableType", "SessionSecurityDiagnosticsArrayType",
  31. "SessionSecurityDiagnosticsType", "DataItemType", "AnalogItemType",
  32. "DiscreteItemType", "TwoStateDiscreteType", "MultiStateDiscreteType",
  33. "ProgramDiagnosticType", "StateVariableType", "FiniteStateVariableType",
  34. "TransitionVariableType", "FiniteTransitionVariableType", "BuildInfoType",
  35. "TwoStateVariableType", "ConditionVariableType",
  36. "MultiStateValueDiscreteType", "OptionSetType", "ArrayItemType",
  37. "YArrayItemType", "XYArrayItemType", "ImageItemType", "CubeItemType",
  38. "NDimensionArrayItemType"])
  39. fixed_size = ['UA_DeadbandType', 'UA_DataChangeTrigger', 'UA_Guid', 'UA_ApplicationType',
  40. 'UA_ComplexNumberType', 'UA_EnumeratedTestType', 'UA_BrowseResultMask',
  41. 'UA_TimeZoneDataType', 'UA_NodeClass', 'UA_IdType', 'UA_ServiceCounterDataType',
  42. 'UA_Float', 'UA_ModelChangeStructureVerbMask', 'UA_EndpointConfiguration',
  43. 'UA_NodeAttributesMask', 'UA_DataChangeFilter', 'UA_StatusCode',
  44. 'UA_MonitoringFilterResult', 'UA_OpenFileMode', 'UA_SecurityTokenRequestType',
  45. 'UA_ServerDiagnosticsSummaryDataType', 'UA_ElementOperand',
  46. 'UA_AggregateConfiguration', 'UA_UInt64', 'UA_FilterOperator',
  47. 'UA_ReadRawModifiedDetails', 'UA_ServerState', 'UA_FilterOperand',
  48. 'UA_SubscriptionAcknowledgement', 'UA_AttributeWriteMask', 'UA_SByte', 'UA_Int32',
  49. 'UA_Range', 'UA_Byte', 'UA_TimestampsToReturn', 'UA_UserTokenType', 'UA_Int16',
  50. 'UA_XVType', 'UA_AggregateFilterResult', 'UA_Boolean', 'UA_MessageSecurityMode',
  51. 'UA_AxisScaleEnumeration', 'UA_PerformUpdateType', 'UA_UInt16',
  52. 'UA_NotificationData', 'UA_DoubleComplexNumberType', 'UA_HistoryUpdateType',
  53. 'UA_MonitoringFilter', 'UA_NodeIdType', 'UA_BrowseDirection',
  54. 'UA_SamplingIntervalDiagnosticsDataType', 'UA_UInt32', 'UA_ChannelSecurityToken',
  55. 'UA_RedundancySupport', 'UA_MonitoringMode', 'UA_HistoryReadDetails',
  56. 'UA_ExceptionDeviationFormat', 'UA_ComplianceLevel', 'UA_DateTime', 'UA_Int64',
  57. 'UA_Double']
  58. def skipType(row):
  59. if row[0] == "" or row[0] in exclude_types or row[2] in exclude_kinds:
  60. return True
  61. if "Test" in row[0]:
  62. return True
  63. if args.only_needed and not(row[0] in only_needed_types):
  64. return True
  65. return False
  66. f = open(args.nodeids)
  67. input_str = f.read() + "\nInvalidType,0,DataType"
  68. input_str = input_str.replace('\r','')
  69. rows = map(lambda x:tuple(x.split(',')), input_str.split('\n'))
  70. f.close()
  71. fh = open(args.outfile + ".h",'w')
  72. fc = open(args.outfile + ".c",'w')
  73. def printh(string):
  74. print(string % inspect.currentframe().f_back.f_locals, end='\n', file=fh)
  75. def printc(string):
  76. print(string % inspect.currentframe().f_back.f_locals, end='\n', file=fc)
  77. printh('''/**********************************************************
  78. * '''+args.outfile+'''.hgen -- do not modify
  79. **********************************************************
  80. * Generated from '''+args.nodeids+''' with script '''+sys.argv[0]+'''
  81. * on host '''+platform.uname()[1]+''' by user '''+getpass.getuser()+''' at '''+
  82. time.strftime("%Y-%m-%d %I:%M:%S")+'''
  83. **********************************************************/\n
  84. #ifndef ''' + args.outfile.upper().split("/")[-1] + '''_H_
  85. #define ''' + args.outfile.upper().split("/")[-1] + '''_H_\n
  86. #include "ua_types.h" // definition of UA_VTable and basic UA_Types
  87. #include "ua_types_generated.h"\n
  88. /**
  89. * @brief maps namespace zero nodeId to index into UA_VTable
  90. *
  91. * @param[in] id The namespace zero nodeId
  92. *
  93. * @retval UA_ERR_INVALID_VALUE whenever ns0Id could not be mapped
  94. * @retval the corresponding index into UA_VTable
  95. */
  96. UA_Int32 UA_ns0ToVTableIndex(const UA_NodeId *id);\n
  97. extern const UA_VTable_Entry UA_EXPORT *UA_TYPES;
  98. extern const UA_NodeId UA_EXPORT *UA_NODEIDS;
  99. /** The entries of UA_TYPES can be accessed with the following indices */ ''')
  100. printc('''/**********************************************************
  101. * '''+args.outfile.split("/")[-1]+'''.cgen -- do not modify
  102. **********************************************************
  103. * Generated from '''+args.nodeids+''' with script '''+sys.argv[0]+'''
  104. * on host '''+platform.uname()[1]+''' by user '''+getpass.getuser() +
  105. ''' at '''+ time.strftime("%Y-%m-%d %I:%M:%S")+'''
  106. **********************************************************/\n
  107. #include "''' + args.outfile.split("/")[-1] + '''.h"\n
  108. #include "ua_util.h"
  109. UA_Int32 UA_ns0ToVTableIndex(const UA_NodeId *id) {
  110. UA_Int32 retval = 0; // InvalidType
  111. if(id->namespaceIndex != 0) return retval;
  112. switch (id->identifier.numeric) {''')
  113. i = 0
  114. for row in rows:
  115. if skipType(row):
  116. continue
  117. if row[0] == "BaseDataType":
  118. name = "UA_Variant"
  119. elif row[0] == "Structure":
  120. name = "UA_ExtensionObject"
  121. else:
  122. name = "UA_" + row[0]
  123. printh("#define "+name.upper()+" "+str(i))
  124. printc('\tcase '+row[1]+': retval='+name.upper()+'; break; //'+row[2])
  125. i = i+1
  126. printh('\n#define SIZE_UA_VTABLE '+str(i));
  127. printh("") # newline
  128. printh("/** In UA_NODEIDS are the nodeids of the types, referencetypes and objects */")
  129. # assign indices to the reference types afterwards
  130. for row in rows:
  131. if row[0] == "" or (row[2] != "ReferenceType" and (row[2] != "Object" or "_Encoding_Default" in row[0])):
  132. continue
  133. name = "UA_" + row[0]
  134. printh("#define "+name.upper()+" "+str(i))
  135. i=i+1
  136. printc('''\n}\nreturn retval;\n}\n''');
  137. printh("") # newline
  138. printh("/** These are the actual (numeric) nodeids of the types, not the indices to the vtable */")
  139. printc('''const UA_VTable_Entry *UA_TYPES = (UA_VTable_Entry[]){''')
  140. for row in rows:
  141. if skipType(row):
  142. continue
  143. if row[0] == "BaseDataType":
  144. name = "UA_Variant"
  145. elif row[0] == "Structure":
  146. name = "UA_ExtensionObject"
  147. else:
  148. name = "UA_" + row[0]
  149. printh('#define '+name.upper()+'_NS0 '+row[1])
  150. printc("\t{.typeId={.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric=" + row[1] + "}" +
  151. ",\n.name=(UA_Byte*)&\"%(name)s\"" +
  152. ",\n.new=(void *(*)())%(name)s_new" +
  153. ",\n.init=(void(*)(void *))%(name)s_init"+
  154. ",\n.copy=(UA_Int32(*)(void const * ,void*))%(name)s_copy" +
  155. ",\n.delete=(void(*)(void *))%(name)s_delete" +
  156. ",\n.deleteMembers=(void(*)(void *))%(name)s_deleteMembers" +
  157. ",\n#ifdef DEBUG //FIXME: seems to be okay atm, however a pointer to a noop function would be more safe" +
  158. "\n.print=(void(*)(const void *, FILE *))%(name)s_print," +
  159. "\n#endif" +
  160. "\n.memSize=" + ("sizeof(%(name)s)" if (name != "UA_InvalidType") else "0") +
  161. ",\n.dynMembers=" + ("UA_FALSE" if (name in fixed_size) else "UA_TRUE") +
  162. ",\n.encodings={{.calcSize=(UA_Int32(*)(const void*))%(name)s_calcSizeBinary" +
  163. ",\n.encode=(UA_Int32(*)(const void*,UA_ByteString*,UA_UInt32*))%(name)s_encodeBinary" +
  164. ",\n.decode=(UA_Int32(*)(const UA_ByteString*,UA_UInt32*,void*))%(name)s_decodeBinary}" +
  165. (",\n{.calcSize=(UA_Int32(*)(const void*))%(name)s_calcSizeXml" +
  166. ",\n.encode=(UA_Int32(*)(const void*,UA_ByteString*,UA_UInt32*))%(name)s_encodeXml" +
  167. ",\n.decode=(UA_Int32(*)(const UA_ByteString*,UA_UInt32*,void*))%(name)s_decodeXml}" if (args.with_xml) else "") +
  168. "}},")
  169. printc('};')
  170. # make the nodeids available as well
  171. printc('''const UA_NodeId *UA_NODEIDS = (UA_NodeId[]){''')
  172. for row in rows:
  173. if skipType(row):
  174. continue
  175. if row[0] == "BaseDataType":
  176. name = "UA_Variant"
  177. elif row[0] == "Structure":
  178. name = "UA_ExtensionObject"
  179. else:
  180. name = "UA_" + row[0]
  181. printc("\t{.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = " + row[1] + "},")
  182. for row in rows:
  183. if row[0] == "" or (row[2] != "ReferenceType" and (row[2] != "Object" or "_Encoding_Default" in row[0])):
  184. continue
  185. printc("\t{.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = " + row[1] + "},")
  186. printc('};')
  187. printh('\n#endif /* OPCUA_NAMESPACE_0_H_ */')
  188. fh.close()
  189. fc.close()