Pārlūkot izejas kodu

improve documentation

Julius Pfrommer 7 gadi atpakaļ
vecāks
revīzija
8cc2b59fdd
6 mainītis faili ar 438 papildinājumiem un 226 dzēšanām
  1. 161 20
      doc/index.rst
  2. 2 0
      include/ua_constants.h
  3. 189 165
      include/ua_types.h
  4. 51 17
      src/server/ua_nodes.h
  5. 14 3
      src/server/ua_services.h
  6. 21 21
      src/server/ua_services_attribute.c

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 161 - 20
doc/index.rst


+ 2 - 0
include/ua_constants.h

@@ -26,6 +26,8 @@ extern "C" {
  * This section contains numerical and string constants that are defined in the
  * OPC UA standard.
  *
+ * .. _attribute-id:
+ *
  * Attribute Id
  * ------------
  * Every node in an OPC UA information model contains attributes depending on

+ 189 - 165
include/ua_types.h

@@ -1,5 +1,4 @@
-/*
- * Copyright (C) 2013-2015 the contributors as stated in the AUTHORS file
+/* Copyright (C) 2013-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
@@ -10,8 +9,7 @@
  * 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.
- */
+ * details. */
 
 #ifndef UA_TYPES_H_
 #define UA_TYPES_H_
@@ -29,32 +27,42 @@ extern "C" {
  * Data Types
  * ==========
  *
- * In open62541, all data types share the same basic API for creation, copying
- * and deletion. The header ``ua_types.h`` defines the builtin data types. In
- * addition, the auto-generated ``ua_types_generated.h`` contains additional
- * data types making use of the builtin data types only. The following functions
- * are defined for all (builtin and generated) data types ``T``:
- *
- * ``void T_init(T *ptr)``
- *   Initialize the data type. This is synonymous with zeroing out the memory,
- *   i.e. ``memset(ptr, 0, sizeof(T))``.
- * ``T* T_new()``
- *   Allocate and return the memory for the data type. The memory is already
- *   initialized.
- * ``UA_StatusCode T_copy(const T *src, T *dst)``
- *   Copy the content of the data type. Returns ``UA_STATUSCODE_GOOD`` or
+ * The OPC UA protocol defines 25 builtin data types and three ways of combining
+ * them into higher-order types: arrays, structures and unions. When the type of
+ * a value can be decided at runtime, it is be wrapped into a :ref:`variant`
+ * together with a description of the content. This metadata is used to decode
+ * the value on the receiving end. In open62541, the builtin data types are
+ * defined manually. Higher-order data types are generated from standard XML
+ * definitions. Their exact definitions can be looked up at
+ * https://opcfoundation.org/UA/schemas/Opc.Ua.Types.bsd.xml.
+ *
+ * Note that arrays can only be part of a scalar data type and never constitute
+ * a data type on their own. Also, open62541 does not implement unions so far.
+ * They are a recent addition to the protocol (since OPC UA v1.03). And so far,
+ * no service definition makes of unions in the request / response message
+ * definition. Instead, :ref:`Variants <variant>` are used where several member
+ * value types are possible.
+ *
+ * All data types ``T`` (builtin and generated) share the same basic API for
+ * creation, copying and deletion:
+ *
+ * - ``void T_init(T *ptr)``: Initialize the data type. This is synonymous with
+ *   zeroing out the memory, i.e. ``memset(ptr, 0, sizeof(T))``.
+ * - ``T* T_new()``: Allocate and return the memory for the data type. The
+ *   memory is already initialized.
+ * - ``UA_StatusCode T_copy(const T *src, T *dst)``: Copy the content of the
+ *   data type. Returns ``UA_STATUSCODE_GOOD`` or
  *   ``UA_STATUSCODE_BADOUTOFMEMORY``.
- * ``void T_deleteMembers(T *ptr)``
- *   Delete the dynamically allocated content of the data type and perform a
- *   ``T_init`` to reset the type.
- * ``void T_delete(T *ptr)``
- *   Delete the content of the data type and the memory for the data type itself. */
+ * - ``void T_deleteMembers(T *ptr)``: Delete the dynamically allocated content
+ *   of the data type and perform a ``T_init`` to reset the type.
+ * - ``void T_delete(T *ptr)``: Delete the content of the data type and the
+ *   memory for the data type itself. */
 
 #define UA_BUILTIN_TYPES_COUNT 25U
 
 /**
- * Builtin Types Part 1
- * --------------------
+ * Builtin Types
+ * -------------
  *
  * Boolean
  * ^^^^^^^
@@ -68,65 +76,65 @@ typedef bool UA_Boolean;
  * ^^^^^
  * An integer value between -128 and 127. */
 typedef int8_t UA_SByte;
-#define UA_SBYTE_MAX 127
 #define UA_SBYTE_MIN (-128)
+#define UA_SBYTE_MAX 127
 
 /**
  * Byte
  * ^^^^
  * An integer value between 0 and 256. */
 typedef uint8_t UA_Byte;
-#define UA_BYTE_MAX 256
 #define UA_BYTE_MIN 0
+#define UA_BYTE_MAX 256
 
 /**
  * Int16
  * ^^^^^
  * An integer value between -32 768 and 32 767. */
 typedef int16_t UA_Int16;
-#define UA_INT16_MAX 32767
 #define UA_INT16_MIN (-32768)
+#define UA_INT16_MAX 32767
 
 /**
  * UInt16
  * ^^^^^^
  * An integer value between 0 and 65 535. */
 typedef uint16_t UA_UInt16;
-#define UA_UINT16_MAX 65535
 #define UA_UINT16_MIN 0
+#define UA_UINT16_MAX 65535
 
 /**
  * Int32
  * ^^^^^
  * An integer value between -2 147 483 648 and 2 147 483 647. */
 typedef int32_t UA_Int32;
-#define UA_INT32_MAX 2147483647
 #define UA_INT32_MIN (-2147483648)
+#define UA_INT32_MAX 2147483647
 
 /**
  * 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
+#define UA_UINT32_MAX 4294967295
 
 /**
  * Int64
  * ^^^^^
- * An integer value between -10 223 372 036 854 775 808 and
+ * An integer value between -9 223 372 036 854 775 808 and
  * 9 223 372 036 854 775 807. */
 typedef int64_t UA_Int64;
-#define UA_INT64_MAX (int64_t)9223372036854775807
 #define UA_INT64_MIN ((int64_t)-9223372036854775808)
+#define UA_INT64_MAX (int64_t)9223372036854775807
 
 /**
  * UInt64
  * ^^^^^^
  * An integer value between 0 and 18 446 744 073 709 551 615. */
 typedef uint64_t UA_UInt64;
-#define UA_UINT64_MAX (int64_t)18446744073709551615
 #define UA_UINT64_MIN (int64_t)0
+#define UA_UINT64_MAX (int64_t)18446744073709551615
 
 /**
  * Float
@@ -151,76 +159,6 @@ typedef double UA_Double;
 typedef uint32_t UA_StatusCode;
 
 /**
- * Array handling
- * --------------
- * In OPC UA, arrays can have a length of zero or more with the usual meaning.
- * In addition, arrays can be undefined. Then, they don't even have a length. In
- * the binary encoding, this is indicated by an array of length -1.
- *
- * In open62541 however, we use ``size_t`` for array lengths. An undefined array
- * has length 0 and the data pointer is NULL. An array of length 0 also has
- * length 0 but points to a sentinel memory address. */
-#define UA_EMPTY_ARRAY_SENTINEL ((void*)0x01)
-
-/** Forward Declaration of UA_DataType. See Section `Generic Type Handling`_
-    for details. */
-struct UA_DataType;
-typedef struct UA_DataType UA_DataType;
-
-/** The following functions are used for handling arrays of any data type. */
-
-/* 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_EXPORT * UA_Array_new(size_t size, const UA_DataType *type) UA_FUNC_ATTR_MALLOC;
-
-/* Allocates and copies an array
- *
- * @param src The memory location of the source array
- * @param 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 UA_STATUSCODE_GOOD or UA_STATUSCODE_BADOUTOFMEMORY */
-UA_StatusCode UA_EXPORT
-UA_Array_copy(const void *src, size_t size, void **dst,
-              const UA_DataType *type) UA_FUNC_ATTR_WARN_UNUSED_RESULT;
-
-/* 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_EXPORT UA_Array_delete(void *p, size_t size, const UA_DataType *type);
-
-/**
- * .. _numericrange:
- *
- * NumericRange
- * ^^^^^^^^^^^^
- *
- * 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 {
-    UA_UInt32 min;
-    UA_UInt32 max;
-} UA_NumericRangeDimension;
-    
-typedef struct {
-    size_t dimensionsSize;
-    UA_NumericRangeDimension *dimensions;
-} UA_NumericRange;
-
-/**
- * Builtin Types, Part 2
- * ---------------------
- *
  * String
  * ^^^^^^
  * A sequence of Unicode characters. Strings are just an array of UA_Byte. */
@@ -339,6 +277,8 @@ UA_BYTESTRING_ALLOC(const char *chars) {
 typedef UA_String UA_XmlElement;
 
 /**
+ * .. _nodeid:
+ *
  * NodeId
  * ^^^^^^
  * An identifier for a node in the address space of an OPC UA Server. */
@@ -459,6 +399,8 @@ UA_EXPANDEDNODEID_BYTESTRING_ALLOC(UA_UInt16 nsIndex, const char *chars) {
 }
 
 /**
+ * .. _qualifiedname:
+ *
  * QualifiedName
  * ^^^^^^^^^^^^^
  * A name qualified by a namespace. */
@@ -505,63 +447,52 @@ UA_LOCALIZEDTEXT_ALLOC(const char *locale, const char *text) {
     lt.text = UA_STRING_ALLOC(text); return lt;
 }
 
-/**
- * ExtensionObject
- * ^^^^^^^^^^^^^^^
- * ExtensionObjects may contain scalars of any data type. Even those that are
- * unknown to the receiver. See the Section `Generic Type Handling`_ on how
- * types are described. An ExtensionObject always contains the NodeId of the
- * Data Type. If the data cannot be decoded, we keep the encoded string and the
- * NodeId. */
-typedef struct {
-    enum {
-        UA_EXTENSIONOBJECT_ENCODED_NOBODY     = 0,
-        UA_EXTENSIONOBJECT_ENCODED_BYTESTRING = 1,
-        UA_EXTENSIONOBJECT_ENCODED_XML        = 2,
-        UA_EXTENSIONOBJECT_DECODED            = 3,
-        UA_EXTENSIONOBJECT_DECODED_NODELETE   = 4 /* Don't delete the content
-                                                     together with the
-                                                     ExtensionObject */
-    } 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;
-
 /**
  * .. _variant:
  *
  * Variant
  * ^^^^^^^
- * Variants may contain data of any type. See the Section `Generic Type
- * Handling`_ on how types are described. If the data is not of one of the 25
- * builtin types, it will be encoded as an `ExtensionObject`_ on the wire. (The
- * standard says that a variant is a union of the built-in types. open62541
- * generalizes this to any data type by transparently de- and encoding
- * ExtensionObjects in the background. If the decoding fails, the variant
- * contains the original ExtensionObject.)
- *
- * Variants can contain a single scalar or an array. For details on the handling
- * of arrays, see the Section `Array Handling`_. Array variants can have an
- * additional dimensionality (matrix, 3-tensor, ...) defined in an array of
- * dimension sizes.
- *
- * The differentiation between variants containing a scalar, an array or no data
- * is as follows:
- *
- * - ``arrayLength == 0 && data == NULL``: the variant is empty
+ *
+ * Variants may contain values of any type together with a description of the
+ * content. See the section on :ref:`generic-types` on how types are described.
+ * The standard mandates that variants contain built-in data types only. If the
+ * value is not of a builtin type, it is wrapped into an :ref:`extensionobject`.
+ * open62541 hides this wrapping transparently in the encoding layer. If the
+ * data type is unknown to the receiver, the variant contains the original
+ * ExtensionObject in binary or XML encoding.
+ *
+ * Variants may contain a scalar value or an array. For details on the handling
+ * of arrays, see the section on :ref:`array-handling`. Array variants can have
+ * an additional dimensionality (matrix, 3-tensor, ...) defined in an array of
+ * dimension lengths. The actual values are kept in an array of dimensions one.
+ * For users who work with higher-dimensions arrays directly, keep in mind that
+ * dimensions of higher rank are serialized first (the highest rank dimension
+ * has stride 1 and elements follow each other directly). Usually it is simplest
+ * to interact with higher-dimensional arrays via ``UA_NumericRange``
+ * descriptions (see :ref:`array-handling`).
+ *
+ * To differentiate between scalar / array variants, the following definition is
+ * used. ``UA_Variant_isScalar`` provides simplified access to these checks.
+ *
+ * - ``arrayLength == 0 && data == NULL``: undefined array of length -1
  * - ``arrayLength == 0 && data == UA_EMPTY_ARRAY_SENTINEL``: array of length 0
  * - ``arrayLength == 0 && data > UA_EMPTY_ARRAY_SENTINEL``: scalar value
- * - ``arrayLength > 0``: array of the given length */
+ * - ``arrayLength > 0``: array of the given length
+ *
+ * Variants can also be *empty*. Then, the pointer to the type description is
+ * ``NULL``. */
+/* Forward declaration. See the section on Generic Type Handling */
+struct UA_DataType;
+typedef struct UA_DataType UA_DataType;
+
+/* Forward declaration. See the section on Array Handling */
+struct UA_NumericRange;
+typedef struct UA_NumericRange UA_NumericRange;
+
+#define UA_EMPTY_ARRAY_SENTINEL ((void*)0x01)
+
 typedef struct {
-    const UA_DataType *type; /* The data type description */
+    const UA_DataType *type;      /* The data type description */
     enum {
         UA_VARIANT_DATA,          /* The data has the same lifecycle as the
                                      variant */
@@ -569,10 +500,10 @@ typedef struct {
                                      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 */
+    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 */
+    UA_UInt32 *arrayDimensions;   /* The length of each dimension */
 } UA_Variant;
 
 /* Returns true if the variant contains a scalar value. Note that empty variants
@@ -664,6 +595,38 @@ UA_StatusCode UA_EXPORT
 UA_Variant_setRangeCopy(UA_Variant *v, const void *array,
                         size_t arraySize, const UA_NumericRange range);
 
+/**
+ * .. _extensionobject:
+ *
+ * ExtensionObject
+ * ^^^^^^^^^^^^^^^
+ *
+ * ExtensionObjects may contain scalars of any data type. Even those that are
+ * unknown to the receiver. See the section on :ref:`generic-types` on how types
+ * are described. If the received data type is unkown, the encoded string and
+ * target NodeId is stored instead of the decoded value. */
+typedef struct {
+    enum {
+        UA_EXTENSIONOBJECT_ENCODED_NOBODY     = 0,
+        UA_EXTENSIONOBJECT_ENCODED_BYTESTRING = 1,
+        UA_EXTENSIONOBJECT_ENCODED_XML        = 2,
+        UA_EXTENSIONOBJECT_DECODED            = 3,
+        UA_EXTENSIONOBJECT_DECODED_NODELETE   = 4 /* Don't delete the content
+                                                     together with the
+                                                     ExtensionObject */
+    } 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;
+
 /**
  * .. _datavalue:
  *
@@ -708,6 +671,8 @@ typedef struct UA_DiagnosticInfo {
 } UA_DiagnosticInfo;
 
 /**
+ * .. _generic-types:
+ *
  * Generic Type Handling
  * ---------------------
  * The builtin types can be combined to data structures. All information about a
@@ -728,8 +693,8 @@ typedef struct {
     UA_Boolean namespaceZero : 1; /* The type of the member is defined in
                                      namespace zero. In this implementation,
                                      types from custom namespace may contain
-                                     members from the same namespace or ns0
-                                     only.*/
+                                     members from the same namespace or
+                                     namespace zero only.*/
     UA_Boolean isArray       : 1; /* The member is an array */
 } UA_DataTypeMember;
 
@@ -747,8 +712,8 @@ struct UA_DataType {
                                     pointers */
     UA_Boolean overlayable  : 1; /* The type has the identical memory layout in
                                     memory and on the binary stream. */
-    //UA_UInt16  xmlEncodingId;    /* NodeId of datatype when encoded as XML */
-    UA_UInt16  binaryEncodingId;    /* NodeId of datatype when encoded as binary */
+    UA_UInt16  binaryEncodingId; /* NodeId of datatype when encoded as binary */
+    //UA_UInt16  xmlEncodingId;  /* NodeId of datatype when encoded as XML */
     UA_DataTypeMember *members;
 };
 
@@ -757,8 +722,8 @@ struct UA_DataType {
 /* Allocates and initializes a variable of type dataType
  *
  * @param type The datatype description
- * @return Returns the memory location of the variable or (void*)0 if no
- *         memory is available */
+ * @return Returns the memory location of the variable or NULL if no
+ *         memory could be allocated */
 void UA_EXPORT * UA_new(const UA_DataType *type) UA_FUNC_ATTR_MALLOC;
 
 /* Initializes a variable to default values
@@ -796,6 +761,65 @@ void UA_EXPORT UA_deleteMembers(void *p, const UA_DataType *type);
  * @param type The datatype description of the variable */
 void UA_EXPORT UA_delete(void *p, const UA_DataType *type);
 
+/**
+ * .. _array-handling:
+ *
+ * Array handling
+ * --------------
+ * In OPC UA, arrays can have a length of zero or more with the usual meaning.
+ * In addition, arrays can be undefined. Then, they don't even have a length. In
+ * the binary encoding, this is indicated by an array of length -1.
+ *
+ * In open62541 however, we use ``size_t`` for array lengths. An undefined array
+ * has length 0 and the data pointer is ``NULL``. An array of length 0 also has
+ * length 0 but a data pointer ``UA_EMPTY_ARRAY_SENTINEL``. */
+/* 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 NULL if no memory
+           could be allocated */
+void UA_EXPORT * UA_Array_new(size_t size, const UA_DataType *type) UA_FUNC_ATTR_MALLOC;
+
+/* Allocates and copies an array
+ *
+ * @param src The memory location of the source array
+ * @param 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 UA_STATUSCODE_GOOD or UA_STATUSCODE_BADOUTOFMEMORY */
+UA_StatusCode UA_EXPORT
+UA_Array_copy(const void *src, size_t size, void **dst,
+              const UA_DataType *type) UA_FUNC_ATTR_WARN_UNUSED_RESULT;
+
+/* 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_EXPORT UA_Array_delete(void *p, size_t size, const UA_DataType *type);
+
+/**
+ * .. _numericrange:
+ *
+ * NumericRange
+ * ^^^^^^^^^^^^
+ *
+ * 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 {
+    UA_UInt32 min;
+    UA_UInt32 max;
+} UA_NumericRangeDimension;
+    
+struct UA_NumericRange {
+    size_t dimensionsSize;
+    UA_NumericRangeDimension *dimensions;
+};
+
 /**
  * Random Number Generator
  * -----------------------
@@ -807,12 +831,12 @@ UA_UInt32 UA_EXPORT UA_UInt32_random(void); /* no cryptographic entropy */
 UA_Guid UA_EXPORT UA_Guid_random(void);     /* no cryptographic entropy */
 
 /**
+ * .. _generated-types:
+ *
  * Generated Data Type Definitions
  * -------------------------------
  *
  * The following data types were auto-generated from a definition in XML format.
- * Their exact definitions can be looked up here:
- * https://opcfoundation.org/UA/schemas/Opc.Ua.Types.bsd.xml.
  *
  * .. include:: types_generated.rst */
 #ifdef __cplusplus

+ 51 - 17
src/server/ua_nodes.h

@@ -15,13 +15,17 @@ extern "C" {
  * semantic modelling. At the core, an OPC UA information model is a graph made
  * up of
  *
- * - Nodes: There are eight possible node types (variable, object, method, ...)
+ * - Nodes: There are eight possible Node types (variable, object, method, ...)
  * - References: Typed and directed relations between two nodes
  *
- * An example reference is a ``hasTypeDefinition`` reference between a variable
- * and its variable type. See the section on :ref:`reference types
- * <referencetypenode>` for more details about possible references and their
- * semantics.
+ * Every node is identified by a unique (within the server) :ref:`nodeid`.
+ * Reference are triples of the form ``(source-nodeid, referencetype-nodeid,
+ * target-nodeid)``. An example reference between nodes is a
+ * ``hasTypeDefinition`` reference between a Variable and its VariableType. Some
+ * ReferenceTypes are *hierarchic* and must not form *directed loops*. Every
+ * node (except ``Root``) must have at least one hierarchic reference to a
+ * parent. See the section on :ref:`ReferenceTypes <referencetypenode>` for more
+ * details on possible references and their semantics.
  *
  * The structures defined in this section are *not user-facing*. The interaction
  * with the information model is possible only via the OPC UA :ref:`services`.
@@ -31,10 +35,14 @@ extern "C" {
  * Base Node Attributes
  * --------------------
  *
- * The following attributes are common to all nodes. We use ``UA_Node`` in
- * places where the exact node type is not known or not important. The
- * ``nodeClass`` attribute is used to ensure the correctness of casting from
- * ``UA_Node`` to a specific node type. */
+ * Nodes contain attributes according to their node type. The base node
+ * attributes are common to all node types. In the OPC UA :ref:`services`,
+ * attributes are referred to via the :ref:`nodeid` of the containing node and
+ * an integer :ref:`attribute-id`.
+ *
+ * Internally, open62541 uses ``UA_Node`` in places where the exact node type is
+ * not known or not important. The ``nodeClass`` attribute is used to ensure the
+ * correctness of casting from ``UA_Node`` to a specific node type. */
 #define UA_NODE_BASEATTRIBUTES                  \
     UA_NodeId nodeId;                           \
     UA_NodeClass nodeClass;                     \
@@ -71,10 +79,10 @@ typedef struct {
  * Data Type
  * ^^^^^^^^^
  *
- * The type of the literal value is constrained to be of a specific type or one
- * of its children in the type hierarchy. The data type is given as a nodeid
- * pointing to a :ref:`datatypenode` in the type hierarchy. See the Section
- * :ref:`datatypenode` for more details.
+ * The (scalar) data type of the variable is constrained to be of a specific
+ * type or one of its children in the type hierarchy. The data type is given as
+ * a NodeId pointing to a :ref:`datatypenode` in the type hierarchy. See the
+ * Section :ref:`datatypenode` for more details.
  *
  * If the data type attribute points to ``UInt32``, then the value attribute
  * must be of that exact type since ``UInt32`` does not have children in the
@@ -154,7 +162,12 @@ typedef struct {
  * VariableTypeNode
  * ----------------
  *
- * VariableTypes are used to provide type definitions for variables. */
+ * VariableTypes are used to provide type definitions for variables.
+ * VariableTypes constrain the data type, value rank and array dimensions
+ * attributes of variable instances. Furthermore, instantiating from a specific
+ * variable type may provide semantic information. For example, an instance from
+ * ``MotorTemperatureVariableType`` is more meaningful than a float variable
+ * instantiated from ``BaseDataVariable``. */
 typedef struct {
     UA_NODE_BASEATTRIBUTES
     UA_NODE_VARIABLEATTRIBUTES
@@ -162,10 +175,23 @@ typedef struct {
 } UA_VariableTypeNode;
 
 /**
+ * .. _methodnode:
+ *
  * MethodNode
  * ----------
  *
- * Methods define callable functions and are invoked using the Call service. */
+ * Methods define callable functions and are invoked using the :ref:`Call
+ * <method-services>` service. MethodNodes may have special properties (variable
+ * childen with a ``hasProperty`` reference) with the :ref:`qualifiedname` ``(0,
+ * "InputArguments")`` and ``(0, "OutputArguments")``. The input and output
+ * arguments are both described via an array of ``UA_Argument``. While the Call
+ * service uses a generic array of :ref:`variant` for input and output, the
+ * actual argument values are checked to match the signature of the MethodNode.
+ *
+ * Note that the same MethodNode may be referenced from several objects (and
+ * object types). For this, the NodeId of the method *and of the object
+ * providing context* is part of a Call request message.
+ */
 typedef struct {
     UA_NODE_BASEATTRIBUTES
     UA_Boolean executable;
@@ -228,7 +254,13 @@ typedef struct {
  * DataTypeNode
  * ------------
  *
- * The DataType Model is used to define simple and structured data types. */
+ * DataTypes represent simple and structured data types (for scalar values). In
+ * open62541, DataTypeNodes in the hierarchy are matched to `UA_DataType` type
+ * descriptions for :ref:`generic-types` via their NodeId.
+ *
+ * Abstract DataTypes (e.g. ``Number``) cannot be the type of actual values.
+ * They are used to constrain values to possible child DataTypes (e.g.
+ * ``UInt32``). */
 typedef struct {
     UA_NODE_BASEATTRIBUTES
     UA_Boolean isAbstract;
@@ -240,7 +272,9 @@ typedef struct {
  *
  * Each View defines a subset of the Nodes in the AddressSpace. Views can be
  * used when browsing an informatin model to focus on a subset of nodes and
- * references only. */
+ * references only. ViewNodes can be created and be interacted with. But their
+ * use in the :ref:`Browse<view-services>` service is currently unsupported in
+ * open62541. */
 typedef struct {
     UA_NODE_BASEATTRIBUTES
     UA_Byte eventNotifier;

+ 14 - 3
src/server/ua_services.h

@@ -15,8 +15,14 @@ extern "C" {
  * Services
  * ========
  *
- * This section contains the services defined in the OPC UA standard grouped
- * into service sets. Their definition is internal and *not visible to users*.
+ * In OPC UA, all communication is based on service calls, each consisting of a
+ * request and a response message. These messages are defined as data structures
+ * with a binary encoding and listed in :ref:`generated-types`. Since all
+ * Services are pre-defined in the standard, they cannot be modified by the
+ * user. But you can use the :ref:`Call <method-services>` service to invoke
+ * user-defined methods on the server.
+ *
+ * The following service signatures are internal and *not visible to users*.
  * Still, we present them here for an overview of the capabilities of OPC UA.
  * Please refer to the :ref:`client` and :ref:`server` API where the services
  * are exposed to end users. */
@@ -120,6 +126,8 @@ void Service_DeleteReferences(UA_Server *server, UA_Session *session,
                               UA_DeleteReferencesResponse *response);
 
 /**
+ * .. _view-services:
+ *
  * View Service Set
  * ----------------
  * Clients use the browse Services of the View Service Set to navigate through
@@ -198,10 +206,13 @@ void Service_Write(UA_Server *server, UA_Session *session,
 /* Not Implemented: Service_HistoryUpdate */
 
 /**
+ * .. _method-services:
+ *
  * Method Service Set
  * ------------------
  * The Method Service Set defines the means to invoke methods. A method shall be
- * a component of an Object. */
+ * a component of an Object. See the section on :ref:`MethodNodes <methodnode>`
+ * for more information. */
 /* Used to call (invoke) a list of Methods. Each method call is invoked within
  * the context of an existing Session. If the Session is terminated, the results
  * of the method's execution cannot be returned to the Client and are

+ 21 - 21
src/server/ua_services_attribute.c

@@ -368,27 +368,27 @@ __UA_Server_read(UA_Server *server, const UA_NodeId *nodeId,
     }
 
     /* Prepare the result */
-     if(attributeId == UA_ATTRIBUTEID_VALUE ||
-        attributeId == UA_ATTRIBUTEID_ARRAYDIMENSIONS) {
-         /* Return the entire variant */
-         if(dv.value.storageType == UA_VARIANT_DATA_NODELETE) {
-             retval = UA_Variant_copy(&dv.value, v);
-         } else {
-             /* storageType is UA_VARIANT_DATA. Copy the entire variant
-              * (including pointers and all) */
-             memcpy(v, &dv.value, sizeof(UA_Variant));
-         }
-     }  else {
-         /* Return the variant content only */
-         if(dv.value.storageType == UA_VARIANT_DATA_NODELETE) {
-             retval = UA_copy(dv.value.data, v, dv.value.type);
-         } else {
-             /* storageType is UA_VARIANT_DATA. Copy the content of the type
-              * (including pointers and all) */
-             memcpy(v, dv.value.data, dv.value.type->memSize);
-             /* Delete the "carrier" in the variant */
-             UA_free(dv.value.data);
-         }
+    if(attributeId == UA_ATTRIBUTEID_VALUE ||
+       attributeId == UA_ATTRIBUTEID_ARRAYDIMENSIONS) {
+        /* Return the entire variant */
+        if(dv.value.storageType == UA_VARIANT_DATA_NODELETE) {
+            retval = UA_Variant_copy(&dv.value, v);
+        } else {
+            /* storageType is UA_VARIANT_DATA. Copy the entire variant
+             * (including pointers and all) */
+            memcpy(v, &dv.value, sizeof(UA_Variant));
+        }
+    } else {
+        /* Return the variant content only */
+        if(dv.value.storageType == UA_VARIANT_DATA_NODELETE) {
+            retval = UA_copy(dv.value.data, v, dv.value.type);
+        } else {
+            /* storageType is UA_VARIANT_DATA. Copy the content of the type
+             * (including pointers and all) */
+            memcpy(v, dv.value.data, dv.value.type->memSize);
+            /* Delete the "carrier" in the variant */
+            UA_free(dv.value.data);
+        }
     }
     return retval;
 }