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

improve the documentation of data types

Julius Pfrommer 9 éve
szülő
commit
06b6687b3f
2 módosított fájl, 635 hozzáadás és 70 törlés
  1. 611 40
      doc/datatypes.rst
  2. 24 30
      include/ua_types.h

+ 611 - 40
doc/datatypes.rst

@@ -18,8 +18,197 @@ deletion. The following functions are present for all data types ``T``.
 ``void T_delete(T *ptr)``
   Delete the content of the data type and the memory for the data type itself.
 
-Here's a small example for the UA_String data type. UA_String will be introduced
-in more detail later on, but you should be able to follow the example already.
+The builtin data types
+----------------------
+
+OPC UA defines 25 builtin data types. All other data types are combinations of
+the 25 builtin data types.
+
+UA_Boolean
+^^^^^^^^^^
+
+A two-state logical value (true or false).
+
+.. code-block:: c
+
+  typedef bool UA_Boolean;
+  #define UA_TRUE true
+  #define UA_FALSE false
+
+UA_SByte
+^^^^^^^^
+
+An integer value between -128 and 127.
+
+.. code-block:: c
+
+  typedef int8_t UA_SByte;
+
+UA_Byte
+^^^^^^^
+
+An integer value between 0 and 256.
+
+.. code-block:: c
+
+  typedef uint8_t UA_Byte;
+
+UA_Int16
+^^^^^^^^
+
+An integer value between -32,768 and 32,767.
+
+.. code-block:: c
+
+  typedef int16_t UA_Int16;
+
+UA_UInt16
+^^^^^^^^^
+
+An integer value between 0 and 65,535.
+
+.. code-block:: c
+
+  typedef uint16_t UA_UInt16;
+
+UA_Int32
+^^^^^^^^
+
+An integer value between -2,147,483,648 and 2,147,483,647.
+
+.. code-block:: c
+
+  typedef int32_t UA_Int32;
+
+UA_UInt32
+^^^^^^^^^
+
+An integer value between 0 and 4,294,967,295.
+
+.. code-block:: c
+
+  typedef uint32_t UA_UInt32;
+
+UA_Int64
+^^^^^^^^
+
+An integer value between -10,223,372,036,854,775,808 and 9,223,372,036,854,775,807.
+
+.. code-block:: c
+
+  typedef int64_t UA_Int64;
+
+UA_UInt64
+^^^^^^^^^
+
+An integer value between 0 and 18,446,744,073,709,551,615.
+
+.. code-block:: c
+
+  typedef uint64_t UA_UInt64;
+
+UA_Float
+^^^^^^^^
+
+An IEEE single precision (32 bit) floating point value.
+
+.. code-block:: c
+
+  typedef float UA_Float;
+
+UA_Double
+^^^^^^^^^
+
+An IEEE double precision (64 bit) floating point value.
+
+.. code-block:: c
+
+  typedef double UA_Double;
+
+UA_DateTime
+^^^^^^^^^^^
+
+An instance in time. A DateTime value is encoded as a 64-bit signed integer
+which represents the number of 100 nanosecond intervals since January 1, 1601
+(UTC).
+
+.. code-block:: c
+
+  typedef UA_Int64 UA_DateTime;
+
+The following functions and definitions are used with UA_DateTime.
+
+.. code-block:: c
+
+  UA_DateTime UA_DateTime_now(void);
+
+  typedef struct UA_DateTimeStruct {
+      UA_UInt16 nanoSec;
+      UA_UInt16 microSec;
+      UA_UInt16 milliSec;
+      UA_UInt16 sec;
+      UA_UInt16 min;
+      UA_UInt16 hour;
+      UA_UInt16 day;
+      UA_UInt16 month;
+      UA_UInt16 year;
+  } UA_DateTimeStruct;
+
+  UA_DateTimeStruct UA_EXPORT UA_DateTime_toStruct(UA_DateTime time);
+
+  UA_String UA_EXPORT UA_DateTime_toString(UA_DateTime time);
+
+UA_Guid
+^^^^^^^
+
+A 16 byte value that can be used as a globally unique identifier.
+
+.. code-block:: c
+
+  typedef struct {
+      UA_UInt32 data1;
+      UA_UInt16 data2;
+      UA_UInt16 data3;
+      UA_Byte   data4[8];
+  } UA_Guid;
+
+The following functions and definitions are used with UA_Guid.
+
+.. code-block:: c
+
+  UA_Boolean UA_Guid_equal(const UA_Guid *g1, const UA_Guid *g2);
+
+  UA_Guid UA_Guid_random(UA_UInt32 *seed);
+
+UA_String
+^^^^^^^^^
+
+A sequence of Unicode characters. See also the section :ref:`array-handling` for
+the usage of arrays in open62541.
+
+.. code-block:: c
+
+  typedef struct {
+      size_t length; // The length of the string
+      UA_Byte *data; // The string's content (not null-terminated)
+  } UA_String;
+
+The following functions and definitions are used with UA_String.
+
+.. code-block:: c
+
+  extern const UA_String UA_STRING_NULL;
+
+  UA_String UA_STRING(char *chars);
+
+  #define UA_STRING_ALLOC(CHARS) UA_String_fromChars(CHARS)
+    
+  /** Copies the content on the heap. Returns a null-string when alloc fails */
+  UA_String UA_String_fromChars(char const src[]);
+
+  UA_Boolean UA_String_equal(const UA_String *s1, const UA_String *s2);
+
+Here's a small example for the usage of UA_String.
 
 .. code-block:: c
 
@@ -44,63 +233,445 @@ in more detail later on, but you should be able to follow the example already.
   UA_String_delete(s3);                    /* Free the string buffer and the string itself */
   UA_String_deleteMembers(&s4);            /* Again, delete only the string buffer */
 
-The builtin data types
-----------------------
+UA_ByteString
+^^^^^^^^^^^^^
 
-OPC UA defines 25 builtin data types. All other data types are combinations of
-the 25 builtin data types.
+A sequence of octets.
 
-*TODO*
+.. code-block:: c
 
-Generic Data Type Handling
---------------------------
+  typedef UA_String UA_ByteString;
+
+UA_XmlEelement
+^^^^^^^^^^^^^^
 
-All standard-defined types are described with an ``UA_DataType`` structure.
+An XML element.
 
-.. doxygenstruct:: UA_DataType
-   :members:
+.. code-block:: c
 
-.. c:var:: const UA_DataType UA_TYPES[UA_TYPES_COUNT]
+  typedef UA_String UA_XmlElement;
 
-  The datatypes defined in the standard are stored in the ``UA_TYPES`` array.
-  A typical function call is ``UA_Array_new(&data_ptr, 20, &UA_TYPES[UA_TYPES_STRING])``.
+UA_NodeId
+^^^^^^^^^
 
-.. doxygenfunction:: UA_new
-.. doxygenfunction:: UA_init
-.. doxygenfunction:: UA_copy
-.. doxygenfunction:: UA_deleteMembers
-.. doxygenfunction:: UA_delete
+An identifier for a node in the address space of an OPC UA Server.
 
-For all datatypes, there are also macros with syntactic sugar over calling the
-generic functions with a pointer into the ``UA_TYPES`` array.
+.. code-block:: c
 
-.. c:function:: <typename>_new()
+  enum UA_NodeIdType {
+      UA_NODEIDTYPE_NUMERIC    = 0, // On the wire, this can be 0, 1 or 2 (shortened numeric nodeids)
+      UA_NODEIDTYPE_STRING     = 3,
+      UA_NODEIDTYPE_GUID       = 4,
+      UA_NODEIDTYPE_BYTESTRING = 5
+  };
 
-  Allocates the memory for the type and runs _init on the returned variable.
-  Returns null if no memory could be allocated.
+  typedef struct {
+      UA_UInt16 namespaceIndex;
+      enum UA_NodeIdType identifierType;
+      union {
+          UA_UInt32     numeric;
+          UA_String     string;
+          UA_Guid       guid;
+          UA_ByteString byteString;
+      } identifier;
+  } UA_NodeId;
 
-.. c:function:: <typename>_init(<typename> *value)
+The following functions and definitions are used with UA_NodeId.
 
-  Sets all members of the type to a default value, usually zero. Arrays (e.g.
-  for strings) are set to a length of -1.
+.. code-block:: c
 
-.. c:function:: <typename>_copy(<typename> *src, <typename> *dst)
+  UA_Boolean UA_NodeId_isNull(const UA_NodeId *p);
 
-  Copies a datatype. This performs a deep copy iterating over the members.
-  Copying into variants with an external data source is not permitted. If
-  copying fails, a deleteMembers is performed and an error code returned.
+  UA_Boolean UA_NodeId_equal(const UA_NodeId *n1, const UA_NodeId *n2);
 
-.. c:function:: <typename>_deleteMembers(<typename> *value)
+  extern const UA_NodeId UA_NODEID_NULL;
 
-   Frees the memory of dynamically sized members of a datatype (e.g. arrays).
+  UA_NodeId UA_NODEID_NUMERIC(UA_UInt16 nsIndex, UA_Int32 identifier);
 
-.. c:function:: <typename>_delete(<typename> *value)
+  UA_NodeId UA_NODEID_STRING(UA_UInt16 nsIndex, char *chars) {
 
-   Frees the memory of the datatype and its dynamically allocated members.
+  UA_NodeId UA_NODEID_STRING_ALLOC(UA_UInt16 nsIndex, const char *chars);
+
+  UA_NodeId UA_NODEID_GUID(UA_UInt16 nsIndex, UA_Guid guid);
+
+  UA_NodeId UA_NODEID_BYTESTRING(UA_UInt16 nsIndex, char *chars);
+
+  UA_NodeId UA_NODEID_BYTESTRING_ALLOC(UA_UInt16 nsIndex, const char *chars);
+
+UA_ExpandedNodeId
+^^^^^^^^^^^^^^^^^
+
+A NodeId that allows the namespace URI to be specified instead of an index.
+
+.. code-block:: c
+
+  typedef struct {
+      UA_NodeId nodeId;
+      UA_String namespaceUri;
+      UA_UInt32 serverIndex;
+  } UA_ExpandedNodeId;
+
+The following functions and definitions are used with UA_ExpandedNodeId.
+
+.. code-block:: c
+
+  UA_ExpandedNodeId UA_EXPANDEDNODEID_NUMERIC(UA_UInt16 nsIndex, UA_Int32 identifier);
+
+  UA_ExpandedNodeId UA_EXPANDEDNODEID_STRING(UA_UInt16 nsIndex, char *chars);
+
+  UA_ExpandedNodeId UA_EXPANDEDNODEID_STRING_ALLOC(UA_UInt16 nsIndex, const char *chars);
+
+  UA_ExpandedNodeId UA_EXPANDEDNODEID_STRING_GUID(UA_UInt16 nsIndex, UA_Guid guid);
+
+  UA_ExpandedNodeId UA_EXPANDEDNODEID_BYTESTRING(UA_UInt16 nsIndex, char *chars);
+
+  UA_ExpandedNodeId UA_EXPANDEDNODEID_BYTESTRING_ALLOC(UA_UInt16 nsIndex, const char *chars);
+
+UA_QualifiedName
+^^^^^^^^^^^^^^^^
+
+A name qualified by a namespace.
+
+.. code-block:: c
+
+  typedef struct {
+      UA_UInt16 namespaceIndex;
+      UA_String name;
+  } UA_QualifiedName;
+
+The following functions and definitions are used with UA_QualifiedName.
+
+.. code-block:: c
+
+  UA_QualifiedName UA_QUALIFIEDNAME(UA_UInt16 nsIndex, char *chars);
+
+  UA_QualifiedName UA_QUALIFIEDNAME_ALLOC(UA_UInt16 nsIndex, const char *chars);
+
+UA_LocalizedText
+^^^^^^^^^^^^^^^^
+
+Human readable text with an optional locale identifier.
+
+.. code-block:: c
+
+  typedef struct {
+      UA_String locale;
+      UA_String text;
+  } UA_LocalizedText;
+                
+The following functions and definitions are used with UA_LocalizedText.
+
+.. code-block:: c
+
+  UA_LocalizedText UA_LOCALIZEDTEXT(char *locale, char *text);
+
+  UA_LocalizedText UA_LOCALIZEDTEXT_ALLOC(const char *locale, const char *text);
+
+UA_ExtensionObject
+^^^^^^^^^^^^^^^^^^
+
+A structure that contains an application specific data type that may not be
+recognized by the receiver.
+
+.. code-block:: c
+
+  typedef struct {
+      enum {
+          UA_EXTENSIONOBJECT_ENCODED_NOBODY     = 0,
+          UA_EXTENSIONOBJECT_ENCODED_BYTESTRING = 1,
+          UA_EXTENSIONOBJECT_ENCODED_XML        = 2,
+          UA_EXTENSIONOBJECT_DECODED            = 3, ///< There is a pointer to the decoded data
+          UA_EXTENSIONOBJECT_DECODED_NODELETE   = 4  ///< Don't delete the decoded data at the lifecycle end
+      } encoding;
+      union {
+          struct {
+              UA_NodeId typeId; ///< The nodeid of the datatype
+              UA_ByteString body; ///< The bytestring of the encoded data
+          } encoded;
+          struct {
+              const UA_DataType *type;
+              void *data;
+          } decoded;
+      } content;
+  } UA_ExtensionObject;
+
+UA_Variant
+^^^^^^^^^^
+
+Stores (arrays of) any data type. Please see section :ref:`generic-handling` for
+the usage of UA_DataType. The semantics of the arrayLength field is explained in
+section :ref:`array-handling`.
+
+.. code-block:: c
+
+  typedef struct {
+      const UA_DataType *type; // The data type description
+      enum {
+          UA_VARIANT_DATA,          /* The data has the same lifecycle as the variant */
+          UA_VARIANT_DATA_NODELETE, /* The data is "borrowed" by the variant and shall not be
+                                       deleted at the end of the variant's lifecycle. */
+      } storageType;
+      size_t arrayLength;  // The number of elements in the data array
+      void *data; // Points to the scalar or array data
+      size_t arrayDimensionsSize; // The number of dimensions the data-array has
+      UA_UInt32 *arrayDimensions; // The length of each dimension of the data-array
+  } UA_Variant;
+
+  /* NumericRanges are used to indicate subsets of a (multidimensional) variant
+  * array. NumericRange has no official type structure in the standard. On the
+  * wire, it only exists as an encoded string, such as "1:2,0:3,5". The colon
+  * separates min/max index and the comma separates dimensions. A single value
+  * indicates a range with a single element (min==max). */
+  typedef struct {
+      size_t dimensionsSize;
+      struct UA_NumericRangeDimension {
+          UA_UInt32 min;
+          UA_UInt32 max;
+      } *dimensions;
+  } UA_NumericRange;
+
+
+The following functions and definitions are used with UA_Variant.
+
+.. code-block:: c
+
+  /**
+   * Returns true if the variant contains a scalar value. Note that empty
+   * variants contain an array of length -1 (undefined).
+   *
+   * @param v The variant
+   * @return Does the variant contain a scalar value.
+   */
+  UA_Boolean UA_Variant_isScalar(const UA_Variant *v);
+
+  /**
+   * Set the variant to a scalar value that already resides in memory. The value
+   * takes on the lifecycle of the variant and is deleted with it.
+   *
+   * @param v The variant
+   * @param p A pointer to the value data
+   * @param type The datatype of the value in question
+   */
+  UA_Variant_setScalar(UA_Variant *v, void * UA_RESTRICT p, const UA_DataType *type);
+
+  /**
+   * Set the variant to a scalar value that is copied from an existing variable.
+   *
+   * @param v The variant
+   * @param p A pointer to the value data
+   * @param type The datatype of the value
+   * @return Indicates whether the operation succeeded or returns an error code
+   */
+  UA_StatusCode UA_Variant_setScalarCopy(UA_Variant *v, const void *p, const UA_DataType *type);
+
+  /**
+   * Set the variant to an array that already resides in memory. The array takes
+   * on the lifecycle of the variant and is deleted with it.
+   *
+   * @param v The variant
+   * @param array A pointer to the array data
+   * @param arraySize The size of the array
+   * @param type The datatype of the array
+   */
+  void UA_Variant_setArray(UA_Variant *v, void * UA_RESTRICT array,
+                           size_t arraySize, const UA_DataType *type);
+
+  /**
+   * Set the variant to an array that is copied from an existing array.
+   *
+   * @param v The variant
+   * @param array A pointer to the array data
+   * @param arraySize The size of the array
+   * @param type The datatype of the array
+   * @return Indicates whether the operation succeeded or returns an error code
+   */
+  UA_StatusCode UA_Variant_setArrayCopy(UA_Variant *v, const void *array,
+                                        size_t arraySize, const UA_DataType *type);
+
+  /**
+   * Copy the variant, but use only a subset of the (multidimensional) array
+   * into a variant. Returns an error code if the variant is not an array or if
+   * the indicated range does not fit.
+   *
+   * @param src The source variant
+   * @param dst The target variant
+   * @param range The range of the copied data
+   * @return Returns UA_STATUSCODE_GOOD or an error code
+   */
+  UA_StatusCode UA_Variant_copyRange(const UA_Variant *src, UA_Variant *dst,
+                                     const UA_NumericRange range);
+
+  /**
+   * Insert a range of data into an existing variant. The data array can't be
+   * reused afterwards if it contains types without a fixed size (e.g. strings)
+   * since the members are moved into the variant and take on its lifecycle.
+   *
+   * @param v The variant
+   * @param dataArray The data array. The type must match the variant
+   * @param dataArraySize The length of the data array. This is checked to match the range size.
+   * @param range The range of where the new data is inserted
+   * @return Returns UA_STATUSCODE_GOOD or an error code
+   */
+  UA_StatusCode UA_Variant_setRange(UA_Variant *v, void * UA_RESTRICT array,
+                                    size_t arraySize, const UA_NumericRange range);
+
+  /**
+   * Deep-copy a range of data into an existing variant.
+   *
+   * @param v The variant
+   * @param dataArray The data array. The type must match the variant
+   * @param dataArraySize The length of the data array. This is checked to match the range size.
+   * @param range The range of where the new data is inserted
+   * @return Returns UA_STATUSCODE_GOOD or an error code
+   */
+  UA_StatusCode UA_Variant_setRangeCopy(UA_Variant *v, const void *array,
+                                        size_t arraySize, const UA_NumericRange range);
+
+UA_DataValue
+^^^^^^^^^^^^
+
+A data value with an associated status code and timestamps.
+
+.. code-block:: c
+   
+  typedef struct {
+      UA_Boolean    hasValue             : 1;
+      UA_Boolean    hasStatus            : 1;
+      UA_Boolean    hasSourceTimestamp   : 1;
+      UA_Boolean    hasServerTimestamp   : 1;
+      UA_Boolean    hasSourcePicoseconds : 1;
+      UA_Boolean    hasServerPicoseconds : 1;
+      UA_Variant    value;
+      UA_StatusCode status;
+      UA_DateTime   sourceTimestamp;
+      UA_Int16      sourcePicoseconds;
+      UA_DateTime   serverTimestamp;
+      UA_Int16      serverPicoseconds;
+  } UA_DataValue;
+
+UA_DiagnosticInfo
+^^^^^^^^^^^^^^^^^
+
+A structure that contains detailed error and diagnostic information associated
+with a StatusCode.
+
+.. code-block:: c
+
+  typedef struct UA_DiagnosticInfo {
+      UA_Boolean    hasSymbolicId          : 1;
+      UA_Boolean    hasNamespaceUri        : 1;
+      UA_Boolean    hasLocalizedText       : 1;
+      UA_Boolean    hasLocale              : 1;
+      UA_Boolean    hasAdditionalInfo      : 1;
+      UA_Boolean    hasInnerStatusCode     : 1;
+      UA_Boolean    hasInnerDiagnosticInfo : 1;
+      UA_Int32      symbolicId;
+      UA_Int32      namespaceUri;
+      UA_Int32      localizedText;
+      UA_Int32      locale;
+      UA_String     additionalInfo;
+      UA_StatusCode innerStatusCode;
+      struct UA_DiagnosticInfo *innerDiagnosticInfo;
+  } UA_DiagnosticInfo;
+
+.. _generic-handling:
+
+Generic Data Type Handling
+--------------------------
+
+All standard-defined data types are described with an ``UA_DataType`` structure.
+In addition to the 25 builtin data types, OPC UA defines many more. But they are
+mere combinations of the builtin data types. We handle all types in a unified
+way by storing their internal structure. So it is not necessary to define
+specialized functions for all additional types.
+
+The ``UA_TYPES`` array contains the description of every standard-defined data
+type.
+
+.. code-block:: c
+
+  extern const UA_DataType UA_TYPES[UA_TYPES_COUNT];
+
+The following is an excerpt from ``ua_types_generated.h`` with the definition of
+OPC UA read requests. This file is auto-generated from the XML-description of
+the OPC UA data types that is part of the ISO/IEC 62541 standard.
+
+.. code-block:: c
+
+  typedef struct {
+      UA_RequestHeader requestHeader;
+      UA_Double maxAge;
+      UA_TimestampsToReturn timestampsToReturn;
+      size_t nodesToReadSize;
+      UA_ReadValueId *nodesToRead;
+  } UA_ReadRequest;
+
+  #define UA_TYPES_READREQUEST 118
+  
+  static UA_INLINE void UA_ReadRequest_init(UA_ReadRequest *p) {
+      memset(p, 0, sizeof(UA_ReadRequest)); }
+
+  static UA_INLINE void UA_ReadRequest_delete(UA_ReadRequest *p) {
+      UA_delete(p, &UA_TYPES[UA_TYPES_READREQUEST]); }
+
+  static UA_INLINE void UA_ReadRequest_deleteMembers(UA_ReadRequest *p) {
+      UA_deleteMembers(p, &UA_TYPES[UA_TYPES_READREQUEST]); }
+
+  static UA_INLINE UA_ReadRequest * UA_ReadRequest_new(void) {
+      return (UA_ReadRequest*) UA_new(&UA_TYPES[UA_TYPES_READREQUEST]); }
+
+  static UA_INLINE UA_StatusCode
+  UA_ReadRequest_copy(const UA_ReadRequest *src, UA_ReadRequest *dst) {
+      return UA_copy(src, dst, &UA_TYPES[UA_TYPES_READREQUEST]); }
+
+.. _array-handling:
 
 Array Handling
 --------------
-   
-.. doxygenfunction:: UA_Array_new
-.. doxygenfunction:: UA_Array_copy
-.. doxygenfunction:: UA_Array_delete
+
+In OPC UA, all arrays can be undefined, have length 0 or a positive length. In
+data structures, all arrays are represented by a ``size_t`` length field and an
+appropriate pointer directly afterwards. In order to distinguish between
+undefined and length-zero arrays, we define the following.
+
+.. code-block:: c
+
+  #define UA_EMPTY_ARRAY_SENTINEL ((void*)0x01)
+
+- size == 0 and data == NULL: The array is undefined
+- size == 0 and data == ``UA_EMPTY_ARRAY_SENTINEL``: The array has length 0
+- size > 0: The array at the given memory address has the given size
+
+The following functions are defined for array handling.
+
+.. code-block:: c
+
+  /**
+   * Allocates and initializes an array of variables of a specific type
+   *
+   * @param size The requested array length
+   * @param type The datatype description
+   * @return Returns the memory location of the variable or (void*)0 if no memory could be allocated
+   */
+  void * UA_Array_new(size_t size, const UA_DataType *type);
+
+  /**
+   * Allocates and copies an array. dst is set to (void*)0 if not enough memory is available.
+   *
+   * @param src The memory location of the source array
+   * @param src_size The size of the array
+   * @param dst The location of the pointer to the new array
+   * @param type The datatype of the array members
+   * @return Returns whether copying succeeded
+   */
+  UA_StatusCode UA_Array_copy(const void *src, size_t src_size, void **dst,
+                              const UA_DataType *type);
+
+  /**
+   * Deletes an array.
+   *
+   * @param p The memory location of the array
+   * @param size The size of the array
+   * @param type The datatype of the array members
+   */
+  void UA_Array_delete(void *p, size_t size, const UA_DataType *type); 

+ 24 - 30
include/ua_types.h

@@ -67,7 +67,7 @@ typedef int32_t UA_Int32;
 #define UA_INT32_MAX 2147483647
 #define UA_INT32_MIN (-2147483648)
 
-/** UInt32: An integer value between 0 and 429 4967 295 */
+/** UInt32: An integer value between 0 and 4 294 967 295 */
 typedef uint32_t UA_UInt32;
 #define UA_UINT32_MAX 4294967295
 #define UA_UINT32_MIN 0
@@ -92,8 +92,8 @@ typedef double UA_Double;
 /* String: A sequence of Unicode characters */
 /********************************************/
 typedef struct {
-    size_t length; ///< The length of the string
-    UA_Byte *data; ///< The string's content (not null-terminated)
+    size_t length; // The length of the string
+    UA_Byte *data; // The string's content (not null-terminated)
 } UA_String;
 
 UA_EXPORT extern const UA_String UA_STRING_NULL;
@@ -195,6 +195,8 @@ typedef struct {
     } identifier;
 } UA_NodeId;
 
+UA_EXPORT extern const UA_NodeId UA_NODEID_NULL;
+
 static UA_INLINE UA_Boolean UA_NodeId_isNull(const UA_NodeId *p) {
     return (p->namespaceIndex == 0 && p->identifierType == UA_NODEIDTYPE_NUMERIC &&
             p->identifier.numeric == 0);
@@ -202,8 +204,6 @@ static UA_INLINE UA_Boolean UA_NodeId_isNull(const UA_NodeId *p) {
 
 UA_Boolean UA_EXPORT UA_NodeId_equal(const UA_NodeId *n1, const UA_NodeId *n2);
 
-UA_EXPORT extern const UA_NodeId UA_NODEID_NULL;
-
 static UA_INLINE UA_NodeId UA_NODEID_NUMERIC(UA_UInt16 nsIndex, UA_Int32 identifier) {
     UA_NodeId id; id.namespaceIndex = nsIndex; id.identifierType = UA_NODEIDTYPE_NUMERIC;
     id.identifier.numeric = identifier; return id; }
@@ -265,8 +265,8 @@ static UA_INLINE UA_ExpandedNodeId UA_EXPANDEDNODEID_BYTESTRING_ALLOC(UA_UInt16
 /* QualifiedName: A name qualified by a namespace */
 /**************************************************/
 typedef struct {
-    UA_UInt16 namespaceIndex; ///< The namespace index
-    UA_String name; ///< The actual name
+    UA_UInt16 namespaceIndex;
+    UA_String name;
 } UA_QualifiedName;
 
 static UA_INLINE UA_QualifiedName UA_QUALIFIEDNAME(UA_UInt16 nsIndex, char *chars) {
@@ -279,8 +279,8 @@ static UA_INLINE UA_QualifiedName UA_QUALIFIEDNAME_ALLOC(UA_UInt16 nsIndex, cons
 /* LocalizedText: Human readable text with an optional locale identifier */
 /*************************************************************************/
 typedef struct {
-    UA_String locale; ///< The locale (e.g. "en-US")
-    UA_String text; ///< The actual text
+    UA_String locale;
+    UA_String text;
 } UA_LocalizedText;
 
 static UA_INLINE UA_LocalizedText UA_LOCALIZEDTEXT(char *locale, char *text) {
@@ -322,29 +322,23 @@ typedef struct {
 /*********************************************/
 /* Variant: Stores (arrays of) any data type */
 /*********************************************/
- /* Variants either they provide a pointer to the data in memory, or functions
-    from which the data can be accessed. Variants are replaced together with
-    the data they store (exception: use a data source).
-
-    Variant semantics:
+ /* Variant semantics:
     - arrayLength == 0 && data == NULL: no existing data
     - arrayLength == 0 && data == 0x01: array of length 0
     - arrayLength == 0 && data > 0x01: scalar value
     - arrayLength > 0: array of the given length
  */
 typedef struct {
-    const UA_DataType *type; ///< The nodeid of the datatype
+    const UA_DataType *type; // The data type description
     enum {
-        UA_VARIANT_DATA, ///< The data is "owned" by this variant (copied and deleted together)
-        UA_VARIANT_DATA_NODELETE, /**< The data is "borrowed" by the variant and shall not be
-                                       deleted at the end of this variant's lifecycle. It is not
-                                       possible to overwrite borrowed data due to concurrent access.
-                                       Use a custom datasource with a mutex. */
-    } storageType; ///< Shall the data be deleted together with the variant
-    size_t arrayLength;  ///< the number of elements in the data-pointer
-    void *data; ///< points to the scalar or array data
-    size_t arrayDimensionsSize; ///< the number of dimensions the data-array has
-    UA_UInt32 *arrayDimensions; ///< the length of each dimension of the data-array
+        UA_VARIANT_DATA,          /* The data has the same lifecycle as the variant */
+        UA_VARIANT_DATA_NODELETE, /* The data is "borrowed" by the variant and shall not be
+                                     deleted at the end of the variant's lifecycle. */
+    } storageType;
+    size_t arrayLength;  // The number of elements in the data array
+    void *data; // Points to the scalar or array data
+    size_t arrayDimensionsSize; // The number of dimensions the data-array has
+    UA_UInt32 *arrayDimensions; // The length of each dimension of the data-array
 } UA_Variant;
 
 /**
@@ -401,11 +395,11 @@ UA_Variant_setArray(UA_Variant *v, void * UA_RESTRICT array, size_t arraySize, c
 UA_StatusCode UA_EXPORT
 UA_Variant_setArrayCopy(UA_Variant *v, const void *array, size_t arraySize, const UA_DataType *type);
 
-/* NumericRanges are used select a subset in a (multidimensional) variant array.
- * NumericRange has no official type structure in the standard. On the wire, it
- * only exists as an encoded string, such as "1:2,0:3,5". The colon separates
- * min/max index and the comma separates dimensions. A single value indicates a
- * range with a single element (min==max). */
+/* NumericRanges are used to indicate subsets of a (multidimensional) variant
+ * array. NumericRange has no official type structure in the standard. On the
+ * wire, it only exists as an encoded string, such as "1:2,0:3,5". The colon
+ * separates min/max index and the comma separates dimensions. A single value
+ * indicates a range with a single element (min==max). */
 typedef struct {
     size_t dimensionsSize;
     struct UA_NumericRangeDimension {