opcua 0.8 → 0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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 *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 *client;
21
+ client_struct *master;
23
22
  VALUE on_change;
24
23
  UA_NodeId id;
25
24
  } node_struct;
@@ -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) { free(ns); }
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->server = server;
21
- ns->id = nodeid;
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->server, UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE)));
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 = UA_NODEID_STRING(ns->server->default_ns, nstr);
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->server->server,
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->server->default_ns, nstr),
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->server,n));
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
- static UA_NodeId node_add_variable_ua(UA_Int32 type, UA_NodeId n, UA_LocalizedText dn, UA_QualifiedName qn, node_struct *parent, VALUE ref) { //{{{
78
- UA_VariableAttributes mnAttr = UA_VariableAttributes_default;
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->server->server,
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
- mnAttr,
270
+ vAttr,
88
271
  NULL,
89
272
  NULL);
90
273
 
91
274
  if (ref != Qnil) {
92
- UA_Server_addReference(parent->server->server,
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->server->default_ns,nstr),
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->server->default_ns, nstr),
290
+ UA_QUALIFIEDNAME(parent->master->default_ns, nstr),
108
291
  parent,
109
- ref
292
+ ref,
293
+ accesslevelmask
110
294
  );
111
295
  } //}}}
112
- static VALUE node_add_variable(int argc, VALUE* argv, VALUE self) { //{{{
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) { // there should only be 1 or 2 arguments
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->server,node_add_variable_ua_simple(type,nstr,parent,argv[1])));
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 node_add_variable_without(VALUE self, VALUE name) { //{{{
136
- VALUE argv[] = { name, Qnil };
137
- return node_add_variable(2,argv,self);
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->server->server,
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->server->server,
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->server->default_ns,nstr),
353
+ UA_NODEID_STRING(parent->master->default_ns,nstr),
168
354
  UA_LOCALIZEDTEXT("en-US", nstr),
169
- UA_QUALIFIEDNAME(parent->server->default_ns, nstr),
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) { // there should only be 2 or 3 arguments
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->server,node_add_object_ua_simple(type,nstr,parent,datatype,argv[2])));
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, 1, &bDes);
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->server->default_ns) {
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
- UA_Server_readNodeClass(parent->server->server, child_id, &nc);
259
- UA_Server_readBrowseName(parent->server->server, child_id, &qn);
260
- UA_Server_readDisplayName(parent->server->server, child_id, &dn);
261
- UA_Server_readBrowseName(parent->server->server, parent->id, &pqn);
262
- UA_Server_readBrowseName(parent->server->server, newnode->id, &nqn);
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->server->default_ns) {
460
+ if (child_id.namespaceIndex == parent->master->default_ns) {
276
461
  UA_QualifiedName mqn;UA_QualifiedName_init(&mqn);
277
- UA_Server_readBrowseName(parent->server->server, UA_NODEID_NUMERIC(0, UA_NS0ID_MODELLINGRULE_MANDATORY), &mqn);
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->server->server, child_id, UA_NODEID_NUMERIC(0, UA_NS0ID_HASMODELLINGRULE), mqn);
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->server->server, child_id, &typeid);
476
+ node_get_reference(parent->master->master, child_id, &typeid);
292
477
 
293
- node_struct *thetype = node_alloc(parent->server,typeid);
294
- node_struct *downnode = node_alloc(parent->server,node_add_object_ua(UA_NS0ID_MODELLINGRULE_MANDATORY,UA_NODEID_STRING(parent->server->default_ns,buffer),dn,qn,newnode,thetype,Qtrue));
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->server,child_id);
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->server->server, child_id, node_manifest_iter, (void *)downhandle);
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->server->default_ns,buffer),dn,qn,newnode,Qtrue);
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->server->default_ns, nidstr);
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->server->server,
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->server->default_ns, nstr),
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->server,n);
561
+ node_struct *ret = node_alloc(ns->master,n);
363
562
  node_struct *handle[2] = { ts, ret };
364
- UA_Server_forEachChildNodeCall(ns->server->server, ts->id, node_manifest_iter, (void *)handle);
563
+ UA_Server_forEachChildNodeCall(ns->master->master, ts->id, node_manifest_iter, (void *)handle);
365
564
 
366
- UA_Server_addNode_finish(ns->server->server,n);
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->server->server, ns->id, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), UA_QUALIFIEDNAME(ns->server->default_ns, nstr));
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->server,ret));
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->server->server, ns->id, &value);
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->server);
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->server = UA_Server_new();
502
- pss->config = UA_Server_getConfig(pss->server);
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->server);
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->server, false);
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->server, nstr);
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
  }