tutorial_server_variables.rst 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. .. role:: ccode(code)
  2. :language: c
  3. 2. Adding variables to a server
  4. ===============================
  5. This tutorial shows how to add variable nodes to a server and how these can be
  6. connected to a physical process in the background. Make sure to read the
  7. :ref:`introduction <introduction>` first.
  8. This is the code for a server with a single variable node holding an integer. We
  9. will take this example to explain some of the fundamental concepts of open62541.
  10. .. literalinclude:: ../../examples/server_variable.c
  11. :language: c
  12. :linenos:
  13. :lines: 4,13,15-
  14. Variants and Datatypes
  15. ----------------------
  16. The datatype *variant* belongs to the built-in datatypes of OPC UA and is used
  17. as a container type. A variant can hold any other datatype as a scalar (except
  18. variant) or as an array. Array variants can additionally denote the
  19. dimensionality of the data (e.g. a 2x3 matrix) in an additional integer array.
  20. You can find the code that defines the variant datatype :ref:`here <variant>`.
  21. The `UA_VariableAttributes` type contains a variant member `value`. The command
  22. :ccode:`UA_Variant_setScalar(&attr.value, &myInteger,
  23. &UA_TYPES[UA_TYPES_INT32])` sets the variant to point to the integer. Note that
  24. this does not make a copy of the integer (for which `UA_Variant_setScalarCopy`
  25. can be used). The variant (and its content) is then copied into the newly
  26. created node.
  27. Since it is a bit involved to set variants by hand, there are four basic
  28. functions you should be aware of:
  29. * **UA_Variant_setScalar** will set the contents of the variant to a pointer
  30. to the object that you pass with the call. Make sure to never deallocate
  31. that object while the variant exists!
  32. * **UA_Variant_setScalarCopy** will copy the object pointed to into a new
  33. object of the same type and attach that to the variant.
  34. * **UA_Variant_setArray** will set the contents of the variant to be an array
  35. and point to the exact pointer/object that you passed the call.
  36. * **UA_Variant_setArrayCopy** will create a copy of the array passed with the
  37. call.
  38. The equivalent code using allocations is as follows:
  39. .. code-block:: c
  40. UA_VariableAttributes attr;
  41. UA_VariableAttributes_init(&attr);
  42. UA_Int32 myInteger = 42;
  43. UA_Variant_setScalarCopy(&attr.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
  44. attr.description = UA_LOCALIZEDTEXT_ALLOC("en_US","the answer");
  45. attr.displayName = UA_LOCALIZEDTEXT_ALLOC("en_US","the answer");
  46. /* add the variable node here */
  47. UA_VariableAttributes_deleteMembers(&attr); /* free the allocated memory */
  48. Finally, one needs to tell the server where to add the new variable in the
  49. information model. For that, we state the NodeId of the parent node and the
  50. (hierarchical) reference to the parent node.
  51. NodeIds
  52. -------
  53. A node ID is a unique identifier in server's context. It is composed of two members:
  54. +-------------+-----------------+---------------------------+
  55. | Type | Name | Notes |
  56. +=============+=================+===========================+
  57. | UInt16 | namespaceIndex | Number of the namespace |
  58. +-------------+-----------------+---------------------------+
  59. | Union | identifier | One idenifier of the |
  60. | | * String | listed types |
  61. | | * Integer | |
  62. | | * GUID | |
  63. | | * ByteString | |
  64. +-------------+-----------------+---------------------------+
  65. The first parameter is the number of node's namespace, the second one may be a
  66. numeric, a string or a GUID (Globally Unique ID) identifier. The following are
  67. some examples for their usage.
  68. .. code-block:: c
  69. UA_NodeId id1 = UA_NODEID_NUMERIC(1, 1234);
  70. UA_NodeId id2 = UA_NODEID_STRING(1, "testid"); /* points to the static string */
  71. UA_NodeId id3 = UA_NODEID_STRING_ALLOC(1, "testid");
  72. UA_NodeId_deleteMembers(&id3); /* free the allocated string */
  73. What is UA_NODEID_STRING_ALLOC for?
  74. Adding a variable node to the server that contains a user-defined callback
  75. --------------------------------------------------------------------------
  76. The latter case allows to define callback functions that are executed on read or
  77. write of the node. In this case an "UA_DataSource" containing the respective
  78. callback pointer is intserted into the node.
  79. Consider ``examples/server_datasource.c`` in the repository. The examples are
  80. compiled if the Cmake option UA_BUILD_EXAMPLE is turned on.
  81. UA_Server_addVariableNode vs. UA_Server_addDataSourceVariableNode
  82. UA_ValueCallback
  83. UA_DataSource
  84. Asserting success/failure
  85. -------------------------
  86. Almost all functions of the open62541 API will return a `StatusCode` 32-bit
  87. integer. The actual statuscodes are defined :ref:`here <statuscodes>`. Normally,
  88. the functions should return `UA_STATUSCODE_GOOD`, which maps to the zero
  89. integer.