forked from open62541/open62541
-
Notifications
You must be signed in to change notification settings - Fork 4
/
tutorial_server_variabletype.c
142 lines (118 loc) · 5.5 KB
/
tutorial_server_variabletype.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
* See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
/**
* Working with Variable Types
* ---------------------------
*
* Variable types have three functions:
*
* - Constrain the possible data type, value rank and array dimensions of the
* variables of that type. This allows interface code to be written against
* the generic type definition, so it is applicable for all instances.
* - Provide a sensible default value
* - Enable a semantic interpretation of the variable based on its type
*
* In the example of this tutorial, we represent a point in 2D space by an array
* of double values. The following function adds the corresponding
* VariableTypeNode to the hierarchy of variable types.
*/
#include <open62541/plugin/log_stdout.h>
#include <open62541/server.h>
#include <open62541/server_config_default.h>
#include <signal.h>
#include <stdlib.h>
static UA_NodeId pointTypeId;
static void
addVariableType2DPoint(UA_Server *server) {
UA_VariableTypeAttributes vtAttr = UA_VariableTypeAttributes_default;
vtAttr.dataType = UA_TYPES[UA_TYPES_DOUBLE].typeId;
vtAttr.valueRank = UA_VALUERANK_ONE_DIMENSION;
UA_UInt32 arrayDims[1] = {2};
vtAttr.arrayDimensions = arrayDims;
vtAttr.arrayDimensionsSize = 1;
vtAttr.displayName = UA_LOCALIZEDTEXT("en-US", "2DPoint Type");
/* a matching default value is required */
UA_Double zero[2] = {0.0, 0.0};
UA_Variant_setArray(&vtAttr.value, zero, 2, &UA_TYPES[UA_TYPES_DOUBLE]);
UA_Server_addVariableTypeNode(server, UA_NODEID_NULL,
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
UA_QUALIFIEDNAME(1, "2DPoint Type"), UA_NODEID_NULL,
vtAttr, NULL, &pointTypeId);
}
/**
* Now the new variable type for *2DPoint* can be referenced during the creation
* of a new variable. If no value is given, the default from the variable type
* is copied during instantiation.
*/
static UA_NodeId pointVariableId;
static void
addVariable(UA_Server *server) {
/* Prepare the node attributes */
UA_VariableAttributes vAttr = UA_VariableAttributes_default;
vAttr.dataType = UA_TYPES[UA_TYPES_DOUBLE].typeId;
vAttr.valueRank = UA_VALUERANK_ONE_DIMENSION;
UA_UInt32 arrayDims[1] = {2};
vAttr.arrayDimensions = arrayDims;
vAttr.arrayDimensionsSize = 1;
vAttr.displayName = UA_LOCALIZEDTEXT("en-US", "2DPoint Variable");
vAttr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
/* vAttr.value is left empty, the server instantiates with the default value */
/* Add the node */
UA_Server_addVariableNode(server, UA_NODEID_NULL,
UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
UA_QUALIFIEDNAME(1, "2DPoint Type"), pointTypeId,
vAttr, NULL, &pointVariableId);
}
/**
* The constraints of the variable type are enforced when creating new variable
* instances of the type. In the following function, adding a variable of
* *2DPoint* type with a string value fails because The value does not match the
* variable type constraints. */
static void
addVariableFail(UA_Server *server) {
/* Prepare the node attributes */
UA_VariableAttributes vAttr = UA_VariableAttributes_default;
vAttr.dataType = UA_TYPES[UA_TYPES_DOUBLE].typeId;
vAttr.valueRank = UA_VALUERANK_SCALAR; /* a scalar. this is not allowed per the variable type */
vAttr.displayName = UA_LOCALIZEDTEXT("en-US", "2DPoint Variable (fail)");
UA_String s = UA_STRING("2dpoint?");
UA_Variant_setScalar(&vAttr.value, &s, &UA_TYPES[UA_TYPES_STRING]);
/* Add the node will return UA_STATUSCODE_BADTYPEMISMATCH*/
UA_Server_addVariableNode(server, UA_NODEID_NULL,
UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
UA_QUALIFIEDNAME(1, "2DPoint Type (fail)"), pointTypeId,
vAttr, NULL, NULL);
}
/**
* The constraints of the variable type are enforced when writing the datatype,
* valuerank and arraydimensions attributes of the variable. This, in turn,
* constrains the value attribute of the variable. */
static void
writeVariable(UA_Server *server) {
UA_StatusCode retval = UA_Server_writeValueRank(server, pointVariableId, UA_VALUERANK_ONE_OR_MORE_DIMENSIONS);
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
"Setting the Value Rank failed with Status Code %s",
UA_StatusCode_name(retval));
}
/** It follows the main server code, making use of the above definitions. */
static volatile UA_Boolean running = true;
static void stopHandler(int sign) {
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "received ctrl-c");
running = false;
}
int main(void) {
signal(SIGINT, stopHandler);
signal(SIGTERM, stopHandler);
UA_Server *server = UA_Server_new();
UA_ServerConfig_setDefault(UA_Server_getConfig(server));
addVariableType2DPoint(server);
addVariable(server);
addVariableFail(server);
writeVariable(server);
UA_StatusCode retval = UA_Server_run(server, &running);
UA_Server_delete(server);
return retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE;
}