tutorial_server_variables.rst 3.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. Adding nodes to a server and connecting nodes to user-defined values
  2. ======================
  3. This tutorial shows how to add variable nodes to a server and how these can be connected to user-defined values and callbacks.
  4. Firstly, we need to introduce a concept of Variants. This is a data structure able to hold any datatype.
  5. Variants
  6. ---------------------
  7. 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::
  8. typedef struct {
  9. const UA_DataType *type; ///< The nodeid of the datatype
  10. enum {
  11. UA_VARIANT_DATA, ///< The data is "owned" by this variant (copied and deleted together)
  12. UA_VARIANT_DATA_NODELETE, /**< The data is "borrowed" by the variant and shall not be
  13. deleted at the end of this variant's lifecycle. It is not
  14. possible to overwrite borrowed data due to concurrent access.
  15. Use a custom datasource with a mutex. */
  16. } storageType; ///< Shall the data be deleted together with the variant
  17. UA_Int32 arrayLength; ///< the number of elements in the data-pointer
  18. void *data; ///< points to the scalar or array data
  19. UA_Int32 arrayDimensionsSize; ///< the number of dimensions the data-array has
  20. UA_Int32 *arrayDimensions; ///< the length of each dimension of the data-array
  21. } UA_Variant;
  22. The members of the struct are
  23. * type: a pointer to the vtable entry. It points onto the functions which handles the stored data i.e. encode/decode etc.
  24. * storageType: used to declare who the owner of data is and to which lifecycle it belongs. Three different cases are possible:
  25. * 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
  26. * 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
  27. * arrayLength: length of the array (-1 if a scalar is saved)
  28. * data: raw pointer to the saved vale or callback
  29. * arrayDimensionsSize: size of arrayDimensions array
  30. * arrayDimensions: dimensinos array in case the array is interpreted as a multi-dimensional construction, e.g., [5,5] for a 5x5 matrix
  31. Adding a variable node to the server that contains a user-defined variable
  32. ---------------------
  33. 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.
  34. Consider 'examples/server_variable.c' in the repository. The examples are compiled if the Cmake option BUILD_EXAMPLE is turned on.
  35. Adding a variable node to the server that contains a user-defined callback.
  36. ---------------------
  37. 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.
  38. Consider 'examples/server_datasource.c' in the repository. The examples are compiled if the Cmake option BUILD_EXAMPLE is turned on.