opcua 0.11 → 0.12
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +109 -6
- data/Rakefile +6 -5
- data/cert/cert.h +52 -52
- data/cert/cert_key.h +101 -101
- data/example/client_get_sync.rb +15 -0
- data/example/client_get_value.rb +16 -0
- data/example/client_set_value.rb +15 -0
- data/example/server.rb +15 -3
- data/ext/opcua/client/client.c +143 -17
- data/ext/opcua/client/client.h +1 -0
- data/ext/opcua/server/extconf.rb +1 -0
- data/ext/opcua/server/server.c +252 -57
- data/ext/opcua/values.h +206 -41
- data/lib/opcua/client.rb +11 -0
- data/lib/opcua/server.rb +51 -0
- data/opcua.gemspec +1 -1
- metadata +5 -2
data/ext/opcua/values.h
CHANGED
@@ -2,6 +2,96 @@
|
|
2
2
|
VALUE mTYPES = Qnil;
|
3
3
|
|
4
4
|
/* -- */
|
5
|
+
static void variant_set_one_dimension(UA_Variant *variant,UA_UInt32 len) {
|
6
|
+
variant->arrayDimensions = (UA_UInt32 *)UA_Array_new(1, &UA_TYPES[UA_TYPES_UINT32]);
|
7
|
+
variant->arrayDimensions[0] = len;
|
8
|
+
variant->arrayDimensionsSize = 1;
|
9
|
+
}
|
10
|
+
static bool value_to_array(VALUE value, UA_Variant *variant) {/*{{{*/
|
11
|
+
int done = false;
|
12
|
+
|
13
|
+
if (rb_obj_is_kind_of(RARRAY_AREF(value,0),rb_cTime)) {
|
14
|
+
UA_DateTime tmp[RARRAY_LEN(value)];
|
15
|
+
for (int i=0; i < RARRAY_LEN(value); i++) {
|
16
|
+
if (TYPE(RARRAY_AREF(value,i)) == T_FALSE) {
|
17
|
+
tmp[i] = UA_DateTime_fromUnixTime(rb_time_timeval(RARRAY_AREF(value,i)).tv_sec);
|
18
|
+
} else {
|
19
|
+
tmp[i] = UA_DateTime_fromUnixTime(0);
|
20
|
+
}
|
21
|
+
}
|
22
|
+
variant_set_one_dimension(variant,1);
|
23
|
+
UA_Variant_setArrayCopy(variant, tmp, RARRAY_LEN(value), &UA_TYPES[UA_TYPES_BOOLEAN]);
|
24
|
+
done = true;
|
25
|
+
} else {
|
26
|
+
switch (TYPE(RARRAY_AREF(value,0))) {
|
27
|
+
case T_TRUE:
|
28
|
+
case T_FALSE:
|
29
|
+
{
|
30
|
+
UA_Boolean tmp[RARRAY_LEN(value)];
|
31
|
+
for (int i=0; i < RARRAY_LEN(value); i++) {
|
32
|
+
if (TYPE(RARRAY_AREF(value,i)) == T_FALSE) {
|
33
|
+
tmp[i] = false;
|
34
|
+
} else {
|
35
|
+
tmp[i] = true;
|
36
|
+
}
|
37
|
+
}
|
38
|
+
variant_set_one_dimension(variant,1);
|
39
|
+
UA_Variant_setArrayCopy(variant, tmp, RARRAY_LEN(value), &UA_TYPES[UA_TYPES_BOOLEAN]);
|
40
|
+
done = true;
|
41
|
+
break;
|
42
|
+
}
|
43
|
+
case T_FLOAT:
|
44
|
+
case T_FIXNUM:
|
45
|
+
{
|
46
|
+
UA_Double tmp[RARRAY_LEN(value)];
|
47
|
+
for (int i=0; i < RARRAY_LEN(value); i++) {
|
48
|
+
if (TYPE(RARRAY_AREF(value,i)) == T_FLOAT || TYPE(RARRAY_AREF(value,i)) == T_FIXNUM) {
|
49
|
+
tmp[i] = NUM2DBL(RARRAY_AREF(value,i));
|
50
|
+
} else {
|
51
|
+
tmp[i] = 0.0;
|
52
|
+
}
|
53
|
+
}
|
54
|
+
variant_set_one_dimension(variant,1);
|
55
|
+
UA_Variant_setArrayCopy(variant, tmp, RARRAY_LEN(value), &UA_TYPES[UA_TYPES_DOUBLE]);
|
56
|
+
done = true;
|
57
|
+
break;
|
58
|
+
}
|
59
|
+
case T_STRING:
|
60
|
+
case T_SYMBOL:
|
61
|
+
{
|
62
|
+
UA_String tmp[RARRAY_LEN(value)];
|
63
|
+
for (int i=0; i < RARRAY_LEN(value); i++) {
|
64
|
+
if (TYPE(RARRAY_AREF(value,i)) == T_STRING || TYPE(RARRAY_AREF(value,i)) == T_SYMBOL) {
|
65
|
+
VALUE str = rb_obj_as_string(RARRAY_AREF(value,i));
|
66
|
+
tmp[i] = UA_STRING(StringValuePtr(str));
|
67
|
+
} else {
|
68
|
+
tmp[i] = UA_STRING("");
|
69
|
+
}
|
70
|
+
}
|
71
|
+
variant_set_one_dimension(variant,1);
|
72
|
+
UA_Variant_setArrayCopy(variant, tmp, RARRAY_LEN(value), &UA_TYPES[UA_TYPES_STRING]);
|
73
|
+
done = true;
|
74
|
+
break;
|
75
|
+
}
|
76
|
+
//////// TODO Currently only one-dimensional data structures are supported
|
77
|
+
// case T_ARRAY:
|
78
|
+
// {
|
79
|
+
// UA_Variant xxx;
|
80
|
+
// for (int i=0; i < RARRAY_LEN(value); i++) {
|
81
|
+
// for (int j=0; j < RARRAY_LEN(RARRAY_AREF(value,0)); j++) {
|
82
|
+
// if (j < RARRAY_LEN(RARRAY_AREF(value,i)) {
|
83
|
+
// } else {
|
84
|
+
// }
|
85
|
+
// }
|
86
|
+
// }
|
87
|
+
// UA_Variant_setArrayCopy(variant, tmp, RARRAY_LEN(value) * RARRAY_LEN(RARRAY_AREF(value,0)), &UA_TYPES[UA_TYPES_STRING]);
|
88
|
+
// done = true;
|
89
|
+
// break;
|
90
|
+
// }
|
91
|
+
}
|
92
|
+
}
|
93
|
+
return done;
|
94
|
+
}/*}}}*/
|
5
95
|
static bool value_to_variant(VALUE value, UA_Variant *variant) { //{{{
|
6
96
|
bool done = false;
|
7
97
|
if (rb_obj_is_kind_of(value,rb_cTime)) {
|
@@ -36,8 +126,6 @@ static bool value_to_variant(VALUE value, UA_Variant *variant) { //{{{
|
|
36
126
|
case T_SYMBOL:
|
37
127
|
{
|
38
128
|
VALUE str = rb_obj_as_string(value);
|
39
|
-
if (NIL_P(str) || TYPE(str) != T_STRING)
|
40
|
-
rb_raise(rb_eTypeError, "cannot convert obj to string");
|
41
129
|
UA_String tmp = UA_STRING(StringValuePtr(str));
|
42
130
|
UA_Variant_setScalarCopy(variant, &tmp, &UA_TYPES[UA_TYPES_STRING]);
|
43
131
|
done = true;
|
@@ -45,11 +133,10 @@ static bool value_to_variant(VALUE value, UA_Variant *variant) { //{{{
|
|
45
133
|
}
|
46
134
|
case T_ARRAY:
|
47
135
|
{
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
// UA_Variant_setArray(&attr.value, UA_Array_new(10, &UA_TYPES[type]), 10, &UA_TYPES[type]);
|
136
|
+
if (value_to_array(value,variant)) {
|
137
|
+
done = true;
|
138
|
+
}
|
139
|
+
break;
|
53
140
|
}
|
54
141
|
}
|
55
142
|
}
|
@@ -69,45 +156,123 @@ static void Init_types() {/*{{{*/
|
|
69
156
|
rb_define_const(mTYPES, "STRING", INT2NUM(UA_TYPES_STRING ));
|
70
157
|
}/*}}}*/
|
71
158
|
|
159
|
+
static VALUE UA_TYPES_DATETIME_to_value(UA_DateTime data) {
|
160
|
+
return rb_time_new(UA_DateTime_toUnixTime(data),0);
|
161
|
+
}
|
162
|
+
static VALUE UA_TYPES_BOOLEAN_to_value(UA_Boolean data) {
|
163
|
+
return data ? Qtrue : Qfalse;
|
164
|
+
}
|
165
|
+
static VALUE UA_TYPES_DOUBLE_to_value(UA_Double data) {
|
166
|
+
return DBL2NUM(data);
|
167
|
+
}
|
168
|
+
static VALUE UA_TYPES_INT32_to_value(UA_Int32 data) {
|
169
|
+
return INT2NUM(data);
|
170
|
+
}
|
171
|
+
static VALUE UA_TYPES_INT16_to_value(UA_Int16 data) {
|
172
|
+
return INT2NUM(data);
|
173
|
+
}
|
174
|
+
static VALUE UA_TYPES_UINT32_to_value(UA_UInt32 data) {
|
175
|
+
return UINT2NUM(data);
|
176
|
+
}
|
177
|
+
static VALUE UA_TYPES_UINT16_to_value(UA_UInt16 data) {
|
178
|
+
return UINT2NUM(data);
|
179
|
+
}
|
180
|
+
static VALUE UA_TYPES_STRING_to_value(UA_String data) {
|
181
|
+
return rb_str_export_locale(rb_str_new((char *)(data.data),data.length));
|
182
|
+
}
|
183
|
+
|
72
184
|
static VALUE extract_value(UA_Variant value) { //{{{
|
73
185
|
VALUE ret = rb_ary_new2(2);
|
74
186
|
rb_ary_store(ret,0,Qnil);
|
75
187
|
rb_ary_store(ret,1,Qnil);
|
76
|
-
//
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
} else if (
|
106
|
-
|
107
|
-
|
108
|
-
|
188
|
+
//printf("type: %s\n",value.type->typeName);
|
189
|
+
//printf("dim: %ld\n",value.arrayDimensionsSize);
|
190
|
+
//printf("alen: %ld\n",value.arrayLength);
|
191
|
+
if (value.arrayDimensionsSize == 0 && value.arrayLength == 0) {
|
192
|
+
if (UA_Variant_hasScalarType(&value, &UA_TYPES[UA_TYPES_DATETIME])) {
|
193
|
+
rb_ary_store(ret,0,UA_TYPES_DATETIME_to_value(*(UA_DateTime *)value.data));
|
194
|
+
rb_ary_store(ret,1,ID2SYM(rb_intern("VariantType.DateTime")));
|
195
|
+
} else if (UA_Variant_hasScalarType(&value, &UA_TYPES[UA_TYPES_BOOLEAN])) {
|
196
|
+
rb_ary_store(ret,0,UA_TYPES_BOOLEAN_to_value(*(UA_Boolean *)value.data));
|
197
|
+
rb_ary_store(ret,1,ID2SYM(rb_intern("VariantType.Boolean")));
|
198
|
+
} else if (UA_Variant_hasScalarType(&value, &UA_TYPES[UA_TYPES_DOUBLE])) {
|
199
|
+
rb_ary_store(ret,0,UA_TYPES_DOUBLE_to_value(*(UA_Double *)value.data));
|
200
|
+
rb_ary_store(ret,1,ID2SYM(rb_intern("VariantType.Double")));
|
201
|
+
} else if (UA_Variant_hasScalarType(&value, &UA_TYPES[UA_TYPES_INT32])) {
|
202
|
+
rb_ary_store(ret,0,UA_TYPES_INT32_to_value(*(UA_Int32 *)value.data));
|
203
|
+
rb_ary_store(ret,1,ID2SYM(rb_intern("VariantType.Int32")));
|
204
|
+
} else if (UA_Variant_hasScalarType(&value, &UA_TYPES[UA_TYPES_INT16])) {
|
205
|
+
rb_ary_store(ret,0,UA_TYPES_INT16_to_value(*(UA_Int16 *)value.data));
|
206
|
+
rb_ary_store(ret,1,ID2SYM(rb_intern("VariantType.Int16")));
|
207
|
+
} else if (UA_Variant_hasScalarType(&value, &UA_TYPES[UA_TYPES_UINT32])) {
|
208
|
+
rb_ary_store(ret,0,UA_TYPES_UINT32_to_value(*(UA_UInt32 *)value.data));
|
209
|
+
rb_ary_store(ret,1,ID2SYM(rb_intern("VariantType.UInt32")));
|
210
|
+
} else if (UA_Variant_hasScalarType(&value, &UA_TYPES[UA_TYPES_UINT16])) {
|
211
|
+
rb_ary_store(ret,0,UA_TYPES_UINT16_to_value(*(UA_UInt16 *)value.data));
|
212
|
+
rb_ary_store(ret,1,ID2SYM(rb_intern("VariantType.UInt16")));
|
213
|
+
} else if (UA_Variant_hasScalarType(&value, &UA_TYPES[UA_TYPES_STRING])) {
|
214
|
+
rb_ary_store(ret,0,UA_TYPES_STRING_to_value(*(UA_String *)value.data));
|
215
|
+
rb_ary_store(ret,1,ID2SYM(rb_intern("VariantType.String")));
|
216
|
+
}
|
217
|
+
} else if (value.arrayDimensionsSize == 1 || (value.arrayDimensionsSize == 0 && value.arrayLength > 0)) {
|
218
|
+
if (UA_Variant_hasArrayType(&value, &UA_TYPES[UA_TYPES_DATETIME])) {
|
219
|
+
VALUE res = rb_ary_new();
|
220
|
+
rb_ary_store(ret,0,res);
|
221
|
+
rb_ary_store(ret,1,ID2SYM(rb_intern("VariantType.DateTime")));
|
222
|
+
for (int i=0; i < value.arrayLength; i++) {
|
223
|
+
rb_ary_push(res,UA_TYPES_DATETIME_to_value(((UA_DateTime *)value.data)[i]));
|
224
|
+
}
|
225
|
+
} else if (UA_Variant_hasArrayType(&value, &UA_TYPES[UA_TYPES_BOOLEAN])) {
|
226
|
+
VALUE res = rb_ary_new();
|
227
|
+
rb_ary_store(ret,0,res);
|
228
|
+
rb_ary_store(ret,1,ID2SYM(rb_intern("VariantType.Boolean")));
|
229
|
+
for (int i=0; i < value.arrayLength; i++) {
|
230
|
+
rb_ary_push(res,UA_TYPES_BOOLEAN_to_value(((UA_Boolean *)value.data)[i]));
|
231
|
+
}
|
232
|
+
} else if (UA_Variant_hasArrayType(&value, &UA_TYPES[UA_TYPES_DOUBLE])) {
|
233
|
+
VALUE res = rb_ary_new();
|
234
|
+
rb_ary_store(ret,0,res);
|
235
|
+
rb_ary_store(ret,1,ID2SYM(rb_intern("VariantType.Double")));
|
236
|
+
for (int i=0; i < value.arrayLength; i++) {
|
237
|
+
rb_ary_push(res,UA_TYPES_DOUBLE_to_value(((UA_Double *)value.data)[i]));
|
238
|
+
}
|
239
|
+
} else if (UA_Variant_hasArrayType(&value, &UA_TYPES[UA_TYPES_INT32])) {
|
240
|
+
VALUE res = rb_ary_new();
|
241
|
+
rb_ary_store(ret,0,res);
|
242
|
+
rb_ary_store(ret,1,ID2SYM(rb_intern("VariantType.Int32")));
|
243
|
+
for (int i=0; i < value.arrayLength; i++) {
|
244
|
+
rb_ary_push(res,UA_TYPES_INT32_to_value(((UA_Int32 *)value.data)[i]));
|
245
|
+
}
|
246
|
+
} else if (UA_Variant_hasArrayType(&value, &UA_TYPES[UA_TYPES_INT16])) {
|
247
|
+
VALUE res = rb_ary_new();
|
248
|
+
rb_ary_store(ret,0,res);
|
249
|
+
rb_ary_store(ret,1,ID2SYM(rb_intern("VariantType.Int16")));
|
250
|
+
for (int i=0; i < value.arrayLength; i++) {
|
251
|
+
rb_ary_push(res,UA_TYPES_INT16_to_value(((UA_Int16 *)value.data)[i]));
|
252
|
+
}
|
253
|
+
} else if (UA_Variant_hasArrayType(&value, &UA_TYPES[UA_TYPES_UINT32])) {
|
254
|
+
VALUE res = rb_ary_new();
|
255
|
+
rb_ary_store(ret,0,res);
|
256
|
+
rb_ary_store(ret,1,ID2SYM(rb_intern("VariantType.UInt32")));
|
257
|
+
for (int i=0; i < value.arrayLength; i++) {
|
258
|
+
rb_ary_push(res,UA_TYPES_UINT32_to_value(((UA_UInt32 *)value.data)[i]));
|
259
|
+
}
|
260
|
+
} else if (UA_Variant_hasArrayType(&value, &UA_TYPES[UA_TYPES_UINT16])) {
|
261
|
+
VALUE res = rb_ary_new();
|
262
|
+
rb_ary_store(ret,0,res);
|
263
|
+
rb_ary_store(ret,1,ID2SYM(rb_intern("VariantType.UInt16")));
|
264
|
+
for (int i=0; i < value.arrayLength; i++) {
|
265
|
+
rb_ary_push(res,UA_TYPES_UINT16_to_value(((UA_UInt16 *)value.data)[i]));
|
266
|
+
}
|
267
|
+
} else if (UA_Variant_hasArrayType(&value, &UA_TYPES[UA_TYPES_STRING])) {
|
268
|
+
VALUE res = rb_ary_new();
|
269
|
+
rb_ary_store(ret,0,res);
|
270
|
+
rb_ary_store(ret,1,ID2SYM(rb_intern("VariantType.String")));
|
271
|
+
for (int i=0; i < value.arrayLength; i++) {
|
272
|
+
rb_ary_push(res,UA_TYPES_STRING_to_value(((UA_String *)value.data)[i]));
|
273
|
+
}
|
274
|
+
}
|
109
275
|
}
|
110
|
-
|
111
276
|
return ret;
|
112
277
|
} //}}}
|
113
278
|
/* ++ */
|
data/lib/opcua/client.rb
CHANGED
@@ -8,6 +8,17 @@ require 'daemonite'
|
|
8
8
|
module OPCUA
|
9
9
|
class Client
|
10
10
|
alias_method :initialize_base, :initialize
|
11
|
+
alias_method :get_base, :get
|
12
|
+
|
13
|
+
def get(*a)
|
14
|
+
if a.length == 1 && a[0].to_s =~ /ns=(\d+);i=(.*)/
|
15
|
+
get_base $1.to_i, $2.to_i
|
16
|
+
elsif a.length == 1 && a[0].to_s =~ /ns=(\d+);s=(.*)/
|
17
|
+
get_base $1.to_i, $2
|
18
|
+
else
|
19
|
+
get_base *a
|
20
|
+
end
|
21
|
+
end
|
11
22
|
|
12
23
|
def initialize(url)
|
13
24
|
if url =~ /(^[^:]+):\/\/([^:]+):([^@]+)@(.*)$/
|
data/lib/opcua/server.rb
CHANGED
@@ -4,3 +4,54 @@ else
|
|
4
4
|
require_relative 'server.so'
|
5
5
|
end
|
6
6
|
require 'daemonite'
|
7
|
+
|
8
|
+
module OPCUA
|
9
|
+
class Server
|
10
|
+
alias_method :get_base, :get
|
11
|
+
|
12
|
+
def get(*a)
|
13
|
+
if a.length == 1 && a[0].to_s =~ /ns=(\d+);i=(.*)/
|
14
|
+
get_base $1.to_i, $2.to_i
|
15
|
+
elsif a.length == 1 && a[0].to_s =~ /ns=(\d+);s=(.*)/
|
16
|
+
get_base $1.to_i, $2
|
17
|
+
else
|
18
|
+
get_base *a
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class ObjectNode
|
23
|
+
alias_method :find_one, :find
|
24
|
+
|
25
|
+
def find(*what)
|
26
|
+
if what.length == 0
|
27
|
+
nil
|
28
|
+
elsif what.length == 1
|
29
|
+
find_one what[0]
|
30
|
+
else
|
31
|
+
what.map{|e| find_one e}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class TypeSubNode
|
37
|
+
def add_property(name)
|
38
|
+
add_variable name, OPCUA::PROPERTYTYPE
|
39
|
+
end
|
40
|
+
def add_property_rw
|
41
|
+
add_variable_rw name, OPCUA::PROPERTYTYPE
|
42
|
+
end
|
43
|
+
def add_properties(*item)
|
44
|
+
item.each { |e| add_property e }
|
45
|
+
end
|
46
|
+
def add_property_rw(*item)
|
47
|
+
item.each { |e| add_property_rw e }
|
48
|
+
end
|
49
|
+
def add_variables(*item)
|
50
|
+
item.each { |e| add_variable e }
|
51
|
+
end
|
52
|
+
def add_variables_rw(*item)
|
53
|
+
item.each { |e| add_variable_rw e }
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
data/opcua.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "opcua"
|
3
|
-
s.version = "0.
|
3
|
+
s.version = "0.12"
|
4
4
|
s.platform = Gem::Platform::RUBY
|
5
5
|
s.license = "LGPL-3.0"
|
6
6
|
s.summary = "Preliminary release of opcua (open62541) ruby bindings. C performance, Ruby elegance, simplicity, and productivity."
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: opcua
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.12'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Juergen eTM Mangler
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: tools
|
11
11
|
cert_chain: []
|
12
|
-
date: 2019-06-
|
12
|
+
date: 2019-06-30 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: daemonite
|
@@ -73,7 +73,10 @@ files:
|
|
73
73
|
- Rakefile
|
74
74
|
- cert/cert.h
|
75
75
|
- cert/cert_key.h
|
76
|
+
- example/client_get_sync.rb
|
77
|
+
- example/client_get_value.rb
|
76
78
|
- example/client_method.rb
|
79
|
+
- example/client_set_value.rb
|
77
80
|
- example/client_subscription.rb
|
78
81
|
- example/kelch.KMT
|
79
82
|
- example/server.rb
|