opcua 0.8 → 0.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
  }