opcua 0.11 → 0.12

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/ruby
2
+ require_relative '../lib/opcua/client'
3
+ #require 'opcua/client'
4
+
5
+ ### username & pass in url (e.g. siemens)
6
+ # client = OPCUA::Client.new("opc.tcp://OpcUaClient:SUNRISE@localhost:4840")
7
+
8
+ client = OPCUA::Client.new("opc.tcp://localhost:4840")
9
+ client.subscription_interval = 100 # default 500
10
+
11
+ node = client.get 2, '/KalimatC34/Tools/Tool1/ToolNumber' # get node from nodeid
12
+ p node.value
13
+ node.on_value_change do
14
+ puts 'now'
15
+ end
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/ruby
2
+ require_relative '../lib/opcua/client'
3
+ #require 'opcua/client'
4
+
5
+ ### username & pass in url (e.g. siemens)
6
+ # client = OPCUA::Client.new("opc.tcp://OpcUaClient:SUNRISE@localhost:4840")
7
+
8
+ client = OPCUA::Client.new("opc.tcp://localhost:4840")
9
+ client.subscription_interval = 100 # default 500
10
+
11
+ if (node = client.get 2, '/KalimatC34/Tools/Tool1/ToolNumber') # get node from nodeid
12
+ p node
13
+ p node.value
14
+ else
15
+ p 'invalid nodeid'
16
+ end
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/ruby
2
+ require_relative '../lib/opcua/client'
3
+ #require 'opcua/client'
4
+
5
+ ### username & pass in url (e.g. siemens)
6
+ # client = OPCUA::Client.new("opc.tcp://OpcUaClient:SUNRISE@localhost:4840")
7
+
8
+ client = OPCUA::Client.new("opc.tcp://localhost:4840")
9
+ client.default_ns = 2
10
+
11
+ if (node = client.get '/KalimatC34/Tools/Tool1/ToolNumber')
12
+ node.value = [:a, :b]
13
+ else
14
+ p 'invalid nodeid'
15
+ end
@@ -16,9 +16,9 @@ Daemonite.new do
16
16
  t.add_variable :SollWertX
17
17
  t.add_variable :SollWertY
18
18
  t.add_variable :SollWertZ
19
- t.add_variable :ToolNumber
19
+ t.add_variable_rw :ToolNumber
20
20
  t.add_variable :DuploNumber
21
- t.add_variable :testValue1
21
+ t.add_property :testValue1
22
22
  t.add_method :testMethod, test1: OPCUA::TYPES::STRING, test2: OPCUA::TYPES::DATETIME do |node, test1, test2|
23
23
  ns, nid = node.id
24
24
  puts '-' * 10
@@ -45,18 +45,30 @@ Daemonite.new do
45
45
  t3 = tools.manifest(:Tool3,tt)
46
46
 
47
47
  opts[:tn] = t1.find(:ToolNumber)
48
+ opts[:tn].description = 'test test'
49
+ opts[:tn].value = [0,1]
50
+ p opts[:tn].description
48
51
 
49
52
  measurments_t1 = t1.find(:Measurements)
50
53
  measurments_t1.manifest(:M1,mt)
51
54
  measurments_t1.manifest(:M2,mt)
55
+
56
+ p opts['server'].namespaces
52
57
  rescue => e
53
58
  puts e.message
54
59
  end
55
60
 
61
+
62
+ counter = 0
56
63
  run do |opts|
57
64
  GC.start
58
65
  sleep opts['server'].run
59
- opts[:tn].value = Time.now
66
+ # if counter % 100 == 0
67
+ # opts[:tn].value = [counter, counter]
68
+ # # opts[:tn].value = 1
69
+ # p opts[:tn].value
70
+ # end
71
+ # counter += 1
60
72
  rescue => e
61
73
  puts e.message
62
74
  end
@@ -2,6 +2,7 @@
2
2
  #include "../../../cert/cert.h"
3
3
  #include "../../../cert/cert_key.h"
4
4
 
5
+
5
6
  VALUE mOPCUA = Qnil;
6
7
  VALUE cClient = Qnil;
7
8
  VALUE cVarNode = Qnil;
@@ -10,6 +11,11 @@ VALUE cNode = Qnil;
10
11
 
11
12
  #include "../values.h"
12
13
 
14
+ #include <signal.h>
15
+
16
+ static volatile bool keepRunning = true;
17
+ void intHandler(int dummy) { keepRunning = false; }
18
+
13
19
  /* -- */
14
20
  static void node_free(node_struct *ns) { //{{{
15
21
  if (ns != NULL) {
@@ -26,6 +32,7 @@ static node_struct * node_alloc(client_struct *client, UA_NodeId nodeid) { //{{{
26
32
  ns->master = client;
27
33
  ns->id = nodeid;
28
34
  ns->on_change = Qnil;
35
+ ns->waiting = 0;
29
36
 
30
37
  return ns;
31
38
  } //}}}
@@ -51,6 +58,28 @@ static VALUE node_value(VALUE self) { //{{{
51
58
  UA_Variant_clear(&value);
52
59
  return rb_ary_entry(ret,0);
53
60
  } //}}}
61
+ static VALUE node_value_set(VALUE self, VALUE value) { //{{{
62
+ node_struct *ns;
63
+ Data_Get_Struct(self, node_struct, ns);
64
+ if (!ns->master->started) rb_raise(rb_eRuntimeError, "Client disconnected.");
65
+
66
+ UA_Variant variant;
67
+ if (value_to_variant(value,&variant)) {
68
+ // printf("-----------------------------------------%ld\n",variant.arrayDimensionsSize);
69
+ if (variant.arrayDimensionsSize > 0) {
70
+ UA_Int32 ads = (UA_Int32) variant.arrayDimensionsSize;
71
+ UA_Client_writeValueRankAttribute(ns->master->master, ns->id, &ads);
72
+ UA_Client_writeArrayDimensionsAttribute(ns->master->master, ns->id, variant.arrayDimensionsSize, variant.arrayDimensions);
73
+ }
74
+
75
+ UA_StatusCode retval = UA_Client_writeValueAttribute(ns->master->master, ns->id, &variant);
76
+ if (retval != UA_STATUSCODE_GOOD) {
77
+ rb_raise(rb_eRuntimeError, "Can't set value: %s.", UA_StatusCode_name(retval));
78
+ }
79
+ }
80
+
81
+ return self;
82
+ } //}}}
54
83
  static VALUE node_on_change(VALUE self) { //{{{
55
84
  node_struct *ns;
56
85
  Data_Get_Struct(self, node_struct, ns);
@@ -67,6 +96,82 @@ static VALUE node_on_change(VALUE self) { //{{{
67
96
 
68
97
  return self;
69
98
  } //}}}
99
+ static void node_on_value_change_handler(UA_Client *client, UA_UInt32 subId, void *subContext, UA_UInt32 monId, void *monContext, UA_DataValue *value) {
100
+ VALUE ins = (VALUE)monContext;
101
+ VALUE blk = RARRAY_AREF(ins,1);
102
+
103
+ node_struct *ns;
104
+ Data_Get_Struct(RARRAY_AREF(ins,0), node_struct, ns);
105
+ ns->waiting = ns->waiting + 1;
106
+
107
+ if (ns->waiting == 2 && (NIL_P(blk) || TYPE(blk) != T_NIL)) {
108
+ VALUE args = rb_ary_new2(3);
109
+ VALUE ret = extract_value(value->value);
110
+ rb_ary_store(args,0,rb_ary_entry(ret,0));
111
+ if (value->hasSourceTimestamp) {
112
+ rb_ary_store(args,1,rb_time_new(UA_DateTime_toUnixTime(value->sourceTimestamp),0));
113
+ } else {
114
+ if (value->hasServerTimestamp) {
115
+ rb_ary_store(args,1,rb_time_new(UA_DateTime_toUnixTime(value->serverTimestamp),0));
116
+ } else {
117
+ rb_ary_store(args,1,Qnil);
118
+ }
119
+ }
120
+ rb_ary_store(args,2,rb_ary_entry(ret,1));
121
+ rb_proc_call(blk,args);
122
+ }
123
+ }
124
+ static VALUE node_on_value_change(VALUE self) {
125
+ node_struct *ns;
126
+ Data_Get_Struct(self, node_struct, ns);
127
+ if (!ns->master->started) rb_raise(rb_eRuntimeError, "Client disconnected.");
128
+
129
+ if (!rb_block_given_p())
130
+ rb_raise(rb_eArgError, "you need to supply a block with #on_change");
131
+
132
+ UA_CreateSubscriptionRequest sreq; UA_CreateSubscriptionRequest_init(&sreq);
133
+ sreq.requestedPublishingInterval = 100;
134
+ sreq.requestedLifetimeCount = 10000;
135
+ sreq.requestedMaxKeepAliveCount = 10;
136
+ sreq.maxNotificationsPerPublish = 0;
137
+ sreq.publishingEnabled = true;
138
+ sreq.priority = 0;
139
+
140
+ UA_CreateSubscriptionResponse sres = UA_Client_Subscriptions_create(ns->master->master, sreq, NULL, NULL, NULL);
141
+ if (sres.responseHeader.serviceResult != UA_STATUSCODE_GOOD)
142
+ rb_raise(rb_eRuntimeError, "Subscription could not be created.");
143
+
144
+ VALUE ins = rb_ary_new2(2);
145
+ rb_ary_store(ins,0,self);
146
+ rb_ary_store(ins,1,rb_block_proc());
147
+ ns->waiting = 0;
148
+
149
+ UA_MonitoredItemCreateRequest monRequest = UA_MonitoredItemCreateRequest_default(ns->id);
150
+ UA_MonitoredItemCreateResult monResponse =
151
+ UA_Client_MonitoredItems_createDataChange(ns->master->master, sres.subscriptionId,
152
+ UA_TIMESTAMPSTORETURN_BOTH,
153
+ monRequest, (void *)ins, node_on_value_change_handler, NULL);
154
+
155
+ if(monResponse.statusCode != UA_STATUSCODE_GOOD) {
156
+ rb_raise(rb_eRuntimeError, "Monitoring item failed: %s\n", UA_StatusCode_name(monResponse.statusCode));
157
+ }
158
+
159
+ keepRunning = true;
160
+ signal(SIGINT, intHandler);
161
+ while (ns->waiting < 2 && keepRunning) {
162
+ UA_Client_run_iterate(ns->master->master, 100);
163
+ }
164
+ signal(SIGINT, SIG_DFL); // reset the disposition for SIGINT to the default
165
+
166
+ UA_MonitoredItemCreateResult_clear(&monResponse);
167
+ UA_MonitoredItemCreateRequest_clear(&monRequest);
168
+
169
+ UA_Client_Subscriptions_deleteSingle(ns->master->master, sres.subscriptionId);
170
+ UA_CreateSubscriptionResponse_clear(&sres);
171
+ UA_CreateSubscriptionRequest_clear(&sreq);
172
+
173
+ return self;
174
+ }
70
175
 
71
176
  /* -- */
72
177
  static void client_free(client_struct *pss) { //{{{
@@ -238,28 +343,31 @@ static VALUE client_get(int argc, VALUE* argv, VALUE self) { //{{{
238
343
  if (NIL_P(ns) || TYPE(ns) != T_FIXNUM)
239
344
  rb_raise(rb_eTypeError, "ns is not a valid (numeric) namespace id");
240
345
 
241
- node_struct *res;
346
+ UA_NodeId it;
347
+
242
348
  if (TYPE(id) == T_FIXNUM) {
243
- res = node_alloc(pss, UA_NODEID_NUMERIC(NUM2INT(ns), NUM2INT(id)));
349
+ it = UA_NODEID_NUMERIC(NUM2INT(ns), NUM2INT(id));
244
350
  } else {
245
351
  VALUE str = rb_obj_as_string(id);
246
352
  if (NIL_P(str) || TYPE(str) != T_STRING)
247
353
  rb_raise(rb_eTypeError, "cannot convert url to string");
248
354
  char *nstr = (char *)StringValuePtr(str);
249
355
 
250
- res = node_alloc(pss, UA_NODEID_STRING(NUM2INT(ns), nstr));
356
+ it = UA_NODEID_STRING(NUM2INT(ns), nstr);
251
357
  }
252
358
 
253
359
  UA_NodeClass nc;UA_NodeClass_init(&nc);
254
- UA_Client_readNodeClassAttribute(pss->master, res->id, &nc);
360
+ UA_Client_readNodeClassAttribute(pss->master, it, &nc);
255
361
 
256
362
  VALUE node;
257
363
  if (nc == UA_NODECLASS_VARIABLE) {
258
- node = node_wrap(cVarNode,res);
364
+ node = node_wrap(cVarNode,node_alloc(pss, it));
259
365
  } else if (nc == UA_NODECLASS_METHOD) {
260
- node = node_wrap(cMethodNode,res);
366
+ node = node_wrap(cMethodNode,node_alloc(pss, it));
367
+ } else if (nc == UA_NODECLASS_UNSPECIFIED) {
368
+ node = Qnil;
261
369
  } else {
262
- node = node_wrap(cNode,res);
370
+ node = node_wrap(cNode,node_alloc(pss, it));
263
371
  }
264
372
  UA_NodeClass_clear(&nc);
265
373
 
@@ -323,6 +431,25 @@ static VALUE client_debug_set(VALUE self, VALUE val) { //{{{
323
431
  return self;
324
432
  } //}}}
325
433
 
434
+ static VALUE client_namespaces(VALUE self) { //{{{
435
+ client_struct *pss;
436
+ Data_Get_Struct(self, client_struct, pss);
437
+ if (!pss->started) rb_raise(rb_eRuntimeError, "Client disconnected.");
438
+
439
+ UA_Variant value;
440
+ UA_Variant_init(&value);
441
+ UA_StatusCode retval = UA_Client_readValueAttribute(pss->master, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_NAMESPACEARRAY), &value);
442
+
443
+ VALUE ret = Qnil;
444
+ if (retval == UA_STATUSCODE_GOOD) {
445
+ ret = extract_value(value);
446
+ }
447
+
448
+ UA_Variant_clear(&value);
449
+ RB_OBJ_FREEZE(ret);
450
+ return rb_ary_entry(ret,0);
451
+ } //}}}
452
+
326
453
  static VALUE node_id(VALUE self) { //{{{
327
454
  node_struct *ns;
328
455
 
@@ -348,7 +475,7 @@ static VALUE node_to_s(VALUE self) { //{{{
348
475
  Data_Get_Struct(self, node_struct, ns);
349
476
 
350
477
  if (ns->id.identifierType == UA_NODEIDTYPE_NUMERIC) {
351
- ret = rb_sprintf("ns=%d;n=%d", ns->id.namespaceIndex, ns->id.identifier.numeric);
478
+ ret = rb_sprintf("ns=%d;i=%d", ns->id.namespaceIndex, ns->id.identifier.numeric);
352
479
  } else if(ns->id.identifierType == UA_NODEIDTYPE_STRING) {
353
480
  ret = rb_sprintf("ns=%d;s=%.*s", ns->id.namespaceIndex, (int)ns->id.identifier.string.length, ns->id.identifier.string.data);
354
481
  } else {
@@ -357,7 +484,7 @@ static VALUE node_to_s(VALUE self) { //{{{
357
484
  return ret;
358
485
  } //}}}
359
486
 
360
- static VALUE node_call(int argc, VALUE* argv, VALUE self) {
487
+ static VALUE node_call(int argc, VALUE* argv, VALUE self) { //{{{
361
488
  node_struct *ns;
362
489
 
363
490
  VALUE splat;
@@ -389,7 +516,7 @@ static VALUE node_call(int argc, VALUE* argv, VALUE self) {
389
516
  } else {
390
517
  return Qfalse;
391
518
  }
392
- }
519
+ } //}}}
393
520
 
394
521
  static void client_run_handler(UA_Client *client, UA_UInt32 subId, void *subContext, UA_UInt32 monId, void *monContext, UA_DataValue *value) { //{{{
395
522
  VALUE val = (VALUE)monContext;
@@ -465,9 +592,9 @@ void Init_client(void) {
465
592
  mOPCUA = rb_define_module("OPCUA");
466
593
 
467
594
  cClient = rb_define_class_under(mOPCUA, "Client", rb_cObject);
468
- cNode = rb_define_class_under(mOPCUA, "cNode", rb_cObject);
469
- cMethodNode = rb_define_class_under(mOPCUA, "cMethodNode", rb_cObject);
470
- cVarNode = rb_define_class_under(mOPCUA, "cVarNode", rb_cObject);
595
+ cNode = rb_define_class_under(cClient, "cNode", rb_cObject);
596
+ cMethodNode = rb_define_class_under(cClient, "cMethodNode", cNode);
597
+ cVarNode = rb_define_class_under(cClient, "cVarNode", cNode);
471
598
 
472
599
  Init_types();
473
600
 
@@ -480,18 +607,17 @@ void Init_client(void) {
480
607
  rb_define_method(cClient, "subscription_interval=", client_subscription_interval_set, 1);
481
608
  rb_define_method(cClient, "default_ns", client_default_ns, 0);
482
609
  rb_define_method(cClient, "default_ns=", client_default_ns_set, 1);
610
+ rb_define_method(cClient, "namespaces", client_namespaces, 0);
483
611
  rb_define_method(cClient, "debug", client_debug, 0);
484
612
  rb_define_method(cClient, "debug=", client_debug_set, 1);
485
613
 
486
614
  rb_define_method(cNode, "to_s", node_to_s, 0);
487
615
  rb_define_method(cNode, "id", node_id, 0);
488
616
 
489
- rb_define_method(cMethodNode, "to_s", node_to_s, 0);
490
- rb_define_method(cMethodNode, "id", node_id, 0);
491
617
  rb_define_method(cMethodNode, "call", node_call, -1);
492
618
 
493
- rb_define_method(cVarNode, "to_s", node_to_s, 0);
494
- rb_define_method(cVarNode, "id", node_id, 0);
495
619
  rb_define_method(cVarNode, "value", node_value, 0);
620
+ rb_define_method(cVarNode, "value=", node_value_set, 1);
496
621
  rb_define_method(cVarNode, "on_change", node_on_change, 0);
622
+ rb_define_method(cVarNode, "on_value_change", node_on_value_change, 0);
497
623
  }
@@ -22,4 +22,5 @@ typedef struct node_struct {
22
22
  client_struct *master;
23
23
  VALUE on_change;
24
24
  UA_NodeId id;
25
+ int waiting;
25
26
  } node_struct;
@@ -5,5 +5,6 @@ spec = eval(File.read(__dir__ + '/../../../opcua.gemspec'))
5
5
  $CFLAGS = '-g -Wall ' + $CFLAGS
6
6
  $CFLAGS << ''
7
7
  $LDFLAGS << ' -lopen62541'
8
+
8
9
  dir_config('server')
9
10
  create_makefile('server')
@@ -2,9 +2,13 @@
2
2
 
3
3
  VALUE mOPCUA = Qnil;
4
4
  VALUE cServer = Qnil;
5
- VALUE cObjectsNode = Qnil;
6
- VALUE cTypesTopNode = Qnil;
7
- VALUE cTypesSubNode = Qnil;
5
+ VALUE cNode = Qnil;
6
+ VALUE cObjectNode = Qnil;
7
+ VALUE cTypeTopNode = Qnil;
8
+ VALUE cTypeSubNode = Qnil;
9
+ VALUE cReferenceTopNode = Qnil;
10
+ VALUE cReferenceSubNode = Qnil;
11
+ VALUE cReferenceNode = Qnil;
8
12
  VALUE cVarNode = Qnil;
9
13
  VALUE cMethodNode = Qnil;
10
14
 
@@ -41,7 +45,7 @@ static VALUE node_wrap(VALUE klass, node_struct *ns) { //{{{
41
45
  static VALUE node_type_folder(VALUE self) { //{{{
42
46
  node_struct *ns;
43
47
  Data_Get_Struct(self, node_struct, ns);
44
- return node_wrap(cTypesTopNode, node_alloc(ns->master, UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE)));
48
+ return node_wrap(cTypeTopNode, node_alloc(ns->master, UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE)));
45
49
  } //}}}
46
50
  static VALUE node_add_object_type(VALUE self, VALUE name) { //{{{
47
51
  node_struct *ns;
@@ -66,7 +70,34 @@ static VALUE node_add_object_type(VALUE self, VALUE name) { //{{{
66
70
  NULL,
67
71
  NULL);
68
72
 
69
- return node_wrap(cTypesSubNode,node_alloc(ns->master,n));
73
+ return node_wrap(cTypeSubNode,node_alloc(ns->master,n));
74
+ } //}}}
75
+ static VALUE node_add_reference_type(VALUE self, VALUE name, VALUE type) { //{{{
76
+ node_struct *ns;
77
+
78
+ Data_Get_Struct(self, node_struct, ns);
79
+
80
+ VALUE str = rb_obj_as_string(name);
81
+ if (NIL_P(str) || TYPE(str) != T_STRING)
82
+ rb_raise(rb_eTypeError, "cannot convert arg 1 to string");
83
+ char *nstr = (char *)StringValuePtr(str);
84
+ if (TYPE(type) != T_FIXNUM)
85
+ rb_raise(rb_eTypeError, "cannot convert arg 2 to integer");
86
+
87
+ UA_NodeId n = UA_NODEID_NUMERIC(ns->master->default_ns, nodecounter++);
88
+
89
+ UA_ReferenceTypeAttributes rtAttr = UA_ReferenceTypeAttributes_default;
90
+ rtAttr.displayName = UA_LOCALIZEDTEXT("en-US", nstr);
91
+ UA_Server_addReferenceTypeNode(ns->master->master,
92
+ n,
93
+ ns->id,
94
+ UA_NODEID_NUMERIC(0, NUM2INT(type)),
95
+ UA_QUALIFIEDNAME(ns->master->default_ns, nstr),
96
+ rtAttr,
97
+ NULL,
98
+ NULL);
99
+
100
+ return node_wrap(cReferenceSubNode,node_alloc(ns->master,n));
70
101
  } //}}}
71
102
 
72
103
  static VALUE node_id(VALUE self) { //{{{
@@ -94,7 +125,7 @@ static VALUE node_to_s(VALUE self) { //{{{
94
125
  Data_Get_Struct(self, node_struct, ns);
95
126
 
96
127
  if (ns->id.identifierType == UA_NODEIDTYPE_NUMERIC) {
97
- ret = rb_sprintf("ns=%d;n=%d", ns->id.namespaceIndex, ns->id.identifier.numeric);
128
+ ret = rb_sprintf("ns=%d;i=%d", ns->id.namespaceIndex, ns->id.identifier.numeric);
98
129
  } else if(ns->id.identifierType == UA_NODEIDTYPE_STRING) {
99
130
  ret = rb_sprintf("ns=%d;s=%.*s", ns->id.namespaceIndex, (int)ns->id.identifier.string.length, ns->id.identifier.string.data);
100
131
  } else {
@@ -102,6 +133,33 @@ static VALUE node_to_s(VALUE self) { //{{{
102
133
  }
103
134
  return ret;
104
135
  } //}}}
136
+ static VALUE node_add_reference(VALUE self, VALUE to, VALUE type) { //{{{
137
+ node_struct *ns;
138
+ node_struct *tos;
139
+ node_struct *tys;
140
+
141
+ Data_Get_Struct(self, node_struct, ns);
142
+
143
+ if (!(rb_obj_is_kind_of(type,cReferenceSubNode) || rb_obj_is_kind_of(to,cTypeSubNode))) {
144
+ rb_raise(rb_eArgError, "arguments have to be NodeIDs.");
145
+ }
146
+ Data_Get_Struct(to, node_struct, tos);
147
+ Data_Get_Struct(type, node_struct, tys);
148
+ UA_NodeId n = UA_NODEID_NUMERIC(ns->master->default_ns, nodecounter++);
149
+
150
+ UA_ExpandedNodeId toNodeId;
151
+ toNodeId.serverIndex = 0;
152
+ toNodeId.namespaceUri = UA_STRING_NULL;
153
+ toNodeId.nodeId = tos->id;
154
+
155
+ UA_Server_addReference(ns->master->master,
156
+ n,
157
+ tys->id,
158
+ toNodeId,
159
+ true);
160
+
161
+ return node_wrap(cReferenceNode,node_alloc(ns->master,n));
162
+ } //}}}
105
163
 
106
164
  static UA_StatusCode node_add_method_callback( //{{{
107
165
  UA_Server *server,
@@ -121,7 +179,7 @@ static UA_StatusCode node_add_method_callback( //{{{
121
179
  // );
122
180
 
123
181
  VALUE args = rb_ary_new();
124
- rb_ary_push(args, Data_Wrap_Struct(cObjectsNode,NULL,NULL,me));
182
+ rb_ary_push(args, Data_Wrap_Struct(cObjectNode,NULL,NULL,me));
125
183
  for (int i = 0; i < inputSize; i++) {
126
184
  VALUE ret = extract_value(input[i]);
127
185
  rb_ary_push(args,rb_ary_entry(ret,0));
@@ -220,10 +278,9 @@ static VALUE node_add_method(int argc, VALUE* argv, VALUE self) { //{{{
220
278
  return node_wrap(CLASS_OF(self),node_alloc(parent->master,node_add_method_ua_simple(nstr,parent,opts,blk)));
221
279
  } //}}}
222
280
 
223
- 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) { //{{{
281
+ static UA_NodeId node_add_variable_ua(UA_Int32 type, UA_NodeId n, UA_LocalizedText dn, UA_QualifiedName qn, node_struct *parent, UA_Byte accesslevelmask) { //{{{
224
282
  UA_VariableAttributes vAttr = UA_VariableAttributes_default;
225
283
  vAttr.displayName = dn;
226
-
227
284
  vAttr.accessLevel = accesslevelmask;
228
285
 
229
286
  UA_Server_addVariableNode(parent->master->master,
@@ -231,34 +288,30 @@ static UA_NodeId node_add_variable_ua(UA_Int32 type, UA_NodeId n, UA_LocalizedTe
231
288
  parent->id,
232
289
  UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
233
290
  qn,
234
- UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
291
+ UA_NODEID_NUMERIC(0, type),
235
292
  vAttr,
236
293
  NULL,
237
294
  NULL);
238
295
 
239
- if (ref != Qnil) {
240
- UA_Server_addReference(parent->master->master,
241
- n,
242
- UA_NODEID_NUMERIC(0, UA_NS0ID_HASMODELLINGRULE),
243
- UA_EXPANDEDNODEID_NUMERIC(0, type),
244
- true);
245
- }
296
+ UA_Server_addReference(parent->master->master,
297
+ n,
298
+ UA_NODEID_NUMERIC(0, UA_NS0ID_HASMODELLINGRULE),
299
+ UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_MODELLINGRULE_MANDATORY),
300
+ true);
246
301
 
247
302
  return n;
248
-
249
303
  } //}}}
250
- static UA_NodeId node_add_variable_ua_simple(UA_Int32 type, char* nstr, node_struct *parent, VALUE ref, UA_Byte accesslevelmask,bool numeric) { //{{{
304
+ static UA_NodeId node_add_variable_ua_simple(UA_Int32 type, char* nstr, node_struct *parent, UA_Byte accesslevelmask, bool numeric) { //{{{
251
305
  return node_add_variable_ua(
252
306
  type,
253
307
  numeric ? UA_NODEID_NUMERIC(parent->master->default_ns,nodecounter++) : UA_NODEID_STRING(parent->master->default_ns,nstr),
254
308
  UA_LOCALIZEDTEXT("en-US", nstr),
255
309
  UA_QUALIFIEDNAME(parent->master->default_ns, nstr),
256
310
  parent,
257
- ref,
258
311
  accesslevelmask
259
312
  );
260
313
  } //}}}
261
- static VALUE node_add_variable_wrap(int argc, VALUE* argv, VALUE self, UA_Byte accesslevelmask,bool numeric) { //{{{
314
+ static VALUE node_add_variable_wrap(int argc, VALUE* argv, VALUE self, UA_Byte accesslevelmask, bool numeric) { //{{{
262
315
  node_struct *parent;
263
316
 
264
317
  if (argc > 2 || argc == 0) { // there should only be 1 or 2 arguments
@@ -269,7 +322,7 @@ static VALUE node_add_variable_wrap(int argc, VALUE* argv, VALUE self, UA_Byte a
269
322
  if (argc == 2 && argv[1] != Qnil) {
270
323
  type = NUM2INT(argv[1]);
271
324
  } else {
272
- type = UA_NS0ID_MODELLINGRULE_MANDATORY;
325
+ type = UA_NS0ID_BASEDATAVARIABLETYPE;
273
326
  }
274
327
 
275
328
  Data_Get_Struct(self, node_struct, parent);
@@ -279,7 +332,7 @@ static VALUE node_add_variable_wrap(int argc, VALUE* argv, VALUE self, UA_Byte a
279
332
  rb_raise(rb_eTypeError, "cannot convert obj to string");
280
333
  char *nstr = (char *)StringValuePtr(str);
281
334
 
282
- return node_wrap(cVarNode,node_alloc(parent->master,node_add_variable_ua_simple(type,nstr,parent,argv[1],accesslevelmask,numeric)));
335
+ return node_wrap(cVarNode,node_alloc(parent->master,node_add_variable_ua_simple(type,nstr,parent,accesslevelmask,numeric)));
283
336
  } //}}}
284
337
  static VALUE node_add_variable(int argc, VALUE* argv, VALUE self) { //{{{
285
338
  return node_add_variable_wrap(argc,argv,self,UA_ACCESSLEVELMASK_READ,true);
@@ -364,7 +417,7 @@ static VALUE node_add_object(int argc, VALUE* argv, VALUE self) { //{{{
364
417
  type = UA_NS0ID_MODELLINGRULE_MANDATORY;
365
418
  }
366
419
 
367
- if (!(rb_obj_is_kind_of(argv[1],cTypesTopNode) || rb_obj_is_kind_of(argv[1],cTypesSubNode))) {
420
+ if (!(rb_obj_is_kind_of(argv[1],cTypeTopNode) || rb_obj_is_kind_of(argv[1],cTypeSubNode))) {
368
421
  rb_raise(rb_eArgError, "argument 2 has to be a type.");
369
422
  }
370
423
 
@@ -401,12 +454,24 @@ static bool node_get_reference(UA_Server *server, UA_NodeId parent, UA_NodeId *r
401
454
  UA_BrowseDescription_init(&bDes);
402
455
  bDes.nodeId = parent;
403
456
  bDes.resultMask = UA_BROWSERESULTMASK_ALL;
404
- UA_BrowseResult bRes = UA_Server_browse(server, 3, &bDes);
457
+ UA_BrowseResult bRes = UA_Server_browse(server, 999, &bDes);
405
458
 
406
459
  if (bRes.referencesSize > 0) {
407
460
  UA_ReferenceDescription *ref = &(bRes.references[0]);
408
461
 
409
- *result = ref->nodeId.nodeId;
462
+ UA_NodeId_copy(&ref->nodeId.nodeId,result);
463
+
464
+ UA_QualifiedName qn; UA_QualifiedName_init(&qn);
465
+ UA_Server_readBrowseName(server, ref->nodeId.nodeId, &qn);
466
+
467
+ // printf("NS: %d ---> NodeId %u; %-16.*s\n",
468
+ // ref->nodeId.nodeId.namespaceIndex,
469
+ // ref->nodeId.nodeId.identifier.numeric,
470
+ // (int)qn.name.length,
471
+ // qn.name.data
472
+ // );
473
+
474
+ UA_BrowseResult_deleteMembers(&bRes);
410
475
  UA_BrowseResult_clear(&bRes);
411
476
  return true;
412
477
  }
@@ -480,7 +545,18 @@ static UA_StatusCode node_manifest_iter(UA_NodeId child_id, UA_Boolean is_invers
480
545
  free(newparent);
481
546
  }
482
547
  if(nc == UA_NODECLASS_VARIABLE) {
483
- node_add_variable_ua(UA_NS0ID_MODELLINGRULE_MANDATORY,UA_NODEID_STRING(parent->master->default_ns,buffer),dn,qn,newnode,Qtrue,al);
548
+ UA_QualifiedName pqn;UA_QualifiedName_init(&pqn);
549
+ UA_Server_readBrowseName(parent->master->master, UA_NODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE), &pqn);
550
+ UA_BrowsePathResult property = node_browse_path(parent->master->master, child_id, UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION), pqn);
551
+
552
+ if (property.statusCode == UA_STATUSCODE_GOOD) {
553
+ node_add_variable_ua(UA_NS0ID_PROPERTYTYPE,UA_NODEID_STRING(parent->master->default_ns,buffer),dn,qn,newnode,al);
554
+ } else {
555
+ node_add_variable_ua(UA_NS0ID_BASEDATAVARIABLETYPE,UA_NODEID_STRING(parent->master->default_ns,buffer),dn,qn,newnode,al);
556
+ }
557
+
558
+ UA_BrowsePathResult_clear(&property);
559
+ UA_QualifiedName_clear(&pqn);
484
560
  }
485
561
  if(nc == UA_NODECLASS_METHOD) {
486
562
  UA_NodeId ttt;
@@ -512,7 +588,7 @@ static VALUE node_manifest(VALUE self, VALUE name, VALUE parent) { //{{{
512
588
  node_struct *ns;
513
589
  node_struct *ts;
514
590
 
515
- if (!(rb_obj_is_kind_of(parent,cTypesTopNode) || rb_obj_is_kind_of(parent,cTypesSubNode))) {
591
+ if (!(rb_obj_is_kind_of(parent,cTypeTopNode) || rb_obj_is_kind_of(parent,cTypeSubNode))) {
516
592
  rb_raise(rb_eArgError, "argument 2 has to be a type.");
517
593
  }
518
594
 
@@ -569,13 +645,64 @@ static VALUE node_find(VALUE self, VALUE qname) { //{{{
569
645
  } else if (nc == UA_NODECLASS_METHOD) {
570
646
  node = node_wrap(cMethodNode,node_alloc(ns->master,ret));
571
647
  } else {
572
- node = node_wrap(cObjectsNode,node_alloc(ns->master,ret));
648
+ node = node_wrap(cObjectNode,node_alloc(ns->master,ret));
573
649
  }
574
650
  UA_NodeClass_clear(&nc);
575
651
 
576
652
  return node;
577
653
  }
578
654
  } //}}}
655
+ static VALUE server_get(int argc, VALUE* argv, VALUE self) { //{{{
656
+ if (argc > 2 || argc < 1) { // there should only be 1 or 2 arguments
657
+ rb_raise(rb_eArgError, "wrong number of arguments");
658
+ }
659
+
660
+ server_struct *pss;
661
+ Data_Get_Struct(self, server_struct, pss);
662
+
663
+ VALUE ns = UINT2NUM(pss->default_ns);
664
+ VALUE id;
665
+
666
+ if (argc == 1) {
667
+ id = argv[0];
668
+ } else {
669
+ ns = argv[0];
670
+ id = argv[1];
671
+ }
672
+
673
+ if (NIL_P(ns) || TYPE(ns) != T_FIXNUM)
674
+ rb_raise(rb_eTypeError, "ns is not a valid (numeric) namespace id");
675
+
676
+ UA_NodeId it;
677
+
678
+ if (TYPE(id) == T_FIXNUM) {
679
+ it = UA_NODEID_NUMERIC(NUM2INT(ns), NUM2INT(id));
680
+ } else {
681
+ VALUE str = rb_obj_as_string(id);
682
+ if (NIL_P(str) || TYPE(str) != T_STRING)
683
+ rb_raise(rb_eTypeError, "cannot convert url to string");
684
+ char *nstr = (char *)StringValuePtr(str);
685
+
686
+ it = UA_NODEID_STRING(NUM2INT(ns), nstr);
687
+ }
688
+
689
+ UA_NodeClass nc;UA_NodeClass_init(&nc);
690
+ UA_Server_readNodeClass(pss->master, it, &nc);
691
+
692
+ VALUE node;
693
+ if (nc == UA_NODECLASS_VARIABLE) {
694
+ node = node_wrap(cVarNode,node_alloc(pss, it));
695
+ } else if (nc == UA_NODECLASS_METHOD) {
696
+ node = node_wrap(cNode,node_alloc(pss, it));
697
+ } else if (nc == UA_NODECLASS_UNSPECIFIED) {
698
+ node = Qnil;
699
+ } else {
700
+ node = node_wrap(cNode,node_alloc(pss, it));
701
+ }
702
+ UA_NodeClass_clear(&nc);
703
+
704
+ return node;
705
+ } //}}}
579
706
 
580
707
  static VALUE node_value_set(VALUE self, VALUE value) { //{{{
581
708
  node_struct *ns;
@@ -583,6 +710,14 @@ static VALUE node_value_set(VALUE self, VALUE value) { //{{{
583
710
 
584
711
  UA_Variant variant;
585
712
  if (value_to_variant(value,&variant)) {
713
+ // printf("-----------------------------------------%ld\n",variant.arrayDimensionsSize);
714
+ if (variant.arrayDimensionsSize > 0) {
715
+ UA_Server_writeValueRank(ns->master->master, ns->id, variant.arrayDimensionsSize);
716
+ UA_Variant uaArrayDimensions;
717
+ UA_Variant_setArray(&uaArrayDimensions, variant.arrayDimensions, variant.arrayDimensionsSize, &UA_TYPES[UA_TYPES_UINT32]);
718
+ UA_Server_writeArrayDimensions(ns->master->master, ns->id, uaArrayDimensions);
719
+ }
720
+
586
721
  UA_Server_writeValue(ns->master->master, ns->id, variant);
587
722
  }
588
723
  return self;
@@ -603,6 +738,36 @@ static VALUE node_value(VALUE self) { //{{{
603
738
  }
604
739
 
605
740
  UA_Variant_clear(&value);
741
+ return rb_ary_entry(ret,0);
742
+ } //}}}
743
+ static VALUE node_description_set(VALUE self, VALUE value) { //{{{
744
+ node_struct *ns;
745
+ Data_Get_Struct(self, node_struct, ns);
746
+
747
+ VALUE str = rb_obj_as_string(value);
748
+ if (NIL_P(str) || TYPE(str) != T_STRING)
749
+ rb_raise(rb_eTypeError, "cannot convert obj to string");
750
+ char *nstr = (char *)StringValuePtr(str);
751
+ UA_LocalizedText lt = UA_LOCALIZEDTEXT("en-US",nstr);
752
+
753
+ UA_Server_writeDescription(ns->master->master, ns->id, lt);
754
+ return self;
755
+ } //}}}
756
+ static VALUE node_description(VALUE self) { //{{{
757
+ node_struct *ns;
758
+
759
+ Data_Get_Struct(self, node_struct, ns);
760
+
761
+ UA_LocalizedText value;
762
+ UA_LocalizedText_init(&value);
763
+ UA_StatusCode retval = UA_Server_readDescription(ns->master->master, ns->id, &value);
764
+
765
+ VALUE ret = Qnil;
766
+ if (retval == UA_STATUSCODE_GOOD) {
767
+ ret = rb_str_export_locale(rb_str_new((char *)(value.text.data),value.text.length));
768
+ }
769
+
770
+ UA_LocalizedText_clear(&value);
606
771
  return ret;
607
772
  } //}}}
608
773
 
@@ -668,12 +833,17 @@ static VALUE server_add_namespace(VALUE self, VALUE name) { //{{{
668
833
  static VALUE server_types(VALUE self) { //{{{
669
834
  server_struct *pss;
670
835
  Data_Get_Struct(self, server_struct, pss);
671
- return node_wrap(cTypesTopNode, node_alloc(pss, UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE)));
836
+ return node_wrap(cTypeTopNode, node_alloc(pss, UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE)));
837
+ } //}}}
838
+ static VALUE server_references(VALUE self) { //{{{
839
+ server_struct *pss;
840
+ Data_Get_Struct(self, server_struct, pss);
841
+ return node_wrap(cReferenceTopNode, node_alloc(pss, UA_NODEID_NUMERIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES)));
672
842
  } //}}}
673
843
  static VALUE server_objects(VALUE self) { //{{{
674
844
  server_struct *pss;
675
845
  Data_Get_Struct(self, server_struct, pss);
676
- return node_wrap(cObjectsNode, node_alloc(pss, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER)));
846
+ return node_wrap(cObjectNode, node_alloc(pss, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER)));
677
847
  } //}}}
678
848
  static VALUE server_debug(VALUE self) { //{{{
679
849
  server_struct *pss;
@@ -694,6 +864,23 @@ static VALUE server_debug_set(VALUE self, VALUE val) { //{{{
694
864
  }
695
865
  return self;
696
866
  } //}}}
867
+ static VALUE server_namespaces(VALUE self) { //{{{
868
+ server_struct *pss;
869
+ Data_Get_Struct(self, server_struct, pss);
870
+
871
+ UA_Variant value;
872
+ UA_Variant_init(&value);
873
+ UA_StatusCode retval = UA_Server_readValue(pss->master, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_NAMESPACEARRAY), &value);
874
+
875
+ VALUE ret = Qnil;
876
+ if (retval == UA_STATUSCODE_GOOD) {
877
+ ret = extract_value(value);
878
+ }
879
+
880
+ UA_Variant_clear(&value);
881
+ RB_OBJ_FREEZE(ret);
882
+ return rb_ary_entry(ret,0);
883
+ } //}}}
697
884
 
698
885
  void Init_server(void) {
699
886
  mOPCUA = rb_define_module("OPCUA");
@@ -701,45 +888,53 @@ void Init_server(void) {
701
888
  rb_define_const(mOPCUA, "MANDATORYPLACEHOLDER", INT2NUM(UA_NS0ID_MODELLINGRULE_MANDATORYPLACEHOLDER));
702
889
  rb_define_const(mOPCUA, "OPTIONAL", INT2NUM(UA_NS0ID_MODELLINGRULE_OPTIONAL));
703
890
  rb_define_const(mOPCUA, "OPTIONALPLACEHOLDER", INT2NUM(UA_NS0ID_MODELLINGRULE_OPTIONALPLACEHOLDER));
891
+ rb_define_const(mOPCUA, "BASEDATAVARIABLETYPE", INT2NUM(UA_NS0ID_BASEDATAVARIABLETYPE));
892
+ rb_define_const(mOPCUA, "PROPERTYTYPE", INT2NUM(UA_NS0ID_PROPERTYTYPE));
704
893
 
705
894
  Init_types();
706
895
 
707
- cServer = rb_define_class_under(mOPCUA, "Server", rb_cObject);
708
- cObjectsNode = rb_define_class_under(mOPCUA, "cObjectsNode", rb_cObject);
709
- cTypesTopNode = rb_define_class_under(mOPCUA, "cTypesTopNode", rb_cObject);
710
- cTypesSubNode = rb_define_class_under(mOPCUA, "cTypesSubNode", rb_cObject);
711
- cVarNode = rb_define_class_under(mOPCUA, "cVarNode", rb_cObject);
712
- cMethodNode = rb_define_class_under(mOPCUA, "cMethodNode", rb_cObject);
896
+ cServer = rb_define_class_under(mOPCUA, "Server", rb_cObject);
897
+ cNode = rb_define_class_under(cServer, "Node", rb_cObject);
898
+ cObjectNode = rb_define_class_under(cServer, "ObjectNode", cNode);
899
+ cTypeTopNode = rb_define_class_under(cServer, "TypeTopNode", cNode);
900
+ cTypeSubNode = rb_define_class_under(cServer, "TypeSubNode", cNode);
901
+ cReferenceTopNode = rb_define_class_under(cServer, "ReferenceTopNode", cNode);
902
+ cReferenceSubNode = rb_define_class_under(cServer, "ReferenceSubNode", cNode);
903
+ cReferenceNode = rb_define_class_under(cServer, "ObjectReferenceNode", cNode);
904
+ cVarNode = rb_define_class_under(cServer, "ObjectVarNode", cNode);
905
+ cMethodNode = rb_define_class_under(cServer, "ObjectMethodNode", cNode);
713
906
 
714
907
  rb_define_alloc_func(cServer, server_alloc);
715
908
  rb_define_method(cServer, "initialize", server_init, 0);
716
909
  rb_define_method(cServer, "run", server_run, 0);
717
910
  rb_define_method(cServer, "add_namespace", server_add_namespace, 1);
718
911
  rb_define_method(cServer, "types", server_types, 0);
912
+ rb_define_method(cServer, "references", server_references, 0);
719
913
  rb_define_method(cServer, "objects", server_objects, 0);
720
914
  rb_define_method(cServer, "debug", server_debug, 0);
721
915
  rb_define_method(cServer, "debug=", server_debug_set, 1);
916
+ rb_define_method(cServer, "namespaces", server_namespaces, 0);
917
+ rb_define_method(cServer, "get", server_get, -1);
918
+
919
+ rb_define_method(cNode, "to_s", node_to_s, 0);
920
+ rb_define_method(cNode, "id", node_id, 0);
921
+ rb_define_method(cNode, "description", node_description, 0);
922
+ rb_define_method(cNode, "description=", node_description_set, 1);
923
+
924
+ rb_define_method(cTypeTopNode, "add_object_type", node_add_object_type, 1);
925
+ rb_define_method(cTypeTopNode, "add_reference_type", node_add_reference_type, 1);
926
+ rb_define_method(cTypeTopNode, "folder", node_type_folder, 0);
927
+
928
+ rb_define_method(cTypeSubNode, "add_object_type", node_add_object_type, 1);
929
+ rb_define_method(cTypeSubNode, "add_variable", node_add_variable, -1);
930
+ rb_define_method(cTypeSubNode, "add_variable_rw", node_add_variable_rw, -1);
931
+ rb_define_method(cTypeSubNode, "add_object", node_add_object, -1);
932
+ rb_define_method(cTypeSubNode, "add_method", node_add_method, -1);
933
+ rb_define_method(cTypeSubNode, "add_reference", node_add_reference, 2);
934
+
935
+ rb_define_method(cObjectNode, "manifest", node_manifest, 2);
936
+ rb_define_method(cObjectNode, "find", node_find, 1);
722
937
 
723
- rb_define_method(cTypesTopNode, "add_object_type", node_add_object_type, 1);
724
- rb_define_method(cTypesTopNode, "folder", node_type_folder, 0);
725
- rb_define_method(cTypesSubNode, "add_object_type", node_add_object_type, 1);
726
- rb_define_method(cTypesSubNode, "add_variable", node_add_variable, -1);
727
- rb_define_method(cTypesSubNode, "add_variable_rw", node_add_variable_rw, -1);
728
- rb_define_method(cTypesSubNode, "add_object", node_add_object, -1);
729
- rb_define_method(cTypesSubNode, "add_method", node_add_method, -1);
730
- rb_define_method(cTypesSubNode, "to_s", node_to_s, 0);
731
- rb_define_method(cTypesSubNode, "id", node_id, 0);
732
-
733
- rb_define_method(cObjectsNode, "manifest", node_manifest, 2);
734
- rb_define_method(cObjectsNode, "find", node_find, 1);
735
- rb_define_method(cObjectsNode, "to_s", node_to_s, 0);
736
- rb_define_method(cObjectsNode, "id", node_id, 0);
737
-
738
- rb_define_method(cVarNode, "to_s", node_to_s, 0);
739
- rb_define_method(cVarNode, "id", node_id, 0);
740
938
  rb_define_method(cVarNode, "value", node_value, 0);
741
939
  rb_define_method(cVarNode, "value=", node_value_set, 1);
742
-
743
- rb_define_method(cMethodNode, "to_s", node_to_s, 0);
744
- rb_define_method(cMethodNode, "id", node_id, 0);
745
940
  }