123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960 |
- Adding nodes to a server and connecting nodes to user-defined values
- ====================================================================
- This tutorial shows how to add variable nodes to a server and how these can be connected to user-defined values and callbacks.
- Firstly, we need to introduce a concept of Variants. This is a data structure able to hold any datatype.
- Variants
- --------
- The datatype UA_Variant a belongs to the built-in datatypes of OPC UA and is used as a container type. A Variant can hold any other built-in scalar datatype (except Variants) or array built-in datatype (array of variants too). The variant is structured like this in open62541:
- .. code-block:: c
- typedef struct {
- const UA_DataType *type; ///< The nodeid of the datatype
- 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
- UA_Int32 arrayLength; ///< the number of elements in the data-pointer
- void *data; ///< points to the scalar or array data
- UA_Int32 arrayDimensionsSize; ///< the number of dimensions the data-array has
- UA_Int32 *arrayDimensions; ///< the length of each dimension of the data-array
- } UA_Variant;
- The members of the struct are
- * type: a pointer to the vtable entry. It points onto the functions which handles the stored data i.e. encode/decode etc.
- * storageType: used to declare who the owner of data is and to which lifecycle it belongs. Three different cases are possible:
- * UA_VARIANT_DATA: this is the simplest case. The data belongs to the variant, which means if the variant is deleted so does the data which is kept inside
-
- * UA_VARIANT_DATASOURCE: in this case user-defined functions are called to access the data. The signature of the functions is defined by UA_VariantDataSource structure. A use-case could be to access a sensor only when the data is asked by some client
- * arrayLength: length of the array (-1 if a scalar is saved)
- * data: raw pointer to the saved vale or callback
- * arrayDimensionsSize: size of arrayDimensions array
- * arrayDimensions: dimensinos array in case the array is interpreted as a multi-dimensional construction, e.g., [5,5] for a 5x5 matrix
- Adding a variable node to the server that contains a user-defined variable
- --------------------------------------------------------------------------
- This simple case allows to 'inject' a pre-defined variable into a variable node. The variable is wrapped by a "UA_Variant" before being insterted into the node.
- Consider 'examples/server_variable.c' in the repository. The examples are compiled if the Cmake option BUILD_EXAMPLE is turned on.
- Adding a variable node to the server that contains a user-defined callback
- --------------------------------------------------------------------------
- The latter case allows to define callback functions that are executed on read or write of the node. In this case an "UA_DataSource" containing the respective callback pointer is intserted into the node.
- Consider 'examples/server_datasource.c' in the repository. The examples are compiled if the Cmake option BUILD_EXAMPLE is turned on.
|