Forráskód Böngészése

enable statuscode descriptions by default; split functionality across
less files

Julius Pfrommer 8 éve
szülő
commit
6529137c26

+ 12 - 15
CMakeLists.txt

@@ -48,7 +48,6 @@ option(UA_ENABLE_MULTITHREADING "Enable multithreading" OFF)
 option(UA_ENABLE_AMALGAMATION "Concatenate the library to a single file open62541.h/.c" OFF)
 option(UA_ENABLE_COVERAGE "Enable gcov coverage" OFF)
 option(BUILD_SHARED_LIBS "Enable building of shared libraries (dll/so)" OFF)
-option(UA_ENABLE_STATUSCODE_MSG "Enable conversion of StatusCode to human-readable error message" OFF)
 
 if(UA_ENABLE_COVERAGE)
   set(CMAKE_BUILD_TYPE DEBUG)
@@ -58,7 +57,10 @@ if(UA_ENABLE_COVERAGE)
 endif()
 
 # Advanced options
-option(UA_ENABLE_TYPENAMES "Add the type and member names to the UA_DataType structure" OFF)
+option(UA_ENABLE_STATUSCODE_DESCRIPTIONS "Enable conversion of StatusCode to human-readable error message" ON)
+mark_as_advanced(UA_ENABLE_STATUSCODE_DESCRIPTIONS)
+
+option(UA_ENABLE_TYPENAMES "Add the type and member names to the UA_DataType structure" ON)
 mark_as_advanced(UA_ENABLE_TYPENAMES)
 
 option(UA_ENABLE_EMBEDDED_LIBC "Use a custom implementation of some libc functions that might be missing on embedded targets (e.g. string handling)." OFF)
@@ -295,19 +297,14 @@ add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/ua_nodeids.h
                    DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/generate_nodeids.py
                            ${CMAKE_CURRENT_SOURCE_DIR}/tools/schema/NodeIds.csv)
 
-if(UA_ENABLE_STATUSCODE_MSG)
-    # StatusCode to String
-    add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/ua_statuscode_msg_table.c
-            PRE_BUILD
-            COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/generate_statuscode_msg.py
-            ${PROJECT_SOURCE_DIR}/tools/schema/Opc.Ua.StatusCodes.csv ${PROJECT_BINARY_DIR}/src_generated/ua_statuscode_msg_table
-            DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/generate_statuscode_msg.py
-            ${CMAKE_CURRENT_SOURCE_DIR}/tools/schema/Opc.Ua.StatusCodes.csv)
-
-    list(APPEND exported_headers ${PROJECT_SOURCE_DIR}/include/ua_statuscode_msg.h)
-    list(APPEND lib_sources ${PROJECT_BINARY_DIR}/src_generated/ua_statuscode_msg_table.c)
-    list(APPEND lib_sources ${PROJECT_SOURCE_DIR}/src/ua_statuscode_msg.c)
-endif()
+# statuscode explanation
+add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/ua_statuscode_descriptions.c
+        PRE_BUILD
+        COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/generate_statuscode_descriptions.py
+        ${PROJECT_SOURCE_DIR}/tools/schema/Opc.Ua.StatusCodes.csv ${PROJECT_BINARY_DIR}/src_generated/ua_statuscode_descriptions
+        DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/generate_statuscode_descriptions.py
+        ${CMAKE_CURRENT_SOURCE_DIR}/tools/schema/Opc.Ua.StatusCodes.csv)
+list(APPEND lib_sources ${PROJECT_BINARY_DIR}/src_generated/ua_statuscode_descriptions.c)
 
 # generated namespace 0
 add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/ua_namespaceinit_generated.c

+ 0 - 6
examples/client_firstSteps.c

@@ -7,9 +7,6 @@
 #ifdef UA_NO_AMALGAMATION
 #include "ua_client.h"
 #include "ua_config_standard.h"
-#ifdef UA_ENABLE_STATUSCODE_MSG
-#include "ua_statuscode_msg.h"
-#endif
 #else
 #include "open62541.h"
 #endif
@@ -18,9 +15,6 @@ int main(void) {
     UA_Client *client = UA_Client_new(UA_ClientConfig_standard);
     UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:16664");
     if(retval != UA_STATUSCODE_GOOD) {
-#ifdef UA_ENABLE_STATUSCODE_MSG
-	    printf("Client connect failed: %s - %s", UA_StatusCode_name(retval), UA_StatusCode_msg(retval));
-#endif
         UA_Client_delete(client);
         return (int)retval;
     }

+ 21 - 12
include/ua_config.h.in

@@ -20,21 +20,30 @@
 extern "C" {
 #endif
 
-#define UA_LOGLEVEL ${UA_LOGLEVEL}
+/**
+ * Library Version
+ * --------------- */
 #define UA_GIT_COMMIT_ID "${GIT_COMMIT_ID}"
-#cmakedefine UA_ENABLE_MULTITHREADING
+
+/**
+ * Options
+ * ------- */
+#define UA_LOGLEVEL ${UA_LOGLEVEL}
 #cmakedefine UA_ENABLE_METHODCALLS
+#cmakedefine UA_ENABLE_NODEMANAGEMENT
 #cmakedefine UA_ENABLE_SUBSCRIPTIONS
+#cmakedefine UA_ENABLE_MULTITHREADING
+
+/**
+ * Advanced Options
+ * ---------------- */
+#cmakedefine UA_ENABLE_STATUSCODE_DESCRIPTIONS
 #cmakedefine UA_ENABLE_TYPENAMES
+#cmakedefine UA_ENABLE_EMBEDDED_LIBC
 #cmakedefine UA_ENABLE_GENERATE_NAMESPACE0
 #cmakedefine UA_ENABLE_EXTERNAL_NAMESPACES
-#cmakedefine UA_ENABLE_NODEMANAGEMENT
-#cmakedefine UA_ENABLE_STATUSCODE_MSG
-
-#cmakedefine UA_ENABLE_EMBEDDED_LIBC
-
-#cmakedefine UA_ENABLE_NONSTANDARD_UDP
 #cmakedefine UA_ENABLE_NONSTANDARD_STATELESS
+#cmakedefine UA_ENABLE_NONSTANDARD_UDP
 
 /**
  * Standard Includes
@@ -50,10 +59,10 @@ extern "C" {
 
 /**
  * Function Export
- * --------------- */
-/* On Win32: Define UA_DYNAMIC_LINKING and UA_DYNAMIC_LINKING_EXPORT in order to
-   export symbols for a DLL. Define UA_DYNAMIC_LINKING only to import symbols
-   from a DLL.*/
+ * ---------------
+ * On Win32: Define ``UA_DYNAMIC_LINKING`` and ``UA_DYNAMIC_LINKING_EXPORT`` in
+ * order to export symbols for a DLL. Define ``UA_DYNAMIC_LINKING`` only to
+ * import symbols from a DLL.*/
 #cmakedefine UA_DYNAMIC_LINKING
 #if defined(_WIN32) && defined(UA_DYNAMIC_LINKING)
 # ifdef UA_DYNAMIC_LINKING_EXPORT /* export dll */

+ 0 - 44
include/ua_statuscode_msg.h

@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2016 the contributors as stated in the AUTHORS file
- *
- * This file is part of open62541. open62541 is free software: you can
- * redistribute it and/or modify it under the terms of the GNU Lesser General
- * Public License, version 3 (as published by the Free Software Foundation) with
- * a static linking exception as stated in the LICENSE file provided with
- * open62541.
- *
- * open62541 is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
- * details.
- */
-
-#ifndef UA_STATUSCODE_MSG_H_
-#define UA_STATUSCODE_MSG_H_
-
-#include "ua_types.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct UA_StatusCode_msg_info {
-	UA_StatusCode value;        /* The numeric value from UA_StatusCode */
-	const char* name;    /* The equivalent symbolic value */
-	const char* msg;    /* Short message about this value */
-};
-
-extern const struct UA_StatusCode_msg_info UA_StatusCode_msg_table[];
-
-extern const unsigned int UA_StatusCode_msg_table_size;
-
-UA_EXPORT const char * UA_StatusCode_msg(UA_StatusCode code);
-UA_EXPORT const char * UA_StatusCode_name(UA_StatusCode code);
-UA_StatusCode UA_EXPORT UA_StatusCode_from_name(const char* name);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* UA_STATUSCODE_MSG_H_ */

+ 21 - 0
include/ua_types.h

@@ -154,6 +154,27 @@ typedef double UA_Double;
  * specific code. */
 typedef uint32_t UA_StatusCode;
 
+typedef struct {
+	UA_StatusCode code;      /* The numeric value of the StatusCode */
+	const char* name;        /* The symbolic name */
+	const char* explanation; /* Short message explaining the StatusCode */
+} UA_StatusCodeDescription;
+
+/* Returns the description of the StatusCode. Never returns NULL, but a generic
+ * description for invalid StatusCodes instead. */
+UA_EXPORT const UA_StatusCodeDescription *
+UA_StatusCode_description(UA_StatusCode code);
+
+static UA_INLINE const char *
+UA_StatusCode_name(UA_StatusCode code) {
+    return UA_StatusCode_description(code)->name;
+}
+
+static UA_INLINE const char *
+UA_StatusCode_explanation(UA_StatusCode code) {
+    return UA_StatusCode_description(code)->explanation;
+}
+
 /**
  * String
  * ^^^^^^

+ 0 - 60
src/ua_statuscode_msg.c

@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2016 the contributors as stated in the AUTHORS file
- *
- * This file is part of open62541. open62541 is free software: you can
- * redistribute it and/or modify it under the terms of the GNU Lesser General
- * Public License, version 3 (as published by the Free Software Foundation) with
- * a static linking exception as stated in the LICENSE file provided with
- * open62541.
- *
- * open62541 is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
- * details.
- */
-
-#include "ua_config.h"
-#include "ua_statuscode_msg.h"
-#include "ua_util.h"
-
-/*
-
- From generated file:
-
-static const struct UA_StatusCode_msg_info UA_StatusCode_msg_table[] =
-{
-		{UA_STATUSCODE_GOOD, "EPERM", "Not owner"},
-		{UA_STATUSCODE_BADINVALIDARGUMENT, "EPERM", "Not owner"},
-		{UA_STATUSCODE_BADOUTOFMEMORY, "EPERM", "Not owner"}
-};
-
-static const unsigned int UA_StatusCode_msg_table_size = 0;
- */
-
-UA_EXPORT const char* UA_StatusCode_msg(UA_StatusCode code) {
-	for (unsigned int i=0; i<UA_StatusCode_msg_table_size; i++) {
-		if (UA_StatusCode_msg_table[i].value == code)
-			return UA_StatusCode_msg_table[i].msg;
-	}
-	return NULL;
-}
-
-
-UA_EXPORT const char* UA_StatusCode_name(UA_StatusCode code) {
-	for (unsigned int i=0; i<UA_StatusCode_msg_table_size; i++) {
-		if (UA_StatusCode_msg_table[i].value == code)
-			return UA_StatusCode_msg_table[i].name;
-	}
-	return NULL;
-}
-
-
-UA_StatusCode UA_EXPORT UA_StatusCode_from_name(const char* name) {
-	if (name != NULL) {
-		for (unsigned int i=0; i<UA_StatusCode_msg_table_size; i++) {
-			if (strcmp(UA_StatusCode_msg_table[i].name, name) == 0)
-				return UA_StatusCode_msg_table[i].value;
-		}
-	}
-	return UA_UINT32_MAX;
-}

+ 17 - 11
tests/check_utils.c

@@ -2,7 +2,6 @@
 
 #include "ua_types.h"
 #include "ua_client.h"
-#include "ua_statuscode_msg.h"
 #include "check.h"
 
 START_TEST(EndpointUrl_split) {
@@ -115,26 +114,33 @@ END_TEST
 
 
 START_TEST(StatusCode_msg) {
+#ifndef UA_ENABLE_STATUSCODE_DESCRIPTIONS
+    ck_assert_str_eq(UA_StatusCode_msg(UA_STATUSCODE_GOOD), "StatusCode descriptions not available");
+    return;
+#endif
 		// first element in table
-    ck_assert_str_eq(UA_StatusCode_msg(UA_STATUSCODE_GOOD), "No error");
+    ck_assert_str_eq(UA_StatusCode_explanation(UA_STATUSCODE_GOOD), "Success / No error");
     ck_assert_str_eq(UA_StatusCode_name(UA_STATUSCODE_GOOD), "Good");
 
-
 		// just some randomly picked status codes
-    ck_assert_str_eq(UA_StatusCode_msg(UA_STATUSCODE_BADNOCOMMUNICATION), "Communication with the data source is defined");
-    ck_assert_str_eq(UA_StatusCode_name(UA_STATUSCODE_BADNOCOMMUNICATION), "BadNoCommunication");
+    ck_assert_str_eq(UA_StatusCode_explanation(UA_STATUSCODE_BADNOCOMMUNICATION),
+                     "Communication with the data source is defined");
+    ck_assert_str_eq(UA_StatusCode_name(UA_STATUSCODE_BADNOCOMMUNICATION),
+                     "BadNoCommunication");
 
-    ck_assert_str_eq(UA_StatusCode_msg(UA_STATUSCODE_GOODNODATA), "No data exists for the requested time range or event filter.");
+    ck_assert_str_eq(UA_StatusCode_explanation(UA_STATUSCODE_GOODNODATA),
+                     "No data exists for the requested time range or event filter.");
     ck_assert_str_eq(UA_StatusCode_name(UA_STATUSCODE_GOODNODATA), "GoodNoData");
 
 		// last element in table
-    ck_assert_str_eq(UA_StatusCode_msg(UA_STATUSCODE_BADMAXCONNECTIONSREACHED), "The operation could not be finished because all available connections are in use.");
-    ck_assert_str_eq(UA_StatusCode_name(UA_STATUSCODE_BADMAXCONNECTIONSREACHED), "BadMaxConnectionsReached");
+    ck_assert_str_eq(UA_StatusCode_explanation(UA_STATUSCODE_BADMAXCONNECTIONSREACHED),
+                     "The operation could not be finished because all available connections are in use.");
+    ck_assert_str_eq(UA_StatusCode_name(UA_STATUSCODE_BADMAXCONNECTIONSREACHED),
+                     "BadMaxConnectionsReached");
 
 		// an invalid status code
-	ck_assert_ptr_eq(UA_StatusCode_msg(0x80123456), NULL);
-	ck_assert_ptr_eq(UA_StatusCode_name(0x80123456), NULL);
-
+	ck_assert_str_eq(UA_StatusCode_explanation(0x80123456), "Unknown StatusCode");
+	ck_assert_str_eq(UA_StatusCode_name(0x80123456), "Unknown");
 }
 END_TEST
 

+ 65 - 0
tools/generate_statuscode_descriptions.py

@@ -0,0 +1,65 @@
+from __future__ import print_function
+import sys
+import platform
+import getpass
+import time
+import argparse
+
+parser = argparse.ArgumentParser()
+parser.add_argument('statuscodes', help='path/to/Opc.Ua.StatusCodes.csv')
+parser.add_argument('outfile', help='outfile w/o extension')
+args = parser.parse_args()
+
+f = open(args.statuscodes)
+input_str = f.read()
+f.close()
+input_str = input_str.replace('\r','')
+rows = map(lambda x:tuple(x.split(',')), input_str.split('\n'))
+
+fc = open(args.outfile + ".c",'w')
+def printc(string):
+    print(string, end='\n', file=fc)
+
+printc('''/**********************************************************
+ * '''+args.outfile+'''.hgen -- do not modify
+ **********************************************************
+ * Generated from '''+args.statuscodes+''' 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.h"''')
+
+count = 2
+for row in rows:
+    count += 1
+
+printc('''
+#ifndef UA_ENABLE_STATUSCODE_DESCRIPTIONS
+static const size_t statusCodeDescriptionsSize = 1;
+static const UA_StatusCodeDescription statusCodeDescriptions[1] = {
+{0xffffffff, \"StatusCode descriptions not available\", \"open62541 was compiled without support for statuscode descriptions\"}
+};
+#else
+static const size_t statusCodeDescriptionsSize = %s;
+static const UA_StatusCodeDescription statusCodeDescriptions[%i] =
+{''' % (count, count))
+
+printc(" {UA_STATUSCODE_GOOD, \"Good\", \"Success / No error\"},")
+for row in rows:
+    printc(" {UA_STATUSCODE_%s, \"%s\", \"%s\"}," % (row[0].upper(), row[0], row[2]))
+printc(" {0xffffffff, \"Unknown\", \"Unknown StatusCode\"},")
+printc('''\n};
+#endif''')
+
+printc('''
+const UA_StatusCodeDescription * UA_StatusCode_description(UA_StatusCode code) {
+    for(size_t i = 0; i < statusCodeDescriptionsSize; i++) {
+        if(statusCodeDescriptions[i].code == code)
+            return &statusCodeDescriptions[i];
+    }
+    return &statusCodeDescriptions[statusCodeDescriptionsSize-1];
+}
+''')
+
+fc.close()

+ 0 - 51
tools/generate_statuscode_msg.py

@@ -1,51 +0,0 @@
-from __future__ import print_function
-import sys
-import platform
-import getpass
-import time
-import argparse
-
-parser = argparse.ArgumentParser()
-parser.add_argument('statuscodes', help='path/to/Opc.Ua.StatusCodes.csv')
-parser.add_argument('outfile', help='outfile w/o extension')
-args = parser.parse_args()
-
-f = open(args.statuscodes)
-input_str = f.read()
-f.close()
-input_str = input_str.replace('\r','')
-rows = map(lambda x:tuple(x.split(',')), input_str.split('\n'))
-
-fh = open(args.outfile + ".c",'w')
-def printh(string):
-    print(string, end='\n', file=fh)
-
-printh('''/**********************************************************
- * '''+args.outfile+'''.hgen -- do not modify
- **********************************************************
- * Generated from '''+args.statuscodes+''' 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_statuscode_msg.h"
-
-const struct UA_StatusCode_msg_info UA_StatusCode_msg_table[] =
-{''')
-
-#for row in rows:
-#    printh("#define UA_STATUSCODE_%s %s // %s" % (row[0].upper(), row[1].lower(), row[2]))
-
-count = 1
-printh(" {UA_STATUSCODE_GOOD, \"Good\", \"No error\"},")
-
-for row in rows:
-    printh(" {UA_STATUSCODE_%s, \"%s\", \"%s\"}," % (row[0].upper(), row[0], row[2]))
-    count += 1
-
-printh('\n};\n')
-
-printh('const unsigned int UA_StatusCode_msg_table_size = ' + str(count) + ';')
-
-
-fh.close()

+ 1 - 1
tools/travis/travis_linux_script.sh

@@ -111,7 +111,7 @@ else
     #this run inclides full examples and methodcalls
     echo "Debug build and unit tests (64 bit)"
     mkdir -p build && cd build
-    cmake -DCMAKE_BUILD_TYPE=Debug -DUA_BUILD_EXAMPLES=ON -DUA_BUILD_UNIT_TESTS=ON -DUA_ENABLE_COVERAGE=ON -DUA_ENABLE_STATUSCODE_MSG=ON ..
+    cmake -DCMAKE_BUILD_TYPE=Debug -DUA_BUILD_EXAMPLES=ON -DUA_BUILD_UNIT_TESTS=ON -DUA_ENABLE_COVERAGE=ON ..
     make -j8 && make test ARGS="-V"
     echo "Run valgrind to see if the server leaks memory (just starting up and closing..)"
     (valgrind --leak-check=yes --error-exitcode=3 ./examples/server & export pid=$!; sleep 2; kill -INT $pid; wait $pid);