Browse Source

optionally add the type and (struct) member names to the type descriptions

this is useful to show the definition of a type at runtime. and to forward the type definitions to scriptiong languages
Julius Pfrommer 9 years ago
parent
commit
bf8565bb8c
4 changed files with 38 additions and 14 deletions
  1. 14 6
      CMakeLists.txt
  2. 1 0
      include/ua_config.h.in
  3. 6 0
      include/ua_types.h
  4. 17 8
      tools/generate_datatypes.py

+ 14 - 6
CMakeLists.txt

@@ -134,6 +134,14 @@ set(lib_sources ${PROJECT_SOURCE_DIR}/src/ua_types.c
 ## generate code from xml definitions
 file(MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/src_generated")
 
+option(ENABLE_TYPEINTROSPECTION "Add the type and member names to the internal structures" OFF)
+mark_as_advanced(ENABLE_TYPEINTROSPECTION)
+if(ENABLE_TYPEINTROSPECTION)
+  set(generate_typeintrospection "--typeintrospection")
+else()
+  set(generate_typeintrospection "")
+endif()
+
 option(ENABLE_SUBSCRIPTIONS "Enable compilation of subscription and monitoring support." OFF)
 if(ENABLE_SUBSCRIPTIONS)
   set(ENABLE_SUBSCRIPTIONS ON) #to propagate it to the config file
@@ -149,7 +157,7 @@ if(ENABLE_SUBSCRIPTIONS)
                             ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated.h
                             ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated_encoding_binary.h
                      PRE_BUILD
-                     COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/generate_datatypes.py --enable-subscription-types=1 --typedescriptions ${PROJECT_SOURCE_DIR}/tools/schema/NodeIds.csv 0 ${PROJECT_SOURCE_DIR}/tools/schema/Opc.Ua.Types.bsd ${PROJECT_BINARY_DIR}/src_generated/ua_types
+                     COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/generate_datatypes.py --enable-subscription-types=1 ${generate_typeintrospection} --typedescriptions ${PROJECT_SOURCE_DIR}/tools/schema/NodeIds.csv 0 ${PROJECT_SOURCE_DIR}/tools/schema/Opc.Ua.Types.bsd ${PROJECT_BINARY_DIR}/src_generated/ua_types
                      DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/generate_datatypes.py
                              ${CMAKE_CURRENT_SOURCE_DIR}/tools/schema/Opc.Ua.Types.bsd
                              ${CMAKE_CURRENT_SOURCE_DIR}/tools/schema/NodeIds.csv)
@@ -158,7 +166,7 @@ add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated
                           ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated.h
                           ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated_encoding_binary.h
                    PRE_BUILD
-                   COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/generate_datatypes.py --typedescriptions ${PROJECT_SOURCE_DIR}/tools/schema/NodeIds.csv 0 ${PROJECT_SOURCE_DIR}/tools/schema/Opc.Ua.Types.bsd ${PROJECT_BINARY_DIR}/src_generated/ua_types
+                   COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/generate_datatypes.py ${generate_typeintrospection} --typedescriptions ${PROJECT_SOURCE_DIR}/tools/schema/NodeIds.csv 0 ${PROJECT_SOURCE_DIR}/tools/schema/Opc.Ua.Types.bsd ${PROJECT_BINARY_DIR}/src_generated/ua_types
                    DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/generate_datatypes.py
                            ${CMAKE_CURRENT_SOURCE_DIR}/tools/schema/Opc.Ua.Types.bsd
                            ${CMAKE_CURRENT_SOURCE_DIR}/tools/schema/NodeIds.csv)
@@ -168,7 +176,7 @@ add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/ua_transport_gener
                           ${PROJECT_BINARY_DIR}/src_generated/ua_transport_generated.h
                           ${PROJECT_BINARY_DIR}/src_generated/ua_transport_generated_encoding_binary.h
                    PRE_BUILD
-                   COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/generate_datatypes.py --ns0-types-xml ${PROJECT_SOURCE_DIR}/tools/schema/Opc.Ua.Types.bsd 1 ${PROJECT_SOURCE_DIR}/tools/schema/Custom.Opc.Ua.Transport.bsd ${PROJECT_BINARY_DIR}/src_generated/ua_transport
+                   COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/generate_datatypes.py ${generate_typeintrospection} --ns0-types-xml ${PROJECT_SOURCE_DIR}/tools/schema/Opc.Ua.Types.bsd 1 ${PROJECT_SOURCE_DIR}/tools/schema/Custom.Opc.Ua.Transport.bsd ${PROJECT_BINARY_DIR}/src_generated/ua_transport
                    DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/generate_datatypes.py
                            ${CMAKE_CURRENT_SOURCE_DIR}/tools/schema/Custom.Opc.Ua.Transport.bsd)
 
@@ -247,8 +255,8 @@ if(EXTENSION_UDP)
   endif()
 endif()
 
-option(LEGACY "Enable LEGACY code" OFF)
-mark_as_advanced(LEGACY)
+option(ENABLE_LEGACY "Enable LEGACY code" OFF)
+mark_as_advanced(ENABLE_LEGACY)
 
 option(EXTENSION_STATELESS "Enable stateless extension" OFF)
 if(EXTENSION_STATELESS)
@@ -370,7 +378,7 @@ if(BUILD_EXAMPLECLIENT)
             target_link_libraries(client_stateless urcu-cds urcu urcu-common pthread)
         endif()
     endif()
-    if(LEGACY AND NOT ENABLE_AMALGAMATION)
+    if(ENABLE_LEGACY AND NOT ENABLE_AMALGAMATION)
     	add_executable(client_legacy ${PROJECT_SOURCE_DIR}/examples/client_legacy.c $<TARGET_OBJECTS:open62541-object>)
 		target_link_libraries(client_legacy ${LIBS})
 	endif()

+ 1 - 0
include/ua_config.h.in

@@ -9,6 +9,7 @@
 #cmakedefine UA_MULTITHREADING
 #cmakedefine ENABLE_METHODCALLS
 #cmakedefine ENABLE_SUBSCRIPTIONS
+#cmakedefine ENABLE_TYPEINTROSPECTION
 
 /* Function Export */
 #ifdef _WIN32

+ 6 - 0
include/ua_types.h

@@ -562,6 +562,9 @@ UA_StatusCode UA_EXPORT UA_DiagnosticInfo_copy(const UA_DiagnosticInfo *src, UA_
 #define UA_IS_BUILTIN(ID) (ID <= UA_TYPES_DIAGNOSTICINFO)
 
 typedef struct {
+#ifdef ENABLE_TYPEINTROSPECTION
+    const char *memberName;
+#endif
     UA_UInt16 memberTypeIndex; ///< Index of the member in the datatypetable
     UA_Byte padding; /**< How much padding is there before this member element? For arrays this is
                           split into 2 bytes padding before the length index (max 4 bytes) and 3
@@ -573,6 +576,9 @@ typedef struct {
 } UA_DataTypeMember;
     
 struct UA_DataType {
+#ifdef ENABLE_TYPEINTROSPECTION
+    const char *typeName;
+#endif
     UA_NodeId typeId; ///< The nodeid of the type
     UA_UInt16 memSize; ///< Size of the struct in memory
     UA_UInt16 typeIndex; ///< Index of the type in the datatypetable

+ 17 - 8
tools/generate_datatypes.py

@@ -39,9 +39,9 @@ minimal_types = ["InvalidType", "Node", "NodeClass", "ReferenceNode", "Applicati
                  "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",
+                 "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",
@@ -116,30 +116,34 @@ class BuiltinType(object):
             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 "{.typeId = " + typeid + \
+            return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
                 ".memSize = sizeof(" + self.name + "), " + \
                 ".namespaceZero = UA_TRUE, .fixedSize = UA_FALSE, .zeroCopyable = UA_FALSE, " + \
                 ".membersSize = 1,\n\t.members = {{.memberTypeIndex = UA_TYPES_BYTE, .namespaceZero = UA_TRUE, " + \
+                (".memberName = (char*)0, " if typeintrospection else "") + \
                 ".padding = offsetof(UA_String, data) - sizeof(UA_Int32), .isArray = UA_TRUE }}, " + \
                 ".typeIndex = %s }" % (outname.upper() + "_" + self.name[3:].upper())
 
         if self.name == "UA_QualifiedName":
-            return "{.typeId = " + typeid + \
+            return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
                 ".memSize = sizeof(UA_QualifiedName), " + \
                 ".namespaceZero = UA_TRUE, .fixedSize = UA_FALSE, .zeroCopyable = UA_FALSE, " + \
                 ".membersSize = 2, .members = {" + \
                 "\n\t{.memberTypeIndex = UA_TYPES_UINT16, .namespaceZero = UA_TRUE, " + \
+                (".memberName = (char*)0, " if typeintrospection else "") + \
                 ".padding = 0, .isArray = UA_FALSE }," + \
                 "\n\t{.memberTypeIndex = UA_TYPES_STRING, .namespaceZero = UA_TRUE, " + \
+                (".memberName = (char*)0, " if typeintrospection else "") + \
                 ".padding = offsetof(UA_QualifiedName, name) - sizeof(UA_UInt16), .isArray = UA_FALSE }},\n" + \
                 ".typeIndex = UA_TYPES_QUALIFIEDNAME }"
                 
-        return "{.typeId = " + typeid + \
+        return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
             ".memSize = sizeof(" + self.name + "), " + \
             ".namespaceZero = UA_TRUE, " + \
             ".fixedSize = " + ("UA_TRUE" if self.fixed_size() else "UA_FALSE") + \
             ", .zeroCopyable = " + ("UA_TRUE" if self.zero_copy() else "UA_FALSE") + \
             ", .membersSize = 1,\n\t.members = {{.memberTypeIndex = UA_TYPES_" + self.name[3:].upper() + "," + \
+            (".memberName = (char*)0, " if typeintrospection else "") + \
             ".namespaceZero = UA_TRUE, .padding = 0, .isArray = UA_FALSE }}, " + \
             ".typeIndex = %s }" % (outname.upper() + "_" + self.name[3:].upper())
 
@@ -180,6 +184,7 @@ class EnumerationType(object):
             ".namespaceZero = UA_TRUE, " + \
             ".fixedSize = UA_TRUE, .zeroCopyable = UA_TRUE, " + \
             ".membersSize = 1,\n\t.members = {{.memberTypeIndex = UA_TYPES_INT32," + \
+            (".memberName = (char*)0, " if typeintrospection else "") + \
             ".namespaceZero = UA_TRUE, .padding = 0, .isArray = UA_FALSE }}, .typeIndex = UA_TYPES_INT32 }"
 
     def functions_c(self, typeTableName):
@@ -212,9 +217,10 @@ class OpaqueType(object):
             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 "{.typeId = " + typeid + \
+        return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
             ".memSize = sizeof(" + self.name + "), .fixedSize = UA_FALSE, .zeroCopyable = UA_FALSE, " + \
             ".namespaceZero = UA_TRUE, .membersSize = 1,\n\t.members = {{.memberTypeIndex = UA_TYPES_BYTESTRING," + \
+            (".memberName = (char*)0, " if typeintrospection else "") + \
             ".namespaceZero = UA_TRUE, .padding = 0, .isArray = UA_FALSE }}, .typeIndex = UA_TYPES_BYTESTRING }"
 
     def functions_c(self, typeTableName):
@@ -282,7 +288,7 @@ class StructType(object):
             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 = "{.typeId = "+ typeid + \
+        layout = (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
                  ".memSize = sizeof(" + self.name + "), "+ \
                  ".namespaceZero = " + ("UA_TRUE" if namespace_0 else "UA_FALSE") + \
                  ", .fixedSize = " + ("UA_TRUE" if self.fixed_size() else "UA_FALSE") + \
@@ -294,6 +300,7 @@ class StructType(object):
             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 = "+ \
@@ -451,6 +458,7 @@ 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')
@@ -458,6 +466,7 @@ 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