forked from open62541/open62541
-
Notifications
You must be signed in to change notification settings - Fork 0
/
tutorial_datatypes.c
191 lines (160 loc) · 5.62 KB
/
tutorial_datatypes.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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
* See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
/**
* .. _types-tutorial:
*
* Working with Data Types
* -----------------------
*
* OPC UA defines a type system for values that can be encoded in the protocol
* messages. This tutorial shows some examples for available data types and
* their use. See the section on :ref:`types` for the full definitions.
*
* Basic Data Handling
* ^^^^^^^^^^^^^^^^^^^
* This section shows the basic interaction patterns for data types. Make
* sure to compare with the type definitions in ``types.h``. */
#include <open62541/plugin/log_stdout.h>
#include <open62541/server.h>
#include <open62541/server_config_default.h>
#include <stdlib.h>
static void
variables_basic(void) {
/* Int32 */
UA_Int32 i = 5;
UA_Int32 j;
UA_Int32_copy(&i, &j);
UA_Int32 *ip = UA_Int32_new();
UA_Int32_copy(&i, ip);
UA_Int32_delete(ip);
/* String */
UA_String s;
UA_String_init(&s); /* _init zeroes out the entire memory of the datatype */
char *test = "test";
s.length = strlen(test);
s.data = (UA_Byte*)test;
UA_String s2;
UA_String_copy(&s, &s2);
UA_String_clear(&s2); /* Copying heap-allocated the dynamic content */
UA_String s3 = UA_STRING("test2");
UA_String s4 = UA_STRING_ALLOC("test2"); /* Copies the content to the heap */
UA_Boolean eq = UA_String_equal(&s3, &s4);
UA_String_clear(&s4);
if(!eq)
return;
/* Structured Type */
UA_ReadRequest rr;
UA_init(&rr, &UA_TYPES[UA_TYPES_READREQUEST]); /* Generic method */
UA_ReadRequest_init(&rr); /* Shorthand for the previous line */
rr.requestHeader.timestamp = UA_DateTime_now(); /* Members of a structure */
rr.nodesToRead = (UA_ReadValueId *)UA_Array_new(5, &UA_TYPES[UA_TYPES_READVALUEID]);
rr.nodesToReadSize = 5; /* Array size needs to be made known */
UA_ReadRequest *rr2 = UA_ReadRequest_new();
UA_copy(&rr, rr2, &UA_TYPES[UA_TYPES_READREQUEST]);
UA_ReadRequest_clear(&rr);
UA_ReadRequest_delete(rr2);
}
/**
* NodeIds
* ^^^^^^^
* An OPC UA information model is made up of nodes and references between nodes.
* Every node has a unique :ref:`nodeid`. NodeIds refer to a namespace with an
* additional identifier value that can be an integer, a string, a guid or a
* bytestring. */
static void
variables_nodeids(void) {
UA_NodeId id1 = UA_NODEID_NUMERIC(1, 1234);
id1.namespaceIndex = 3;
UA_NodeId id2 = UA_NODEID_STRING(1, "testid"); /* the string is static */
UA_Boolean eq = UA_NodeId_equal(&id1, &id2);
if(eq)
return;
UA_NodeId id3;
UA_NodeId_copy(&id2, &id3);
UA_NodeId_clear(&id3);
UA_NodeId id4 = UA_NODEID_STRING_ALLOC(1, "testid"); /* the string is copied
to the heap */
UA_NodeId_clear(&id4);
}
/**
* Variants
* ^^^^^^^^
* The datatype :ref:`variant` belongs to the built-in datatypes of OPC UA and
* is used as a container type. A variant can hold any other datatype as a
* scalar (except variant) or as an array. Array variants can additionally
* denote the dimensionality of the data (e.g. a 2x3 matrix) in an additional
* integer array. */
static void
variables_variants(void) {
/* Set a scalar value */
UA_Variant v;
UA_Int32 i = 42;
UA_Variant_setScalar(&v, &i, &UA_TYPES[UA_TYPES_INT32]);
/* Make a copy */
UA_Variant v2;
UA_Variant_copy(&v, &v2);
UA_Variant_clear(&v2);
/* Set an array value */
UA_Variant v3;
UA_Double d[9] = {1.0, 2.0, 3.0,
4.0, 5.0, 6.0,
7.0, 8.0, 9.0};
UA_Variant_setArrayCopy(&v3, d, 9, &UA_TYPES[UA_TYPES_DOUBLE]);
/* Set array dimensions */
v3.arrayDimensions = (UA_UInt32 *)UA_Array_new(2, &UA_TYPES[UA_TYPES_UINT32]);
v3.arrayDimensionsSize = 2;
v3.arrayDimensions[0] = 3;
v3.arrayDimensions[1] = 3;
UA_Variant_clear(&v3);
}
#ifdef UA_ENABLE_TYPEDESCRIPTION
static void
prettyprint(void) {
UA_ReadRequest rr;
UA_ReadRequest_init(&rr);
UA_ReadValueId rvi[2];
UA_ReadValueId_init(rvi);
UA_ReadValueId_init(&rvi[1]);
rr.nodesToRead = rvi;
rr.nodesToReadSize = 2;
UA_String out = UA_STRING_NULL;
UA_print(&rr, &UA_TYPES[UA_TYPES_READREQUEST], &out);
printf("%.*s\n", (int)out.length, out.data);
UA_String_clear(&out);
UA_ReadResponse resp;
UA_ReadResponse_init(&resp);
UA_print(&resp, &UA_TYPES[UA_TYPES_READRESPONSE], &out);
printf("%.*s\n", (int)out.length, out.data);
UA_String_clear(&out);
UA_ReferenceDescription br;
UA_ReferenceDescription_init(&br);
br.nodeClass = (UA_NodeClass)5;
UA_print(&br, &UA_TYPES[UA_TYPES_REFERENCEDESCRIPTION], &out);
printf("%.*s\n", (int)out.length, out.data);
UA_String_clear(&out);
UA_Float matrix[4] = {1.0, 2.0, 3.0, 4.0};
UA_UInt32 matrix_dims[2] = {2, 2};
UA_DataValue dv;
UA_DataValue_init(&dv);
UA_Variant_setArray(&dv.value, &matrix, 4, &UA_TYPES[UA_TYPES_FLOAT]);
dv.value.arrayDimensions = matrix_dims;
dv.value.arrayDimensionsSize = 2;
dv.hasValue = true;
dv.hasStatus = true;
dv.hasServerTimestamp = true;
dv.hasSourcePicoseconds = true;
UA_print(&dv, &UA_TYPES[UA_TYPES_DATAVALUE], &out);
printf("%.*s\n", (int)out.length, out.data);
UA_String_clear(&out);
}
#endif
/** It follows the main function, making use of the above definitions. */
int main(void) {
variables_basic();
variables_nodeids();
variables_variants();
#ifdef UA_ENABLE_TYPEDESCRIPTION
prettyprint();
#endif
return EXIT_SUCCESS;
}