forked from open62541/open62541
-
Notifications
You must be signed in to change notification settings - Fork 0
/
tutorial_server_variable.c
158 lines (134 loc) · 6.13 KB
/
tutorial_server_variable.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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
* See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
/**
* Adding Variables to a Server
* ----------------------------
*
* This tutorial shows how to work with data types and how to add variable nodes
* to a server. First, we add a new variable to the server. Take a look at the
* definition of the ``UA_VariableAttributes`` structure to see the list of all
* attributes defined for VariableNodes.
*
* Note that the default settings have the AccessLevel of the variable value as
* read only. See below for making the variable writable.
*/
#include <open62541/plugin/log_stdout.h>
#include <open62541/server.h>
#include <open62541/server_config_default.h>
#include <signal.h>
#include <stdlib.h>
static void
addVariable(UA_Server *server) {
/* Define the attribute of the myInteger variable node */
UA_VariableAttributes attr = UA_VariableAttributes_default;
UA_Int32 myInteger = 42;
UA_Variant_setScalar(&attr.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
attr.description = UA_LOCALIZEDTEXT("en-US","the answer");
attr.displayName = UA_LOCALIZEDTEXT("en-US","the answer");
attr.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
/* Add the variable node to the information model */
UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer");
UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer");
UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId,
parentReferenceNodeId, myIntegerName,
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), attr, NULL, NULL);
}
static void
addMatrixVariable(UA_Server *server) {
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("en-US", "Double Matrix");
attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
/* Set the variable value constraints */
attr.dataType = UA_TYPES[UA_TYPES_DOUBLE].typeId;
attr.valueRank = UA_VALUERANK_TWO_DIMENSIONS;
UA_UInt32 arrayDims[2] = {2,2};
attr.arrayDimensions = arrayDims;
attr.arrayDimensionsSize = 2;
/* Set the value. The array dimensions need to be the same for the value. */
UA_Double zero[4] = {0.0, 0.0, 0.0, 0.0};
UA_Variant_setArray(&attr.value, zero, 4, &UA_TYPES[UA_TYPES_DOUBLE]);
attr.value.arrayDimensions = arrayDims;
attr.value.arrayDimensionsSize = 2;
UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "double.matrix");
UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "double matrix");
UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId,
parentReferenceNodeId, myIntegerName,
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
attr, NULL, NULL);
}
/**
* Now we change the value with the write service. This uses the same service
* implementation that can also be reached over the network by an OPC UA client.
*/
static void
writeVariable(UA_Server *server) {
UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer");
/* Write a different integer value */
UA_Int32 myInteger = 43;
UA_Variant myVar;
UA_Variant_init(&myVar);
UA_Variant_setScalar(&myVar, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
UA_Server_writeValue(server, myIntegerNodeId, myVar);
/* Set the status code of the value to an error code. The function
* UA_Server_write provides access to the raw service. The above
* UA_Server_writeValue is syntactic sugar for writing a specific node
* attribute with the write service. */
UA_WriteValue wv;
UA_WriteValue_init(&wv);
wv.nodeId = myIntegerNodeId;
wv.attributeId = UA_ATTRIBUTEID_VALUE;
wv.value.status = UA_STATUSCODE_BADNOTCONNECTED;
wv.value.hasStatus = true;
UA_Server_write(server, &wv);
/* Reset the variable to a good statuscode with a value */
wv.value.hasStatus = false;
wv.value.value = myVar;
wv.value.hasValue = true;
UA_Server_write(server, &wv);
}
/**
* Note how we initially set the DataType attribute of the variable node to the
* NodeId of the Int32 data type. This forbids writing values that are not an
* Int32. The following code shows how this consistency check is performed for
* every write.
*/
static void
writeWrongVariable(UA_Server *server) {
UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer");
/* Write a string */
UA_String myString = UA_STRING("test");
UA_Variant myVar;
UA_Variant_init(&myVar);
UA_Variant_setScalar(&myVar, &myString, &UA_TYPES[UA_TYPES_STRING]);
UA_StatusCode retval = UA_Server_writeValue(server, myIntegerNodeId, myVar);
printf("Writing a string returned statuscode %s\n", 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));
UA_ServerConfig* config = UA_Server_getConfig(server);
config->verifyRequestTimestamp = UA_RULEHANDLING_ACCEPT;
#ifdef UA_ENABLE_WEBSOCKET_SERVER
UA_ServerConfig_addNetworkLayerWS(UA_Server_getConfig(server), 7681, 0, 0, NULL, NULL);
#endif
addVariable(server);
addMatrixVariable(server);
writeVariable(server);
writeWrongVariable(server);
UA_StatusCode retval = UA_Server_run(server, &running);
UA_Server_delete(server);
return retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE;
}