opcua 0.8 → 0.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/cert/cert.h +52 -52
- data/cert/cert_key.h +99 -99
- data/example/server.rb +53 -31
- data/ext/opcua/client/client.c +24 -20
- data/ext/opcua/client/client.h +2 -3
- data/ext/opcua/server/server.c +301 -123
- data/ext/opcua/server/server.h +6 -3
- data/ext/opcua/values.h +15 -1
- data/opcua.gemspec +1 -1
- metadata +2 -2
data/ext/opcua/client/client.h
CHANGED
@@ -2,11 +2,10 @@
|
|
2
2
|
#include <stdio.h>
|
3
3
|
#include <open62541.h>
|
4
4
|
#include "../log_none.h"
|
5
|
-
#include "../values.h"
|
6
5
|
|
7
6
|
typedef struct client_struct {
|
8
7
|
UA_ClientConfig *config;
|
9
|
-
UA_Client *
|
8
|
+
UA_Client *master;
|
10
9
|
UA_CreateSubscriptionRequest subscription_request;
|
11
10
|
UA_CreateSubscriptionResponse subscription_response;
|
12
11
|
|
@@ -19,7 +18,7 @@ typedef struct client_struct {
|
|
19
18
|
} client_struct;
|
20
19
|
|
21
20
|
typedef struct node_struct {
|
22
|
-
client_struct *
|
21
|
+
client_struct *master;
|
23
22
|
VALUE on_change;
|
24
23
|
UA_NodeId id;
|
25
24
|
} node_struct;
|
data/ext/opcua/server/server.c
CHANGED
@@ -7,9 +7,73 @@ VALUE cTypesTopNode = Qnil;
|
|
7
7
|
VALUE cTypesSubNode = Qnil;
|
8
8
|
VALUE cLeafNode = Qnil;
|
9
9
|
|
10
|
+
#include "../values.h"
|
11
|
+
|
12
|
+
int nodecounter = 2000;
|
13
|
+
|
14
|
+
/* -- */
|
15
|
+
static void set_node_to_value(node_struct *ns, VALUE value) { //{{{
|
16
|
+
UA_Variant variant;
|
17
|
+
if (rb_obj_is_kind_of(value,rb_cTime)) {
|
18
|
+
UA_DateTime tmp = UA_DateTime_fromUnixTime(rb_time_timeval(value).tv_sec);
|
19
|
+
UA_Variant_setScalar(&variant, &tmp, &UA_TYPES[UA_TYPES_DATETIME]);
|
20
|
+
UA_Server_writeValue(ns->master->master, ns->id, variant);
|
21
|
+
} else {
|
22
|
+
switch (TYPE(value)) {
|
23
|
+
case T_FALSE:
|
24
|
+
{
|
25
|
+
UA_Boolean tmp = false;
|
26
|
+
UA_Variant_setScalar(&variant, &tmp, &UA_TYPES[UA_TYPES_BOOLEAN]);
|
27
|
+
UA_Server_writeValue(ns->master->master, ns->id, variant);
|
28
|
+
break;
|
29
|
+
}
|
30
|
+
case T_TRUE:
|
31
|
+
{
|
32
|
+
UA_Boolean tmp = true;
|
33
|
+
UA_Variant_setScalar(&variant, &tmp, &UA_TYPES[UA_TYPES_BOOLEAN]);
|
34
|
+
UA_Server_writeValue(ns->master->master, ns->id, variant);
|
35
|
+
break;
|
36
|
+
}
|
37
|
+
case T_FLOAT:
|
38
|
+
case T_FIXNUM:
|
39
|
+
{
|
40
|
+
UA_Double tmp = NUM2DBL(value);
|
41
|
+
UA_Variant_setScalar(&variant, &tmp, &UA_TYPES[UA_TYPES_DOUBLE]);
|
42
|
+
UA_Server_writeValue(ns->master->master, ns->id, variant);
|
43
|
+
break;
|
44
|
+
}
|
45
|
+
case T_STRING:
|
46
|
+
case T_SYMBOL:
|
47
|
+
{
|
48
|
+
VALUE str = rb_obj_as_string(value);
|
49
|
+
if (NIL_P(str) || TYPE(str) != T_STRING)
|
50
|
+
rb_raise(rb_eTypeError, "cannot convert obj to string");
|
51
|
+
UA_String tmp = UA_STRING(StringValuePtr(str));
|
52
|
+
UA_Variant_setScalar(&variant, &tmp, &UA_TYPES[UA_TYPES_STRING]);
|
53
|
+
UA_Server_writeValue(ns->master->master, ns->id, variant);
|
54
|
+
break;
|
55
|
+
}
|
56
|
+
case T_ARRAY:
|
57
|
+
{
|
58
|
+
// UA_UInt32 arrayDims = 0;
|
59
|
+
// attr.valueRank = UA_VALUERANK_ONE_DIMENSION;
|
60
|
+
// attr.arrayDimensions = &arrayDims;
|
61
|
+
// attr.arrayDimensionsSize = 1;
|
62
|
+
// UA_Variant_setArray(&attr.value, UA_Array_new(10, &UA_TYPES[type]), 10, &UA_TYPES[type]);
|
63
|
+
}
|
64
|
+
}
|
65
|
+
}
|
66
|
+
} //}}}
|
67
|
+
/* ++ */
|
68
|
+
|
10
69
|
/* -- */
|
11
70
|
static void node_free(node_struct *ns) { //{{{
|
12
|
-
if (ns != NULL) {
|
71
|
+
if (ns != NULL) {
|
72
|
+
if (!NIL_P(ns->method)) {
|
73
|
+
rb_gc_unregister_address(&ns->method);
|
74
|
+
}
|
75
|
+
free(ns);
|
76
|
+
}
|
13
77
|
} //}}}
|
14
78
|
static node_struct * node_alloc(server_struct *server, UA_NodeId nodeid) { //{{{
|
15
79
|
node_struct *ns;
|
@@ -17,8 +81,9 @@ static node_struct * node_alloc(server_struct *server, UA_NodeId nodeid) { //{{{
|
|
17
81
|
if (ns == NULL)
|
18
82
|
rb_raise(rb_eNoMemError, "No memory left for node.");
|
19
83
|
|
20
|
-
ns->
|
21
|
-
ns->id
|
84
|
+
ns->master = server;
|
85
|
+
ns->id = nodeid;
|
86
|
+
ns->method = Qnil;
|
22
87
|
|
23
88
|
return ns;
|
24
89
|
} //}}}
|
@@ -30,7 +95,7 @@ static VALUE node_wrap(VALUE klass, node_struct *ns) { //{{{
|
|
30
95
|
static VALUE node_type_folder(VALUE self) { //{{{
|
31
96
|
node_struct *ns;
|
32
97
|
Data_Get_Struct(self, node_struct, ns);
|
33
|
-
return node_wrap(cTypesTopNode, node_alloc(ns->
|
98
|
+
return node_wrap(cTypesTopNode, node_alloc(ns->master, UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE)));
|
34
99
|
} //}}}
|
35
100
|
static VALUE node_add_object_type(VALUE self, VALUE name) { //{{{
|
36
101
|
node_struct *ns;
|
@@ -42,20 +107,20 @@ static VALUE node_add_object_type(VALUE self, VALUE name) { //{{{
|
|
42
107
|
rb_raise(rb_eTypeError, "cannot convert obj to string");
|
43
108
|
char *nstr = (char *)StringValuePtr(str);
|
44
109
|
|
45
|
-
UA_NodeId n =
|
110
|
+
UA_NodeId n = UA_NODEID_NUMERIC(ns->master->default_ns, nodecounter++);
|
46
111
|
|
47
112
|
UA_ObjectTypeAttributes dtAttr = UA_ObjectTypeAttributes_default;
|
48
113
|
dtAttr.displayName = UA_LOCALIZEDTEXT("en-US", nstr);
|
49
|
-
UA_Server_addObjectTypeNode(ns->
|
114
|
+
UA_Server_addObjectTypeNode(ns->master->master,
|
50
115
|
n,
|
51
116
|
ns->id,
|
52
117
|
UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
|
53
|
-
UA_QUALIFIEDNAME(ns->
|
118
|
+
UA_QUALIFIEDNAME(ns->master->default_ns, nstr),
|
54
119
|
dtAttr,
|
55
120
|
NULL,
|
56
121
|
NULL);
|
57
122
|
|
58
|
-
return node_wrap(cTypesSubNode,node_alloc(ns->
|
123
|
+
return node_wrap(cTypesSubNode,node_alloc(ns->master,n));
|
59
124
|
} //}}}
|
60
125
|
|
61
126
|
static VALUE node_to_s(VALUE self) { //{{{
|
@@ -73,23 +138,141 @@ static VALUE node_to_s(VALUE self) { //{{{
|
|
73
138
|
}
|
74
139
|
return ret;
|
75
140
|
} //}}}
|
141
|
+
static UA_StatusCode node_add_method_callback(
|
142
|
+
UA_Server *server,
|
143
|
+
const UA_NodeId *sessionId, void *sessionContext,
|
144
|
+
const UA_NodeId *methodId, void *methodContext,
|
145
|
+
const UA_NodeId *objectId, void *objectContext,
|
146
|
+
size_t inputSize, const UA_Variant *input,
|
147
|
+
size_t outputSize, UA_Variant *output
|
148
|
+
) {
|
149
|
+
node_struct *me = (node_struct *)methodContext;
|
150
|
+
|
151
|
+
// printf(
|
152
|
+
// "NodeId %d, %-16.*s\n",
|
153
|
+
// me->id.namespaceIndex,
|
154
|
+
// (int)me->id.identifier.string.length,
|
155
|
+
// me->id.identifier.string.data
|
156
|
+
// );
|
157
|
+
|
158
|
+
VALUE args = rb_ary_new();
|
159
|
+
rb_ary_push(args, Data_Wrap_Struct(cObjectsNode,NULL,NULL,me));
|
160
|
+
for (int i = 0; i < inputSize; i++) {
|
161
|
+
VALUE ret = extract_value(input[i]);
|
162
|
+
rb_ary_push(args,rb_ary_entry(ret,0));
|
163
|
+
}
|
76
164
|
|
77
|
-
|
78
|
-
|
165
|
+
rb_proc_call(me->method,args);
|
166
|
+
|
167
|
+
return UA_STATUSCODE_GOOD;
|
168
|
+
}
|
169
|
+
static UA_NodeId node_add_method_ua(UA_NodeId n, UA_LocalizedText dn, UA_QualifiedName qn, node_struct *parent,size_t inputArgumentsSize,const UA_Argument *inputArguments, VALUE blk) { //{{{
|
170
|
+
UA_MethodAttributes mnAttr = UA_MethodAttributes_default;
|
79
171
|
mnAttr.displayName = dn;
|
172
|
+
mnAttr.executable = true;
|
173
|
+
mnAttr.userExecutable = true;
|
174
|
+
|
175
|
+
node_struct *me = node_alloc(parent->master,n);
|
176
|
+
me->method = blk;
|
177
|
+
rb_gc_register_address(&blk);
|
178
|
+
rb_gc_register_address(&me->method);
|
179
|
+
|
180
|
+
UA_Server_addMethodNode(parent->master->master,
|
181
|
+
n,
|
182
|
+
parent->id,
|
183
|
+
UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
|
184
|
+
qn,
|
185
|
+
mnAttr,
|
186
|
+
&node_add_method_callback,
|
187
|
+
inputArgumentsSize,
|
188
|
+
inputArguments,
|
189
|
+
0,
|
190
|
+
NULL,
|
191
|
+
(void *)me,
|
192
|
+
NULL);
|
193
|
+
|
194
|
+
|
195
|
+
UA_Server_addReference(parent->master->master,
|
196
|
+
n,
|
197
|
+
UA_NODEID_NUMERIC(0, UA_NS0ID_HASMODELLINGRULE),
|
198
|
+
UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_MODELLINGRULE_MANDATORY),
|
199
|
+
true);
|
200
|
+
|
201
|
+
return n;
|
202
|
+
} //}}}
|
203
|
+
static UA_NodeId node_add_method_ua_simple(char* nstr, node_struct *parent, VALUE opts, VALUE blk) { //{{{
|
204
|
+
UA_Argument inputArguments[RHASH_SIZE(opts)];
|
205
|
+
|
206
|
+
VALUE ary = rb_funcall(opts, rb_intern("to_a"), 0);
|
207
|
+
for (long i=0; i<RARRAY_LEN(ary); i++) {
|
208
|
+
VALUE item = RARRAY_AREF(ary, i);
|
209
|
+
VALUE str = rb_obj_as_string(RARRAY_AREF(item, 0));
|
210
|
+
if (NIL_P(str) || TYPE(str) != T_STRING)
|
211
|
+
rb_raise(rb_eTypeError, "cannot convert obj to string");
|
212
|
+
char *nstr = (char *)StringValuePtr(str);
|
213
|
+
UA_Argument_init(&inputArguments[i]);
|
214
|
+
inputArguments[i].description = UA_LOCALIZEDTEXT("en-US", nstr);
|
215
|
+
inputArguments[i].name = UA_STRING(nstr);
|
216
|
+
inputArguments[i].dataType = UA_TYPES[NUM2INT(RARRAY_AREF(item, 1))].typeId;
|
217
|
+
inputArguments[i].valueRank = UA_VALUERANK_SCALAR;
|
218
|
+
}
|
219
|
+
int nodeid = nodecounter++;
|
220
|
+
|
221
|
+
rb_hash_aset(parent->master->methods,INT2NUM(nodeid),blk);
|
222
|
+
rb_gc_register_address(&blk);
|
223
|
+
|
224
|
+
return node_add_method_ua(
|
225
|
+
UA_NODEID_NUMERIC(parent->master->default_ns,nodeid),
|
226
|
+
UA_LOCALIZEDTEXT("en-US", nstr),
|
227
|
+
UA_QUALIFIEDNAME(parent->master->default_ns, nstr),
|
228
|
+
parent,
|
229
|
+
RHASH_SIZE(opts),
|
230
|
+
inputArguments,
|
231
|
+
blk
|
232
|
+
);
|
233
|
+
} //}}}
|
234
|
+
static VALUE node_add_method(int argc, VALUE* argv, VALUE self) { //{{{
|
235
|
+
node_struct *parent;
|
236
|
+
|
237
|
+
VALUE name;
|
238
|
+
VALUE opts;
|
239
|
+
VALUE blk;
|
240
|
+
rb_gc_register_address(&blk);
|
241
|
+
|
242
|
+
if (argc < 1) { // there should be 1 or more arguments
|
243
|
+
rb_raise(rb_eArgError, "wrong number of arguments");
|
244
|
+
}
|
245
|
+
rb_scan_args(argc, argv, "1:&", &name, &opts, &blk);
|
246
|
+
if (NIL_P(opts)) opts = rb_hash_new();
|
247
|
+
|
248
|
+
Data_Get_Struct(self, node_struct, parent);
|
249
|
+
|
250
|
+
VALUE str = rb_obj_as_string(name);
|
251
|
+
if (NIL_P(str) || TYPE(str) != T_STRING)
|
252
|
+
rb_raise(rb_eTypeError, "cannot convert obj to string");
|
253
|
+
char *nstr = (char *)StringValuePtr(str);
|
254
|
+
|
255
|
+
return node_wrap(CLASS_OF(self),node_alloc(parent->master,node_add_method_ua_simple(nstr,parent,opts,blk)));
|
256
|
+
} //}}}
|
257
|
+
|
258
|
+
static UA_NodeId node_add_variable_ua(UA_Int32 type, UA_NodeId n, UA_LocalizedText dn, UA_QualifiedName qn, node_struct *parent, VALUE ref, UA_Byte accesslevelmask) { //{{{
|
259
|
+
UA_VariableAttributes vAttr = UA_VariableAttributes_default;
|
260
|
+
vAttr.displayName = dn;
|
261
|
+
|
262
|
+
vAttr.accessLevel = accesslevelmask;
|
80
263
|
|
81
|
-
UA_Server_addVariableNode(parent->
|
264
|
+
UA_Server_addVariableNode(parent->master->master,
|
82
265
|
n,
|
83
266
|
parent->id,
|
84
267
|
UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
|
85
268
|
qn,
|
86
269
|
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
|
87
|
-
|
270
|
+
vAttr,
|
88
271
|
NULL,
|
89
272
|
NULL);
|
90
273
|
|
91
274
|
if (ref != Qnil) {
|
92
|
-
UA_Server_addReference(parent->
|
275
|
+
UA_Server_addReference(parent->master->master,
|
93
276
|
n,
|
94
277
|
UA_NODEID_NUMERIC(0, UA_NS0ID_HASMODELLINGRULE),
|
95
278
|
UA_EXPANDEDNODEID_NUMERIC(0, type),
|
@@ -99,20 +282,21 @@ static UA_NodeId node_add_variable_ua(UA_Int32 type, UA_NodeId n, UA_LocalizedTe
|
|
99
282
|
return n;
|
100
283
|
|
101
284
|
} //}}}
|
102
|
-
static UA_NodeId node_add_variable_ua_simple(UA_Int32 type, char* nstr, node_struct *parent, VALUE ref) { //{{{
|
285
|
+
static UA_NodeId node_add_variable_ua_simple(UA_Int32 type, char* nstr, node_struct *parent, VALUE ref, UA_Byte accesslevelmask,bool numeric) { //{{{
|
103
286
|
return node_add_variable_ua(
|
104
287
|
type,
|
105
|
-
UA_NODEID_STRING(parent->
|
288
|
+
numeric ? UA_NODEID_NUMERIC(parent->master->default_ns,nodecounter++) : UA_NODEID_STRING(parent->master->default_ns,nstr),
|
106
289
|
UA_LOCALIZEDTEXT("en-US", nstr),
|
107
|
-
UA_QUALIFIEDNAME(parent->
|
290
|
+
UA_QUALIFIEDNAME(parent->master->default_ns, nstr),
|
108
291
|
parent,
|
109
|
-
ref
|
292
|
+
ref,
|
293
|
+
accesslevelmask
|
110
294
|
);
|
111
295
|
} //}}}
|
112
|
-
static VALUE
|
296
|
+
static VALUE node_add_variable_wrap(int argc, VALUE* argv, VALUE self, UA_Byte accesslevelmask,bool numeric) { //{{{
|
113
297
|
node_struct *parent;
|
114
298
|
|
115
|
-
if (argc > 2 || argc == 0) {
|
299
|
+
if (argc > 2 || argc == 0) { // there should only be 1 or 2 arguments
|
116
300
|
rb_raise(rb_eArgError, "wrong number of arguments");
|
117
301
|
}
|
118
302
|
|
@@ -130,18 +314,20 @@ static VALUE node_add_variable(int argc, VALUE* argv, VALUE self) { //{{{
|
|
130
314
|
rb_raise(rb_eTypeError, "cannot convert obj to string");
|
131
315
|
char *nstr = (char *)StringValuePtr(str);
|
132
316
|
|
133
|
-
return node_wrap(cLeafNode,node_alloc(parent->
|
317
|
+
return node_wrap(cLeafNode,node_alloc(parent->master,node_add_variable_ua_simple(type,nstr,parent,argv[1],accesslevelmask,numeric)));
|
134
318
|
} //}}}
|
135
|
-
static VALUE
|
136
|
-
|
137
|
-
|
319
|
+
static VALUE node_add_variable(int argc, VALUE* argv, VALUE self) { //{{{
|
320
|
+
return node_add_variable_wrap(argc,argv,self,UA_ACCESSLEVELMASK_READ,true);
|
321
|
+
} //}}}
|
322
|
+
static VALUE node_add_variable_rw(int argc, VALUE* argv, VALUE self) { //{{{
|
323
|
+
return node_add_variable_wrap(argc,argv,self,UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE,true);
|
138
324
|
} //}}}
|
139
325
|
|
140
326
|
static UA_NodeId node_add_object_ua(UA_Int32 type, UA_NodeId n, UA_LocalizedText dn, UA_QualifiedName qn, node_struct *parent, node_struct *datatype, VALUE ref) { //{{{
|
141
327
|
UA_ObjectAttributes oAttr = UA_ObjectAttributes_default;
|
142
328
|
oAttr.displayName = dn;
|
143
329
|
|
144
|
-
UA_Server_addObjectNode(parent->
|
330
|
+
UA_Server_addObjectNode(parent->master->master,
|
145
331
|
n,
|
146
332
|
parent->id,
|
147
333
|
UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
|
@@ -152,7 +338,7 @@ static UA_NodeId node_add_object_ua(UA_Int32 type, UA_NodeId n, UA_LocalizedText
|
|
152
338
|
NULL);
|
153
339
|
|
154
340
|
if (ref != Qnil) {
|
155
|
-
UA_Server_addReference(parent->
|
341
|
+
UA_Server_addReference(parent->master->master,
|
156
342
|
n,
|
157
343
|
UA_NODEID_NUMERIC(0, UA_NS0ID_HASMODELLINGRULE),
|
158
344
|
UA_EXPANDEDNODEID_NUMERIC(0, type),
|
@@ -164,9 +350,9 @@ static UA_NodeId node_add_object_ua(UA_Int32 type, UA_NodeId n, UA_LocalizedText
|
|
164
350
|
static UA_NodeId node_add_object_ua_simple(UA_Int32 type, char* nstr, node_struct *parent, node_struct *datatype, VALUE ref) { //{{{
|
165
351
|
return node_add_object_ua(
|
166
352
|
type,
|
167
|
-
UA_NODEID_STRING(parent->
|
353
|
+
UA_NODEID_STRING(parent->master->default_ns,nstr),
|
168
354
|
UA_LOCALIZEDTEXT("en-US", nstr),
|
169
|
-
UA_QUALIFIEDNAME(parent->
|
355
|
+
UA_QUALIFIEDNAME(parent->master->default_ns, nstr),
|
170
356
|
parent,
|
171
357
|
datatype,
|
172
358
|
ref
|
@@ -176,7 +362,7 @@ static VALUE node_add_object(int argc, VALUE* argv, VALUE self) { //{{{
|
|
176
362
|
node_struct *parent;
|
177
363
|
node_struct *datatype;
|
178
364
|
|
179
|
-
if (argc > 3 || argc < 2) {
|
365
|
+
if (argc > 3 || argc < 2) { // there should only be 2 or 3 arguments
|
180
366
|
rb_raise(rb_eArgError, "wrong number of arguments");
|
181
367
|
}
|
182
368
|
|
@@ -199,11 +385,7 @@ static VALUE node_add_object(int argc, VALUE* argv, VALUE self) { //{{{
|
|
199
385
|
rb_raise(rb_eTypeError, "cannot convert obj to string");
|
200
386
|
char *nstr = (char *)StringValuePtr(str);
|
201
387
|
|
202
|
-
return node_wrap(CLASS_OF(self),node_alloc(parent->
|
203
|
-
} //}}}
|
204
|
-
static VALUE node_add_object_without(VALUE self, VALUE name, VALUE parent) { //{{{
|
205
|
-
VALUE argv[] = { name, parent, Qnil };
|
206
|
-
return node_add_object(3,argv,self);
|
388
|
+
return node_wrap(CLASS_OF(self),node_alloc(parent->master,node_add_object_ua_simple(type,nstr,parent,datatype,argv[2])));
|
207
389
|
} //}}}
|
208
390
|
|
209
391
|
static UA_BrowsePathResult node_browse_path(UA_Server *server, UA_NodeId relative, UA_NodeId ref, UA_QualifiedName mqn) { //{{{
|
@@ -228,7 +410,7 @@ static bool node_get_reference(UA_Server *server, UA_NodeId parent, UA_NodeId *r
|
|
228
410
|
UA_BrowseDescription_init(&bDes);
|
229
411
|
bDes.nodeId = parent;
|
230
412
|
bDes.resultMask = UA_BROWSERESULTMASK_ALL;
|
231
|
-
UA_BrowseResult bRes = UA_Server_browse(server,
|
413
|
+
UA_BrowseResult bRes = UA_Server_browse(server, 3, &bDes);
|
232
414
|
|
233
415
|
if (bRes.referencesSize > 0) {
|
234
416
|
UA_ReferenceDescription *ref = &(bRes.references[0]);
|
@@ -247,7 +429,7 @@ static UA_StatusCode node_manifest_iter(UA_NodeId child_id, UA_Boolean is_invers
|
|
247
429
|
node_struct *parent = tandle[0];
|
248
430
|
node_struct *newnode = tandle[1];
|
249
431
|
|
250
|
-
if (child_id.namespaceIndex == parent->
|
432
|
+
if (child_id.namespaceIndex == parent->master->default_ns) {
|
251
433
|
UA_NodeClass nc; UA_NodeClass_init(&nc);
|
252
434
|
|
253
435
|
UA_LocalizedText dn; UA_LocalizedText_init(&dn);
|
@@ -255,11 +437,14 @@ static UA_StatusCode node_manifest_iter(UA_NodeId child_id, UA_Boolean is_invers
|
|
255
437
|
UA_QualifiedName pqn; UA_QualifiedName_init(&pqn);
|
256
438
|
UA_QualifiedName nqn; UA_QualifiedName_init(&nqn);
|
257
439
|
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
UA_Server_readBrowseName(parent->
|
262
|
-
|
440
|
+
UA_Byte al; UA_Byte_init(&al);
|
441
|
+
|
442
|
+
UA_Server_readNodeClass(parent->master->master, child_id, &nc);
|
443
|
+
UA_Server_readBrowseName(parent->master->master, child_id, &qn);
|
444
|
+
UA_Server_readDisplayName(parent->master->master, child_id, &dn);
|
445
|
+
UA_Server_readAccessLevel(parent->master->master, child_id, &al);
|
446
|
+
UA_Server_readBrowseName(parent->master->master, parent->id, &pqn);
|
447
|
+
UA_Server_readBrowseName(parent->master->master, newnode->id, &nqn);
|
263
448
|
|
264
449
|
// printf("%d ---> NodeId %d, %-16.*s, %-16.*s, ref: %d, nc: %d\n",
|
265
450
|
// reference_type_id.identifier.numeric,
|
@@ -272,13 +457,13 @@ static UA_StatusCode node_manifest_iter(UA_NodeId child_id, UA_Boolean is_invers
|
|
272
457
|
// nc
|
273
458
|
// );
|
274
459
|
|
275
|
-
if (child_id.namespaceIndex == parent->
|
460
|
+
if (child_id.namespaceIndex == parent->master->default_ns) {
|
276
461
|
UA_QualifiedName mqn;UA_QualifiedName_init(&mqn);
|
277
|
-
UA_Server_readBrowseName(parent->
|
462
|
+
UA_Server_readBrowseName(parent->master->master, UA_NODEID_NUMERIC(0, UA_NS0ID_MODELLINGRULE_MANDATORY), &mqn);
|
278
463
|
|
279
|
-
UA_BrowsePathResult mandatory = node_browse_path(parent->
|
464
|
+
UA_BrowsePathResult mandatory = node_browse_path(parent->master->master, child_id, UA_NODEID_NUMERIC(0, UA_NS0ID_HASMODELLINGRULE), mqn);
|
280
465
|
|
281
|
-
if (mandatory.statusCode == UA_STATUSCODE_GOOD && (nc == UA_NODECLASS_OBJECT || nc == UA_NODECLASS_VARIABLE)) {
|
466
|
+
if (mandatory.statusCode == UA_STATUSCODE_GOOD && (nc == UA_NODECLASS_OBJECT || nc == UA_NODECLASS_VARIABLE || nc == UA_NODECLASS_METHOD)) {
|
282
467
|
char * buffer = strnautocat(NULL,"",0);
|
283
468
|
if (newnode->id.identifier.string.data[0] != '/') {
|
284
469
|
buffer = strnautocat(buffer,"/",1);
|
@@ -288,16 +473,16 @@ static UA_StatusCode node_manifest_iter(UA_NodeId child_id, UA_Boolean is_invers
|
|
288
473
|
buffer = strnautocat(buffer,(char *)qn.name.data,qn.name.length);
|
289
474
|
if(nc == UA_NODECLASS_OBJECT) {
|
290
475
|
UA_NodeId typeid;
|
291
|
-
node_get_reference(parent->
|
476
|
+
node_get_reference(parent->master->master, child_id, &typeid);
|
292
477
|
|
293
|
-
node_struct *thetype = node_alloc(parent->
|
294
|
-
node_struct *downnode = node_alloc(parent->
|
478
|
+
node_struct *thetype = node_alloc(parent->master,typeid);
|
479
|
+
node_struct *downnode = node_alloc(parent->master,node_add_object_ua(UA_NS0ID_MODELLINGRULE_MANDATORY,UA_NODEID_STRING(parent->master->default_ns,buffer),dn,qn,newnode,thetype,Qtrue));
|
295
480
|
|
296
|
-
node_struct *newparent = node_alloc(parent->
|
481
|
+
node_struct *newparent = node_alloc(parent->master,child_id);
|
297
482
|
node_struct *downhandle[2] = { newparent, downnode };
|
298
483
|
|
299
484
|
// printf("---->\n");
|
300
|
-
UA_Server_forEachChildNodeCall(parent->
|
485
|
+
UA_Server_forEachChildNodeCall(parent->master->master, child_id, node_manifest_iter, (void *)downhandle);
|
301
486
|
// printf("<----\n");
|
302
487
|
|
303
488
|
free(thetype);
|
@@ -305,7 +490,20 @@ static UA_StatusCode node_manifest_iter(UA_NodeId child_id, UA_Boolean is_invers
|
|
305
490
|
free(newparent);
|
306
491
|
}
|
307
492
|
if(nc == UA_NODECLASS_VARIABLE) {
|
308
|
-
node_add_variable_ua(UA_NS0ID_MODELLINGRULE_MANDATORY,UA_NODEID_STRING(parent->
|
493
|
+
node_add_variable_ua(UA_NS0ID_MODELLINGRULE_MANDATORY,UA_NODEID_STRING(parent->master->default_ns,buffer),dn,qn,newnode,Qtrue,al);
|
494
|
+
}
|
495
|
+
if(nc == UA_NODECLASS_METHOD) {
|
496
|
+
UA_NodeId ttt;
|
497
|
+
VALUE blk = rb_hash_aref(parent->master->methods,INT2NUM(child_id.identifier.numeric));
|
498
|
+
if (node_get_reference(parent->master->master, child_id, &ttt)) {
|
499
|
+
UA_Variant arv; UA_Variant_init(&arv);
|
500
|
+
UA_Server_readValue(parent->master->master, ttt, &arv);
|
501
|
+
|
502
|
+
node_add_method_ua(UA_NODEID_STRING(parent->master->default_ns,buffer),dn,qn,newnode,arv.arrayLength,(UA_Argument *)arv.data,blk);
|
503
|
+
UA_Variant_clear(&arv);
|
504
|
+
} else {
|
505
|
+
node_add_method_ua(UA_NODEID_STRING(parent->master->default_ns,buffer),dn,qn,newnode,0,NULL,blk);
|
506
|
+
}
|
309
507
|
}
|
310
508
|
}
|
311
509
|
UA_BrowsePathResult_clear(&mandatory);
|
@@ -313,6 +511,7 @@ static UA_StatusCode node_manifest_iter(UA_NodeId child_id, UA_Boolean is_invers
|
|
313
511
|
}
|
314
512
|
|
315
513
|
UA_NodeClass_clear(&nc);
|
514
|
+
UA_Byte_clear(&al);
|
316
515
|
UA_QualifiedName_clear(&qn);
|
317
516
|
UA_QualifiedName_clear(&pqn);
|
318
517
|
UA_LocalizedText_clear(&dn);
|
@@ -337,33 +536,33 @@ static VALUE node_manifest(VALUE self, VALUE name, VALUE parent) { //{{{
|
|
337
536
|
|
338
537
|
char *nidstr = strnautocat(NULL,"",1);
|
339
538
|
if (ns->id.identifierType == UA_NODEIDTYPE_STRING) {
|
340
|
-
nidstr = strnautocat(nidstr,ns->id.identifier.string.data,ns->id.identifier.string.length);
|
539
|
+
nidstr = strnautocat(nidstr,(char *)ns->id.identifier.string.data,ns->id.identifier.string.length);
|
341
540
|
nidstr = strnautocat(nidstr,"/",1);
|
342
541
|
}
|
343
542
|
nidstr = strnautocat(nidstr,nstr,strlen(nstr));
|
344
543
|
|
345
|
-
UA_NodeId n = UA_NODEID_STRING(ns->
|
544
|
+
UA_NodeId n = UA_NODEID_STRING(ns->master->default_ns, nidstr);
|
346
545
|
|
347
546
|
UA_ObjectAttributes oAttr = UA_ObjectAttributes_default;
|
348
547
|
oAttr.displayName = UA_LOCALIZEDTEXT("en-US", nstr);
|
349
548
|
|
350
|
-
UA_Server_addNode_begin(ns->
|
549
|
+
UA_Server_addNode_begin(ns->master->master,
|
351
550
|
UA_NODECLASS_OBJECT,
|
352
551
|
n,
|
353
552
|
ns->id,
|
354
553
|
UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
|
355
|
-
UA_QUALIFIEDNAME(ns->
|
554
|
+
UA_QUALIFIEDNAME(ns->master->default_ns, nstr),
|
356
555
|
ts->id,
|
357
556
|
(const UA_NodeAttributes*)&oAttr,
|
358
557
|
&UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],
|
359
558
|
NULL,
|
360
559
|
NULL);
|
361
560
|
|
362
|
-
node_struct *ret = node_alloc(ns->
|
561
|
+
node_struct *ret = node_alloc(ns->master,n);
|
363
562
|
node_struct *handle[2] = { ts, ret };
|
364
|
-
UA_Server_forEachChildNodeCall(ns->
|
563
|
+
UA_Server_forEachChildNodeCall(ns->master->master, ts->id, node_manifest_iter, (void *)handle);
|
365
564
|
|
366
|
-
UA_Server_addNode_finish(ns->
|
565
|
+
UA_Server_addNode_finish(ns->master->master,n);
|
367
566
|
|
368
567
|
return Data_Wrap_Struct(CLASS_OF(self), NULL, node_free, ret);
|
369
568
|
} //}}}
|
@@ -378,7 +577,7 @@ static VALUE node_find(VALUE self, VALUE qname) { //{{{
|
|
378
577
|
rb_raise(rb_eTypeError, "cannot convert obj to string");
|
379
578
|
char *nstr = (char *)StringValuePtr(str);
|
380
579
|
|
381
|
-
UA_BrowsePathResult bpr = node_browse_path(ns->
|
580
|
+
UA_BrowsePathResult bpr = node_browse_path(ns->master->master, ns->id, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), UA_QUALIFIEDNAME(ns->master->default_ns, nstr));
|
382
581
|
|
383
582
|
if(bpr.statusCode != UA_STATUSCODE_GOOD || bpr.targetsSize < 1) {
|
384
583
|
return Qnil;
|
@@ -386,66 +585,14 @@ static VALUE node_find(VALUE self, VALUE qname) { //{{{
|
|
386
585
|
UA_NodeId ret;UA_NodeId_init(&ret);
|
387
586
|
UA_NodeId_copy(&bpr.targets[0].targetId.nodeId,&ret);
|
388
587
|
UA_BrowsePathResult_clear(&bpr);
|
389
|
-
return node_wrap(CLASS_OF(self),node_alloc(ns->
|
588
|
+
return node_wrap(CLASS_OF(self),node_alloc(ns->master,ret));
|
390
589
|
}
|
391
590
|
} //}}}
|
392
591
|
|
393
592
|
static VALUE node_value_set(VALUE self, VALUE value) { //{{{
|
394
593
|
node_struct *ns;
|
395
|
-
|
396
594
|
Data_Get_Struct(self, node_struct, ns);
|
397
|
-
|
398
|
-
UA_Variant variant;
|
399
|
-
if (rb_obj_is_kind_of(value,rb_cTime)) {
|
400
|
-
UA_DateTime tmp = UA_DateTime_fromUnixTime(rb_time_timeval(value).tv_sec);
|
401
|
-
UA_Variant_setScalar(&variant, &tmp, &UA_TYPES[UA_TYPES_DATETIME]);
|
402
|
-
UA_Server_writeValue(ns->server->server, ns->id, variant);
|
403
|
-
} else {
|
404
|
-
switch (TYPE(value)) {
|
405
|
-
case T_FALSE:
|
406
|
-
{
|
407
|
-
UA_Boolean tmp = false;
|
408
|
-
UA_Variant_setScalar(&variant, &tmp, &UA_TYPES[UA_TYPES_BOOLEAN]);
|
409
|
-
UA_Server_writeValue(ns->server->server, ns->id, variant);
|
410
|
-
break;
|
411
|
-
}
|
412
|
-
case T_TRUE:
|
413
|
-
{
|
414
|
-
UA_Boolean tmp = true;
|
415
|
-
UA_Variant_setScalar(&variant, &tmp, &UA_TYPES[UA_TYPES_BOOLEAN]);
|
416
|
-
UA_Server_writeValue(ns->server->server, ns->id, variant);
|
417
|
-
break;
|
418
|
-
}
|
419
|
-
case T_FLOAT:
|
420
|
-
case T_FIXNUM:
|
421
|
-
{
|
422
|
-
UA_Double tmp = NUM2DBL(value);
|
423
|
-
UA_Variant_setScalar(&variant, &tmp, &UA_TYPES[UA_TYPES_DOUBLE]);
|
424
|
-
UA_Server_writeValue(ns->server->server, ns->id, variant);
|
425
|
-
break;
|
426
|
-
}
|
427
|
-
case T_STRING:
|
428
|
-
case T_SYMBOL:
|
429
|
-
{
|
430
|
-
VALUE str = rb_obj_as_string(value);
|
431
|
-
if (NIL_P(str) || TYPE(str) != T_STRING)
|
432
|
-
rb_raise(rb_eTypeError, "cannot convert obj to string");
|
433
|
-
UA_String tmp = UA_STRING(StringValuePtr(str));
|
434
|
-
UA_Variant_setScalar(&variant, &tmp, &UA_TYPES[UA_TYPES_STRING]);
|
435
|
-
UA_Server_writeValue(ns->server->server, ns->id, variant);
|
436
|
-
break;
|
437
|
-
}
|
438
|
-
case T_ARRAY:
|
439
|
-
{
|
440
|
-
// UA_UInt32 arrayDims = 0;
|
441
|
-
// attr.valueRank = UA_VALUERANK_ONE_DIMENSION;
|
442
|
-
// attr.arrayDimensions = &arrayDims;
|
443
|
-
// attr.arrayDimensionsSize = 1;
|
444
|
-
// UA_Variant_setArray(&attr.value, UA_Array_new(10, &UA_TYPES[type]), 10, &UA_TYPES[type]);
|
445
|
-
}
|
446
|
-
|
447
|
-
}
|
448
|
-
}
|
595
|
+
set_node_to_value(ns,value);
|
449
596
|
return self;
|
450
597
|
} //}}}
|
451
598
|
static VALUE node_value(VALUE self) { //{{{
|
@@ -455,7 +602,7 @@ static VALUE node_value(VALUE self) { //{{{
|
|
455
602
|
|
456
603
|
UA_Variant value;
|
457
604
|
UA_Variant_init(&value);
|
458
|
-
UA_StatusCode retval = UA_Server_readValue(ns->
|
605
|
+
UA_StatusCode retval = UA_Server_readValue(ns->master->master, ns->id, &value);
|
459
606
|
|
460
607
|
|
461
608
|
VALUE ret = Qnil;
|
@@ -488,7 +635,7 @@ static VALUE node_id(VALUE self) { //{{{
|
|
488
635
|
/* -- */
|
489
636
|
static void server_free(server_struct *pss) { //{{{
|
490
637
|
if (pss != NULL) {
|
491
|
-
UA_Server_delete(pss->
|
638
|
+
UA_Server_delete(pss->master);
|
492
639
|
free(pss);
|
493
640
|
}
|
494
641
|
} //}}}
|
@@ -498,9 +645,11 @@ static VALUE server_alloc(VALUE self) { //{{{
|
|
498
645
|
if (pss == NULL)
|
499
646
|
rb_raise(rb_eNoMemError, "No memory left for OPCUA server.");
|
500
647
|
|
501
|
-
pss->
|
502
|
-
pss->config = UA_Server_getConfig(pss->
|
648
|
+
pss->master = UA_Server_new();
|
649
|
+
pss->config = UA_Server_getConfig(pss->master);
|
503
650
|
pss->default_ns = 1;
|
651
|
+
pss->debug = true;
|
652
|
+
pss->methods = rb_hash_new();
|
504
653
|
|
505
654
|
UA_ServerConfig_setDefault(pss->config);
|
506
655
|
|
@@ -513,7 +662,7 @@ static VALUE server_init(VALUE self) { //{{{
|
|
513
662
|
|
514
663
|
Data_Get_Struct(self, server_struct, pss);
|
515
664
|
|
516
|
-
UA_StatusCode retval = UA_Server_run_startup(pss->
|
665
|
+
UA_StatusCode retval = UA_Server_run_startup(pss->master);
|
517
666
|
if (retval != UA_STATUSCODE_GOOD)
|
518
667
|
rb_raise(rb_eRuntimeError, "Server could not be started.");
|
519
668
|
|
@@ -524,7 +673,7 @@ static VALUE server_run(VALUE self) { //{{{
|
|
524
673
|
|
525
674
|
Data_Get_Struct(self, server_struct, pss);
|
526
675
|
|
527
|
-
UA_UInt16 timeout = UA_Server_run_iterate(pss->
|
676
|
+
UA_UInt16 timeout = UA_Server_run_iterate(pss->master, false);
|
528
677
|
|
529
678
|
return rb_float_new(timeout/1000.0);
|
530
679
|
} //}}}
|
@@ -539,7 +688,7 @@ static VALUE server_add_namespace(VALUE self, VALUE name) { //{{{
|
|
539
688
|
rb_raise(rb_eTypeError, "cannot convert obj to string");
|
540
689
|
char *nstr = (char *)StringValuePtr(str);
|
541
690
|
|
542
|
-
pss->default_ns = UA_Server_addNamespace(pss->
|
691
|
+
pss->default_ns = UA_Server_addNamespace(pss->master, nstr);
|
543
692
|
return self;
|
544
693
|
} //}}}
|
545
694
|
static VALUE server_types(VALUE self) { //{{{
|
@@ -552,6 +701,25 @@ static VALUE server_objects(VALUE self) { //{{{
|
|
552
701
|
Data_Get_Struct(self, server_struct, pss);
|
553
702
|
return node_wrap(cObjectsNode, node_alloc(pss, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER)));
|
554
703
|
} //}}}
|
704
|
+
static VALUE server_debug(VALUE self) { //{{{
|
705
|
+
server_struct *pss;
|
706
|
+
Data_Get_Struct(self, server_struct, pss);
|
707
|
+
|
708
|
+
return (pss->debug) ? Qtrue : Qfalse;
|
709
|
+
} //}}}
|
710
|
+
static VALUE server_debug_set(VALUE self, VALUE val) { //{{{
|
711
|
+
server_struct *pss;
|
712
|
+
Data_Get_Struct(self, server_struct, pss);
|
713
|
+
|
714
|
+
if (val == Qtrue) {
|
715
|
+
pss->config->logger = UA_Log_Stdout_;
|
716
|
+
pss->debug = Qtrue;
|
717
|
+
} else {
|
718
|
+
pss->config->logger = UA_Log_None_;
|
719
|
+
pss->debug = Qfalse;
|
720
|
+
}
|
721
|
+
return self;
|
722
|
+
} //}}}
|
555
723
|
|
556
724
|
void Init_server(void) {
|
557
725
|
mOPCUA = rb_define_module("OPCUA");
|
@@ -560,6 +728,8 @@ void Init_server(void) {
|
|
560
728
|
rb_define_const(mOPCUA, "OPTIONAL", INT2NUM(UA_NS0ID_MODELLINGRULE_OPTIONAL));
|
561
729
|
rb_define_const(mOPCUA, "OPTIONALPLACEHOLDER", INT2NUM(UA_NS0ID_MODELLINGRULE_OPTIONALPLACEHOLDER));
|
562
730
|
|
731
|
+
Init_types();
|
732
|
+
|
563
733
|
cServer = rb_define_class_under(mOPCUA, "Server", rb_cObject);
|
564
734
|
cObjectsNode = rb_define_class_under(mOPCUA, "cObjectsNode", rb_cObject);
|
565
735
|
cTypesTopNode = rb_define_class_under(mOPCUA, "cTypesTopNode", rb_cObject);
|
@@ -572,20 +742,28 @@ void Init_server(void) {
|
|
572
742
|
rb_define_method(cServer, "add_namespace", server_add_namespace, 1);
|
573
743
|
rb_define_method(cServer, "types", server_types, 0);
|
574
744
|
rb_define_method(cServer, "objects", server_objects, 0);
|
745
|
+
rb_define_method(cServer, "debug", server_debug, 0);
|
746
|
+
rb_define_method(cServer, "debug=", server_debug_set, 1);
|
575
747
|
|
576
748
|
rb_define_method(cTypesTopNode, "add_object_type", node_add_object_type, 1);
|
577
749
|
rb_define_method(cTypesTopNode, "folder", node_type_folder, 0);
|
578
750
|
rb_define_method(cTypesSubNode, "add_object_type", node_add_object_type, 1);
|
579
751
|
rb_define_method(cTypesSubNode, "add_variable", node_add_variable, -1);
|
752
|
+
rb_define_method(cTypesSubNode, "add_variable_rw", node_add_variable_rw, -1);
|
580
753
|
rb_define_method(cTypesSubNode, "add_object", node_add_object, -1);
|
754
|
+
rb_define_method(cTypesSubNode, "add_method", node_add_method, -1);
|
755
|
+
rb_define_method(cTypesSubNode, "to_s", node_to_s, 0);
|
581
756
|
rb_define_method(cTypesSubNode, "id", node_id, 0);
|
582
757
|
|
583
|
-
rb_define_method(cObjectsNode, "instantiate", node_add_object_without, 2);
|
584
758
|
rb_define_method(cObjectsNode, "manifest", node_manifest, 2);
|
585
|
-
rb_define_method(cObjectsNode, "add_variable", node_add_variable_without, 1);
|
586
759
|
rb_define_method(cObjectsNode, "find", node_find, 1);
|
587
|
-
rb_define_method(cObjectsNode, "value", node_value, 0);
|
588
|
-
rb_define_method(cObjectsNode, "value=", node_value_set, 1);
|
589
760
|
rb_define_method(cObjectsNode, "to_s", node_to_s, 0);
|
590
761
|
rb_define_method(cObjectsNode, "id", node_id, 0);
|
762
|
+
rb_define_method(cObjectsNode, "value", node_value, 0);
|
763
|
+
rb_define_method(cObjectsNode, "value=", node_value_set, 1);
|
764
|
+
|
765
|
+
rb_define_method(cLeafNode, "to_s", node_to_s, 0);
|
766
|
+
rb_define_method(cLeafNode, "id", node_id, 0);
|
767
|
+
rb_define_method(cLeafNode, "value", node_value, 0);
|
768
|
+
rb_define_method(cLeafNode, "value=", node_value_set, 1);
|
591
769
|
}
|