From 61a82bc7d4914df482b21eae142feb62bde789c1 Mon Sep 17 00:00:00 2001 From: Jelena Mihajlovic Date: Wed, 11 Jun 2025 15:05:26 +0300 Subject: [PATCH 01/13] Add double type --- README.md | 3 +++ ext/opcua_client/opcua_client.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/README.md b/README.md index f4a8f0d..f3e0d61 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,7 @@ All methods raise OPCUAClient::Error if unsuccessful. * ```client.read_int32(Fixnum ns, String name) => Fixnum``` * ```client.read_uint32(Fixnum ns, String name) => Fixnum``` * ```client.read_float(Fixnum ns, String name) => Float``` +* ```client.read_double(Fixnum ns, String name) => Double``` * ```client.read_boolean(Fixnum ns, String name) => true/false``` * ```client.read_string(Fixnum ns, String name) => String``` * ```client.multi_read(Fixnum ns, Array[String] names) => Array values``` @@ -67,6 +68,7 @@ All methods raise OPCUAClient::Error if unsuccessful. * ```client.write_int32(Fixnum ns, String name, Fixnum value)``` * ```client.write_uint32(Fixnum ns, String name, Fixnum value)``` * ```client.write_float(Fixnum ns, String name, Float value)``` +* ```client.write_double(Fixnum ns, String name, Double value)``` * ```client.write_boolean(Fixnum ns, String name, bool value)``` * ```client.write_string(Fixnum ns, String name, String value)``` * ```client.multi_write_int16(Fixnum ns, Array[String] names, Array[Fixnum] values)``` @@ -74,6 +76,7 @@ All methods raise OPCUAClient::Error if unsuccessful. * ```client.multi_write_int32(Fixnum ns, Array[String] names, Array[Fixnum] values)``` * ```client.multi_write_uint32(Fixnum ns, Array[String] names, Array[Fixnum] values)``` * ```client.multi_write_float(Fixnum ns, Array[String] names, Array[Float] values)``` +* ```client.multi_write_double(Fixnum ns, Array[String] names, Array[Double] values)``` * ```client.multi_write_boolean(Fixnum ns, Array[String] names, Array[bool] values)``` * ```client.multi_write_string(Fixnum ns, Array[String] names, Array[String] values)``` diff --git a/ext/opcua_client/opcua_client.c b/ext/opcua_client/opcua_client.c index 9e97024..6134c7d 100644 --- a/ext/opcua_client/opcua_client.c +++ b/ext/opcua_client/opcua_client.c @@ -422,6 +422,9 @@ static VALUE rb_readUaValues(VALUE self, VALUE v_nsIndex, VALUE v_aryNames) { } else if (UA_Variant_hasScalarType(&readValues[i], &UA_TYPES[UA_TYPES_FLOAT])) { UA_Float val = *(UA_Float*)readValues[i].data; rubyVal = DBL2NUM(val); + } else if (UA_Variant_hasScalarType(&readValues[i], &UA_TYPES[UA_TYPES_DOUBLE])) { + UA_Float val = *(UA_Double*)readValues[i].data; + rubyVal = DBL2NUM(val); } else if (UA_Variant_hasScalarType(&readValues[i], &UA_TYPES[UA_TYPES_STRING])) { UA_String val = *(UA_String*)readValues[i].data; rubyVal = rb_utf8_str_new(val.data, val.length); @@ -520,6 +523,12 @@ static VALUE rb_writeUaValues(VALUE self, VALUE v_nsIndex, VALUE v_aryNames, VAL values[i].data = UA_malloc(sizeof(UA_Float)); *(UA_Float*)values[i].data = newValue; values[i].type = &UA_TYPES[uaType]; + } else if (uaType == UA_TYPES_DOUBLE) { + Check_Type(v_newValue, T_DOUBLE); + UA_Double newValue = NUM2DBL(v_newValue); + values[i].data = UA_malloc(sizeof(UA_Double)); + *(UA_Float*)values[i].data = newValue; + values[i].type = &UA_TYPES[uaType]; } else if (uaType == UA_TYPES_BOOLEAN) { if (RB_TYPE_P(v_newValue, T_TRUE) != 1 && RB_TYPE_P(v_newValue, T_FALSE) != 1) { return raise_invalid_arguments_error(); @@ -612,6 +621,11 @@ static VALUE rb_writeUaValue(VALUE self, VALUE v_nsIndex, VALUE v_name, VALUE v_ value.data = UA_malloc(sizeof(UA_Float)); *(UA_Float*)value.data = newValue; value.type = &UA_TYPES[UA_TYPES_FLOAT]; + } else if (uaType == UA_TYPES_DOUBLE) { + UA_Double newValue = NUM2DBL(v_newValue); + value.data = UA_malloc(sizeof(UA_Double)); + *(UA_Double*)value.data = newValue; + value.type = &UA_TYPES[UA_TYPES_DOUBLE]; } else if (uaType == UA_TYPES_BOOLEAN) { UA_Boolean newValue = RTEST(v_newValue); value.data = UA_malloc(sizeof(UA_Boolean)); @@ -690,6 +704,14 @@ static VALUE rb_writeFloatValues(VALUE self, VALUE v_nsIndex, VALUE v_aryNames, return rb_writeUaValues(self, v_nsIndex, v_aryNames, v_aryNewValues, UA_TYPES_FLOAT); } +static VALUE rb_writeDoubleValue(VALUE self, VALUE v_nsIndex, VALUE v_name, VALUE v_newValue) { + return rb_writeUaValue(self, v_nsIndex, v_name, v_newValue, UA_TYPES_DOUBLE); +} + +static VALUE rb_writeDoubleValues(VALUE self, VALUE v_nsIndex, VALUE v_aryNames, VALUE v_aryNewValues) { + return rb_writeUaValues(self, v_nsIndex, v_aryNames, v_aryNewValues, UA_TYPES_DOUBLE); +} + static VALUE rb_writeStringValue(VALUE self, VALUE v_nsIndex, VALUE v_name, VALUE v_newValue) { return rb_writeUaValue(self, v_nsIndex, v_name, v_newValue, UA_TYPES_STRING); } @@ -748,6 +770,9 @@ static VALUE rb_readUaValue(VALUE self, VALUE v_nsIndex, VALUE v_name, int type) } else if (type == UA_TYPES_FLOAT && UA_Variant_hasScalarType(&value, &UA_TYPES[UA_TYPES_FLOAT])) { UA_Float val =*(UA_Float*)value.data; result = DBL2NUM(val); + } else if (type == UA_TYPES_DOUBLE && UA_Variant_hasScalarType(&value, &UA_TYPES[UA_TYPES_DOUBLE])) { + UA_Double val =*(UA_Double*)value.data; + result = DBL2NUM(val); } else if (type == UA_TYPES_STRING && UA_Variant_hasScalarType(&value, &UA_TYPES[UA_TYPES_STRING])) { UA_String val =*(UA_String*)value.data; result = rb_utf8_str_new(val.data, val.length); @@ -786,6 +811,10 @@ static VALUE rb_readFloatValue(VALUE self, VALUE v_nsIndex, VALUE v_name) { return rb_readUaValue(self, v_nsIndex, v_name, UA_TYPES_FLOAT); } +static VALUE rb_readDoubleValue(VALUE self, VALUE v_nsIndex, VALUE v_name) { + return rb_readUaValue(self, v_nsIndex, v_name, UA_TYPES_DOUBLE); +} + static VALUE rb_readStringValue(VALUE self, VALUE v_nsIndex, VALUE v_name) { return rb_readUaValue(self, v_nsIndex, v_name, UA_TYPES_STRING); } @@ -876,6 +905,7 @@ void Init_opcua_client() rb_define_method(cClient, "read_int32", rb_readInt32Value, 2); rb_define_method(cClient, "read_uint32", rb_readUInt32Value, 2); rb_define_method(cClient, "read_float", rb_readFloatValue, 2); + rb_define_method(cClient, "read_double", rb_readDoubleValue, 2); rb_define_method(cClient, "read_boolean", rb_readBooleanValue, 2); rb_define_method(cClient, "read_bool", rb_readBooleanValue, 2); rb_define_method(cClient, "read_string", rb_readStringValue, 2); @@ -885,6 +915,7 @@ void Init_opcua_client() rb_define_method(cClient, "write_int32", rb_writeInt32Value, 3); rb_define_method(cClient, "write_uint32", rb_writeUInt32Value, 3); rb_define_method(cClient, "write_float", rb_writeFloatValue, 3); + rb_define_method(cClient, "write_double", rb_writeDoubleValue, 3); rb_define_method(cClient, "write_boolean", rb_writeBooleanValue, 3); rb_define_method(cClient, "write_bool", rb_writeBooleanValue, 3); rb_define_method(cClient, "write_string", rb_writeStringValue, 3); @@ -894,6 +925,7 @@ void Init_opcua_client() rb_define_method(cClient, "multi_write_int32", rb_writeInt32Values, 3); rb_define_method(cClient, "multi_write_uint32", rb_writeUInt32Values, 3); rb_define_method(cClient, "multi_write_float", rb_writeFloatValues, 3); + rb_define_method(cClient, "multi_write_double", rb_writeDoubleValues, 3); rb_define_method(cClient, "multi_write_boolean", rb_writeBooleanValues, 3); rb_define_method(cClient, "multi_write_bool", rb_writeBooleanValues, 3); rb_define_method(cClient, "multi_write_string", rb_writeStringValues, 3); From 748de6a67d5fe4aaa17d90b5515c677969ca5077 Mon Sep 17 00:00:00 2001 From: Jelena Mihajlovic Date: Thu, 12 Jun 2025 10:14:04 +0300 Subject: [PATCH 02/13] Update to T_FLOAT --- ext/opcua_client/opcua_client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/opcua_client/opcua_client.c b/ext/opcua_client/opcua_client.c index 6134c7d..9c0ed0b 100644 --- a/ext/opcua_client/opcua_client.c +++ b/ext/opcua_client/opcua_client.c @@ -524,7 +524,7 @@ static VALUE rb_writeUaValues(VALUE self, VALUE v_nsIndex, VALUE v_aryNames, VAL *(UA_Float*)values[i].data = newValue; values[i].type = &UA_TYPES[uaType]; } else if (uaType == UA_TYPES_DOUBLE) { - Check_Type(v_newValue, T_DOUBLE); + Check_Type(v_newValue, T_FLOAT); UA_Double newValue = NUM2DBL(v_newValue); values[i].data = UA_malloc(sizeof(UA_Double)); *(UA_Float*)values[i].data = newValue; From 9f5821fd02e6013d52315ca9f1535f793ccce558 Mon Sep 17 00:00:00 2001 From: Jelena Mihajlovic Date: Thu, 12 Jun 2025 11:02:52 +0300 Subject: [PATCH 03/13] Add byte type --- ext/opcua_client/opcua_client.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/ext/opcua_client/opcua_client.c b/ext/opcua_client/opcua_client.c index 9c0ed0b..b306e12 100644 --- a/ext/opcua_client/opcua_client.c +++ b/ext/opcua_client/opcua_client.c @@ -636,6 +636,12 @@ static VALUE rb_writeUaValue(VALUE self, VALUE v_nsIndex, VALUE v_name, VALUE v_ value.data = UA_malloc(sizeof(UA_String)); UA_String_copy(&newValue, (UA_String*)value.data); value.type = &UA_TYPES[UA_TYPES_STRING]; + } else if (uaType == UA_TYPES_BYTE) { + Check_Type(v_newValue, T_FIXNUM); + UA_Byte newValue = NUM2BYTE(v_newValue); + value.data = UA_malloc(sizeof(UA_Byte)); + *(UA_Byte*)value.data = newValue; + value.type = &UA_TYPES[UA_TYPES_BYTE]; } else { rb_raise(cError, "Unsupported type"); } @@ -720,6 +726,14 @@ static VALUE rb_writeStringValues(VALUE self, VALUE v_nsIndex, VALUE v_aryNames, return rb_writeUaValues(self, v_nsIndex, v_aryNames, v_aryNewValues, UA_TYPES_STRING); } +static VALUE rb_writeByteValue(VALUE self, VALUE v_nsIndex, VALUE v_name, VALUE v_newValue) { + return rb_writeUaValue(self, v_nsIndex, v_name, v_newValue, UA_TYPES_BYTE); +} + +static VALUE rb_writeByteValues(VALUE self, VALUE v_nsIndex, VALUE v_aryNames, VALUE v_aryNewValues) { + return rb_writeUaValues(self, v_nsIndex, v_aryNames, v_aryNewValues, UA_TYPES_BYTE); +} + static VALUE rb_readUaValue(VALUE self, VALUE v_nsIndex, VALUE v_name, int type) { if (RB_TYPE_P(v_name, T_STRING) != 1) { return raise_invalid_arguments_error(); @@ -776,6 +790,9 @@ static VALUE rb_readUaValue(VALUE self, VALUE v_nsIndex, VALUE v_name, int type) } else if (type == UA_TYPES_STRING && UA_Variant_hasScalarType(&value, &UA_TYPES[UA_TYPES_STRING])) { UA_String val =*(UA_String*)value.data; result = rb_utf8_str_new(val.data, val.length); + } else if (type == UA_TYPES_BYTE && UA_Variant_hasScalarType(&value, &UA_TYPES[UA_TYPES_BYTE])) { + UA_Byte val = *(UA_Byte*)value.data; + result = INT2FIX(val); } else { rb_raise(cError, "UA type mismatch"); return Qnil; @@ -819,6 +836,14 @@ static VALUE rb_readStringValue(VALUE self, VALUE v_nsIndex, VALUE v_name) { return rb_readUaValue(self, v_nsIndex, v_name, UA_TYPES_STRING); } +static VALUE rb_readByteValue(VALUE self, VALUE v_nsIndex, VALUE v_name) { + return rb_readUaValue(self, v_nsIndex, v_name, UA_TYPES_BYTE); +} + +static VALUE rb_readByteValues(VALUE self, VALUE v_nsIndex, VALUE v_aryNames) { + return rb_readUaValues(self, v_nsIndex, v_aryNames, UA_TYPES_BYTE); +} + static VALUE rb_get_human_UA_StatusCode(VALUE self, VALUE v_code) { if (RB_TYPE_P(v_code, T_FIXNUM) == 1) { unsigned int code = FIX2UINT(v_code); @@ -909,6 +934,8 @@ void Init_opcua_client() rb_define_method(cClient, "read_boolean", rb_readBooleanValue, 2); rb_define_method(cClient, "read_bool", rb_readBooleanValue, 2); rb_define_method(cClient, "read_string", rb_readStringValue, 2); + rb_define_method(cClient, "read_byte", rb_readByteValue, 2); + rb_define_method(cClient, "read_bytes", rb_readByteValues, 2); rb_define_method(cClient, "write_int16", rb_writeInt16Value, 3); rb_define_method(cClient, "write_uint16", rb_writeUInt16Value, 3); @@ -919,6 +946,8 @@ void Init_opcua_client() rb_define_method(cClient, "write_boolean", rb_writeBooleanValue, 3); rb_define_method(cClient, "write_bool", rb_writeBooleanValue, 3); rb_define_method(cClient, "write_string", rb_writeStringValue, 3); + rb_define_method(cClient, "write_byte", rb_writeByteValue, 3); + rb_define_method(cClient, "write_bytes", rb_writeByteValues, 3); rb_define_method(cClient, "multi_write_int16", rb_writeInt16Values, 3); rb_define_method(cClient, "multi_write_uint16", rb_writeUInt16Values, 3); From 8c89e8134fa2053c7730f97aab6679bca1626976 Mon Sep 17 00:00:00 2001 From: Jelena Mihajlovic Date: Thu, 12 Jun 2025 11:05:57 +0300 Subject: [PATCH 04/13] Remove read & write bytes --- ext/opcua_client/opcua_client.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/ext/opcua_client/opcua_client.c b/ext/opcua_client/opcua_client.c index b306e12..b1f433f 100644 --- a/ext/opcua_client/opcua_client.c +++ b/ext/opcua_client/opcua_client.c @@ -730,10 +730,6 @@ static VALUE rb_writeByteValue(VALUE self, VALUE v_nsIndex, VALUE v_name, VALUE return rb_writeUaValue(self, v_nsIndex, v_name, v_newValue, UA_TYPES_BYTE); } -static VALUE rb_writeByteValues(VALUE self, VALUE v_nsIndex, VALUE v_aryNames, VALUE v_aryNewValues) { - return rb_writeUaValues(self, v_nsIndex, v_aryNames, v_aryNewValues, UA_TYPES_BYTE); -} - static VALUE rb_readUaValue(VALUE self, VALUE v_nsIndex, VALUE v_name, int type) { if (RB_TYPE_P(v_name, T_STRING) != 1) { return raise_invalid_arguments_error(); @@ -840,10 +836,6 @@ static VALUE rb_readByteValue(VALUE self, VALUE v_nsIndex, VALUE v_name) { return rb_readUaValue(self, v_nsIndex, v_name, UA_TYPES_BYTE); } -static VALUE rb_readByteValues(VALUE self, VALUE v_nsIndex, VALUE v_aryNames) { - return rb_readUaValues(self, v_nsIndex, v_aryNames, UA_TYPES_BYTE); -} - static VALUE rb_get_human_UA_StatusCode(VALUE self, VALUE v_code) { if (RB_TYPE_P(v_code, T_FIXNUM) == 1) { unsigned int code = FIX2UINT(v_code); @@ -935,7 +927,6 @@ void Init_opcua_client() rb_define_method(cClient, "read_bool", rb_readBooleanValue, 2); rb_define_method(cClient, "read_string", rb_readStringValue, 2); rb_define_method(cClient, "read_byte", rb_readByteValue, 2); - rb_define_method(cClient, "read_bytes", rb_readByteValues, 2); rb_define_method(cClient, "write_int16", rb_writeInt16Value, 3); rb_define_method(cClient, "write_uint16", rb_writeUInt16Value, 3); @@ -947,7 +938,6 @@ void Init_opcua_client() rb_define_method(cClient, "write_bool", rb_writeBooleanValue, 3); rb_define_method(cClient, "write_string", rb_writeStringValue, 3); rb_define_method(cClient, "write_byte", rb_writeByteValue, 3); - rb_define_method(cClient, "write_bytes", rb_writeByteValues, 3); rb_define_method(cClient, "multi_write_int16", rb_writeInt16Values, 3); rb_define_method(cClient, "multi_write_uint16", rb_writeUInt16Values, 3); From 0f0f75901bafb6702072205088b67c2edd390089 Mon Sep 17 00:00:00 2001 From: Jelena Mihajlovic Date: Thu, 12 Jun 2025 11:09:31 +0300 Subject: [PATCH 05/13] Convert number to int before converting to byte --- ext/opcua_client/opcua_client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/opcua_client/opcua_client.c b/ext/opcua_client/opcua_client.c index b1f433f..36c8918 100644 --- a/ext/opcua_client/opcua_client.c +++ b/ext/opcua_client/opcua_client.c @@ -638,7 +638,7 @@ static VALUE rb_writeUaValue(VALUE self, VALUE v_nsIndex, VALUE v_name, VALUE v_ value.type = &UA_TYPES[UA_TYPES_STRING]; } else if (uaType == UA_TYPES_BYTE) { Check_Type(v_newValue, T_FIXNUM); - UA_Byte newValue = NUM2BYTE(v_newValue); + UA_Byte newValue = (UA_Byte)NUM2UINT(v_newValue); value.data = UA_malloc(sizeof(UA_Byte)); *(UA_Byte*)value.data = newValue; value.type = &UA_TYPES[UA_TYPES_BYTE]; From 5a2ff57b23bcf77ad7745c4267e400a9ae67eff5 Mon Sep 17 00:00:00 2001 From: Jelena Mihajlovic Date: Thu, 12 Jun 2025 11:23:43 +0300 Subject: [PATCH 06/13] Add int list read/write --- README.md | 3 +++ ext/opcua_client/opcua_client.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/README.md b/README.md index f3e0d61..515f6ac 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,8 @@ All methods raise OPCUAClient::Error if unsuccessful. * ```client.read_double(Fixnum ns, String name) => Double``` * ```client.read_boolean(Fixnum ns, String name) => true/false``` * ```client.read_string(Fixnum ns, String name) => String``` +* ```client.read_byte(Fixnum ns, String name) => Byte``` +* ```client.read_uint32_list(Fixnum ns, String name) => Array[Fixnum]``` * ```client.multi_read(Fixnum ns, Array[String] names) => Array values``` * ```client.write_int16(Fixnum ns, String name, Fixnum value)``` * ```client.write_uint16(Fixnum ns, String name, Fixnum value)``` @@ -71,6 +73,7 @@ All methods raise OPCUAClient::Error if unsuccessful. * ```client.write_double(Fixnum ns, String name, Double value)``` * ```client.write_boolean(Fixnum ns, String name, bool value)``` * ```client.write_string(Fixnum ns, String name, String value)``` +* ```client.write_uint32_list(Fixnum ns, String name, Array[Fixnum] value)``` * ```client.multi_write_int16(Fixnum ns, Array[String] names, Array[Fixnum] values)``` * ```client.multi_write_uint16(Fixnum ns, Array[String] names, Array[Fixnum] values)``` * ```client.multi_write_int32(Fixnum ns, Array[String] names, Array[Fixnum] values)``` diff --git a/ext/opcua_client/opcua_client.c b/ext/opcua_client/opcua_client.c index 36c8918..2bbc573 100644 --- a/ext/opcua_client/opcua_client.c +++ b/ext/opcua_client/opcua_client.c @@ -611,6 +611,19 @@ static VALUE rb_writeUaValue(VALUE self, VALUE v_nsIndex, VALUE v_name, VALUE v_ value.data = UA_malloc(sizeof(UA_Int32)); *(UA_Int32*)value.data = newValue; value.type = &UA_TYPES[UA_TYPES_INT32]; + } else if (uaType == UA_TYPES_UINT32 && RB_TYPE_P(v_newValue, T_ARRAY)) { + size_t arrayLength = RARRAY_LEN(v_newValue); + UA_UInt32 *arrayData = UA_malloc(sizeof(UA_UInt32) * arrayLength); + + for (size_t i = 0; i < arrayLength; i++) { + VALUE element = rb_ary_entry(v_newValue, i); + Check_Type(element, T_FIXNUM); + arrayData[i] = NUM2UINT(element); + } + + value.data = arrayData; + value.arrayLength = arrayLength; + value.type = &UA_TYPES[UA_TYPES_UINT32]; } else if (uaType == UA_TYPES_UINT32) { UA_UInt32 newValue = NUM2UINT(v_newValue); value.data = UA_malloc(sizeof(UA_UInt32)); @@ -694,6 +707,10 @@ static VALUE rb_writeUInt32Values(VALUE self, VALUE v_nsIndex, VALUE v_aryNames, return rb_writeUaValues(self, v_nsIndex, v_aryNames, v_aryNewValues, UA_TYPES_UINT32); } +static VALUE rb_writeUint32List(VALUE self, VALUE v_nsIndex, VALUE v_name, VALUE v_newValue) { + return rb_writeUaValue(self, v_nsIndex, v_name, v_newValue, UA_TYPES_UINT32); +} + static VALUE rb_writeBooleanValue(VALUE self, VALUE v_nsIndex, VALUE v_name, VALUE v_newValue) { return rb_writeUaValue(self, v_nsIndex, v_name, v_newValue, UA_TYPES_BOOLEAN); } @@ -771,6 +788,14 @@ static VALUE rb_readUaValue(VALUE self, VALUE v_nsIndex, VALUE v_name, int type) } else if (type == UA_TYPES_INT32 && UA_Variant_hasScalarType(&value, &UA_TYPES[UA_TYPES_INT32])) { UA_Int32 val =*(UA_Int32*)value.data; result = INT2FIX(val); + } else if (type == UA_TYPES_UINT32 && UA_Variant_hasArrayType(&value, &UA_TYPES[UA_TYPES_UINT32])) { + size_t arrayLength = value.arrayLength; + UA_UInt32 *arrayData = (UA_UInt32 *)value.data; + + result = rb_ary_new(); + for (size_t i = 0; i < arrayLength; i++) { + rb_ary_push(result, INT2FIX(arrayData[i])); + } } else if (type == UA_TYPES_UINT32 && UA_Variant_hasScalarType(&value, &UA_TYPES[UA_TYPES_UINT32])) { UA_UInt32 val =*(UA_UInt32*)value.data; result = INT2FIX(val); @@ -816,6 +841,10 @@ static VALUE rb_readUInt32Value(VALUE self, VALUE v_nsIndex, VALUE v_name) { return rb_readUaValue(self, v_nsIndex, v_name, UA_TYPES_UINT32); } +static VALUE rb_readUint32List(VALUE self, VALUE v_nsIndex, VALUE v_name) { + return rb_readUaValue(self, v_nsIndex, v_name, UA_TYPES_UINT32); +} + static VALUE rb_readBooleanValue(VALUE self, VALUE v_nsIndex, VALUE v_name) { return rb_readUaValue(self, v_nsIndex, v_name, UA_TYPES_BOOLEAN); } @@ -927,6 +956,7 @@ void Init_opcua_client() rb_define_method(cClient, "read_bool", rb_readBooleanValue, 2); rb_define_method(cClient, "read_string", rb_readStringValue, 2); rb_define_method(cClient, "read_byte", rb_readByteValue, 2); + rb_define_method(cClient, "read_uint32_list", rb_readUint32List, 2); rb_define_method(cClient, "write_int16", rb_writeInt16Value, 3); rb_define_method(cClient, "write_uint16", rb_writeUInt16Value, 3); @@ -938,6 +968,7 @@ void Init_opcua_client() rb_define_method(cClient, "write_bool", rb_writeBooleanValue, 3); rb_define_method(cClient, "write_string", rb_writeStringValue, 3); rb_define_method(cClient, "write_byte", rb_writeByteValue, 3); + rb_define_method(cClient, "write_uint32_list", rb_writeUint32List, 3); rb_define_method(cClient, "multi_write_int16", rb_writeInt16Values, 3); rb_define_method(cClient, "multi_write_uint16", rb_writeUInt16Values, 3); From 66cf0069d1a213cbe6e3e335b817511c83cc08e6 Mon Sep 17 00:00:00 2001 From: Jelena Mihajlovic Date: Thu, 12 Jun 2025 11:42:14 +0300 Subject: [PATCH 07/13] Add int32 list read/write --- ext/opcua_client/opcua_client.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/ext/opcua_client/opcua_client.c b/ext/opcua_client/opcua_client.c index 2bbc573..d724353 100644 --- a/ext/opcua_client/opcua_client.c +++ b/ext/opcua_client/opcua_client.c @@ -606,6 +606,19 @@ static VALUE rb_writeUaValue(VALUE self, VALUE v_nsIndex, VALUE v_name, VALUE v_ value.data = UA_malloc(sizeof(UA_UInt16)); *(UA_UInt16*)value.data = newValue; value.type = &UA_TYPES[UA_TYPES_UINT16]; + } else if (uaType == UA_TYPES_INT32 && RB_TYPE_P(v_newValue, T_ARRAY)) { + size_t arrayLength = RARRAY_LEN(v_newValue); + UA_Int32 *arrayData = UA_malloc(sizeof(UA_Int32) * arrayLength); + + for (size_t i = 0; i < arrayLength; i++) { + VALUE element = rb_ary_entry(v_newValue, i); + Check_Type(element, T_FIXNUM); + arrayData[i] = NUM2INT(element); + } + + value.data = arrayData; + value.arrayLength = arrayLength; + value.type = &UA_TYPES[UA_TYPES_INT32]; } else if (uaType == UA_TYPES_INT32) { UA_Int32 newValue = NUM2INT(v_newValue); value.data = UA_malloc(sizeof(UA_Int32)); @@ -699,6 +712,10 @@ static VALUE rb_writeInt32Values(VALUE self, VALUE v_nsIndex, VALUE v_aryNames, return rb_writeUaValues(self, v_nsIndex, v_aryNames, v_aryNewValues, UA_TYPES_INT32); } +static VALUE rb_writeInt32List(VALUE self, VALUE v_nsIndex, VALUE v_name, VALUE v_newValue) { + return rb_writeUaValue(self, v_nsIndex, v_name, v_newValue, UA_TYPES_INT32); +} + static VALUE rb_writeUInt32Value(VALUE self, VALUE v_nsIndex, VALUE v_name, VALUE v_newValue) { return rb_writeUaValue(self, v_nsIndex, v_name, v_newValue, UA_TYPES_UINT32); } @@ -785,6 +802,14 @@ static VALUE rb_readUaValue(VALUE self, VALUE v_nsIndex, VALUE v_name, int type) UA_UInt16 val =*(UA_UInt16*)value.data; // printf("the value is: %i\n", val); result = INT2FIX(val); + } else if (type == UA_TYPES_INT32 && UA_Variant_hasArrayType(&value, &UA_TYPES[UA_TYPES_INT32])) { + size_t arrayLength = value.arrayLength; + UA_Int32 *arrayData = (UA_Int32 *)value.data; + + result = rb_ary_new(); + for (size_t i = 0; i < arrayLength; i++) { + rb_ary_push(result, INT2FIX(arrayData[i])); + } } else if (type == UA_TYPES_INT32 && UA_Variant_hasScalarType(&value, &UA_TYPES[UA_TYPES_INT32])) { UA_Int32 val =*(UA_Int32*)value.data; result = INT2FIX(val); @@ -837,6 +862,10 @@ static VALUE rb_readInt32Value(VALUE self, VALUE v_nsIndex, VALUE v_name) { return rb_readUaValue(self, v_nsIndex, v_name, UA_TYPES_INT32); } +static VALUE rb_readInt32List(VALUE self, VALUE v_nsIndex, VALUE v_name) { + return rb_readUaValue(self, v_nsIndex, v_name, UA_TYPES_INT32); +} + static VALUE rb_readUInt32Value(VALUE self, VALUE v_nsIndex, VALUE v_name) { return rb_readUaValue(self, v_nsIndex, v_name, UA_TYPES_UINT32); } @@ -957,6 +986,7 @@ void Init_opcua_client() rb_define_method(cClient, "read_string", rb_readStringValue, 2); rb_define_method(cClient, "read_byte", rb_readByteValue, 2); rb_define_method(cClient, "read_uint32_list", rb_readUint32List, 2); + rb_define_method(cClient, "read_int32_list", rb_readInt32List, 2); rb_define_method(cClient, "write_int16", rb_writeInt16Value, 3); rb_define_method(cClient, "write_uint16", rb_writeUInt16Value, 3); @@ -969,6 +999,7 @@ void Init_opcua_client() rb_define_method(cClient, "write_string", rb_writeStringValue, 3); rb_define_method(cClient, "write_byte", rb_writeByteValue, 3); rb_define_method(cClient, "write_uint32_list", rb_writeUint32List, 3); + rb_define_method(cClient, "write_int32_list", rb_writeInt32List, 3); rb_define_method(cClient, "multi_write_int16", rb_writeInt16Values, 3); rb_define_method(cClient, "multi_write_uint16", rb_writeUInt16Values, 3); From df06a6d3cf43adb0deca73201eeb0d07a41c0c5a Mon Sep 17 00:00:00 2001 From: Jelena Mihajlovic Date: Thu, 12 Jun 2025 11:49:42 +0300 Subject: [PATCH 08/13] Add int32 list to docs --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 515f6ac..219984b 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,7 @@ All methods raise OPCUAClient::Error if unsuccessful. * ```client.read_string(Fixnum ns, String name) => String``` * ```client.read_byte(Fixnum ns, String name) => Byte``` * ```client.read_uint32_list(Fixnum ns, String name) => Array[Fixnum]``` +* ```client.read_int32_list(Fixnum ns, String name) => Array[Fixnum]``` * ```client.multi_read(Fixnum ns, Array[String] names) => Array values``` * ```client.write_int16(Fixnum ns, String name, Fixnum value)``` * ```client.write_uint16(Fixnum ns, String name, Fixnum value)``` @@ -74,6 +75,7 @@ All methods raise OPCUAClient::Error if unsuccessful. * ```client.write_boolean(Fixnum ns, String name, bool value)``` * ```client.write_string(Fixnum ns, String name, String value)``` * ```client.write_uint32_list(Fixnum ns, String name, Array[Fixnum] value)``` +* ```client.write_int32_list(Fixnum ns, String name, Array[Fixnum] value)``` * ```client.multi_write_int16(Fixnum ns, Array[String] names, Array[Fixnum] values)``` * ```client.multi_write_uint16(Fixnum ns, Array[String] names, Array[Fixnum] values)``` * ```client.multi_write_int32(Fixnum ns, Array[String] names, Array[Fixnum] values)``` From 306ea8824f72473f803773997166d1be467e5bd5 Mon Sep 17 00:00:00 2001 From: Jelena Mihajlovic Date: Thu, 12 Jun 2025 13:22:27 +0300 Subject: [PATCH 09/13] Add multiwrite byte and array[int32] values --- README.md | 3 +++ ext/opcua_client/opcua_client.c | 10 ++++++++++ 2 files changed, 13 insertions(+) diff --git a/README.md b/README.md index 219984b..f7e4e36 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,9 @@ All methods raise OPCUAClient::Error if unsuccessful. * ```client.multi_write_double(Fixnum ns, Array[String] names, Array[Double] values)``` * ```client.multi_write_boolean(Fixnum ns, Array[String] names, Array[bool] values)``` * ```client.multi_write_string(Fixnum ns, Array[String] names, Array[String] values)``` +* ```client.multi_write_byte(Fixnum ns, Array[String] names, Array[Byte] values)``` +* ```client.multi_write_int32_list(Fixnum ns, Array[String] names, Array[Array[Fixnum]] values)``` + ### Available methods - misc: diff --git a/ext/opcua_client/opcua_client.c b/ext/opcua_client/opcua_client.c index d724353..3a6e546 100644 --- a/ext/opcua_client/opcua_client.c +++ b/ext/opcua_client/opcua_client.c @@ -728,6 +728,10 @@ static VALUE rb_writeUint32List(VALUE self, VALUE v_nsIndex, VALUE v_name, VALUE return rb_writeUaValue(self, v_nsIndex, v_name, v_newValue, UA_TYPES_UINT32); } +static VALUE rb_writeInt32ListValues(VALUE self, VALUE v_nsIndex, VALUE v_aryNames, VALUE v_aryNewValues) { + return rb_writeUaValues(self, v_nsIndex, v_aryNames, v_aryNewValues, UA_TYPES_INT32); +} + static VALUE rb_writeBooleanValue(VALUE self, VALUE v_nsIndex, VALUE v_name, VALUE v_newValue) { return rb_writeUaValue(self, v_nsIndex, v_name, v_newValue, UA_TYPES_BOOLEAN); } @@ -764,6 +768,10 @@ static VALUE rb_writeByteValue(VALUE self, VALUE v_nsIndex, VALUE v_name, VALUE return rb_writeUaValue(self, v_nsIndex, v_name, v_newValue, UA_TYPES_BYTE); } +static VALUE rb_writeByteValues(VALUE self, VALUE v_nsIndex, VALUE v_aryNames, VALUE v_aryNewValues) { + return rb_writeUaValues(self, v_nsIndex, v_aryNames, v_aryNewValues, UA_TYPES_BYTE); +} + static VALUE rb_readUaValue(VALUE self, VALUE v_nsIndex, VALUE v_name, int type) { if (RB_TYPE_P(v_name, T_STRING) != 1) { return raise_invalid_arguments_error(); @@ -1010,6 +1018,8 @@ void Init_opcua_client() rb_define_method(cClient, "multi_write_boolean", rb_writeBooleanValues, 3); rb_define_method(cClient, "multi_write_bool", rb_writeBooleanValues, 3); rb_define_method(cClient, "multi_write_string", rb_writeStringValues, 3); + rb_define_method(cClient, "multi_write_byte", rb_writeByteValues, 3); + rb_define_method(cClient, "multi_write_uint32_list", rb_writeUint32ListValues, 3); rb_define_method(cClient, "multi_read", rb_readUaValues, 2); From fdd52a583524f9fb91d016631ffa861f162603ba Mon Sep 17 00:00:00 2001 From: Jelena Mihajlovic Date: Thu, 12 Jun 2025 13:25:52 +0300 Subject: [PATCH 10/13] Fix method call --- ext/opcua_client/opcua_client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/opcua_client/opcua_client.c b/ext/opcua_client/opcua_client.c index 3a6e546..a26f0e0 100644 --- a/ext/opcua_client/opcua_client.c +++ b/ext/opcua_client/opcua_client.c @@ -1019,7 +1019,7 @@ void Init_opcua_client() rb_define_method(cClient, "multi_write_bool", rb_writeBooleanValues, 3); rb_define_method(cClient, "multi_write_string", rb_writeStringValues, 3); rb_define_method(cClient, "multi_write_byte", rb_writeByteValues, 3); - rb_define_method(cClient, "multi_write_uint32_list", rb_writeUint32ListValues, 3); + rb_define_method(cClient, "multi_write_int32_list", rb_writeint32ListValues, 3); rb_define_method(cClient, "multi_read", rb_readUaValues, 2); From bff0e57ad20ea0570f3a65aa31c33072ca98dcce Mon Sep 17 00:00:00 2001 From: Jelena Mihajlovic Date: Thu, 12 Jun 2025 13:26:42 +0300 Subject: [PATCH 11/13] Fix method call --- ext/opcua_client/opcua_client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/opcua_client/opcua_client.c b/ext/opcua_client/opcua_client.c index a26f0e0..ac859a2 100644 --- a/ext/opcua_client/opcua_client.c +++ b/ext/opcua_client/opcua_client.c @@ -1019,7 +1019,7 @@ void Init_opcua_client() rb_define_method(cClient, "multi_write_bool", rb_writeBooleanValues, 3); rb_define_method(cClient, "multi_write_string", rb_writeStringValues, 3); rb_define_method(cClient, "multi_write_byte", rb_writeByteValues, 3); - rb_define_method(cClient, "multi_write_int32_list", rb_writeint32ListValues, 3); + rb_define_method(cClient, "multi_write_int32_list", rb_writeInt32ListValues, 3); rb_define_method(cClient, "multi_read", rb_readUaValues, 2); From d5800be56cfbf378f791f5c645bd51ff18448059 Mon Sep 17 00:00:00 2001 From: Jelena Mihajlovic Date: Thu, 12 Jun 2025 14:18:32 +0300 Subject: [PATCH 12/13] Update rb_writeUaValues for multi write byte and multi write int32 list --- ext/opcua_client/opcua_client.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/ext/opcua_client/opcua_client.c b/ext/opcua_client/opcua_client.c index ac859a2..ffa8863 100644 --- a/ext/opcua_client/opcua_client.c +++ b/ext/opcua_client/opcua_client.c @@ -543,7 +543,26 @@ static VALUE rb_writeUaValues(VALUE self, VALUE v_nsIndex, VALUE v_aryNames, VAL values[i].data = UA_malloc(sizeof(UA_String)); UA_String_copy(&newValue, (UA_String*)values[i].data); values[i].type = &UA_TYPES[uaType]; - } else { + } else if (uaType == UA_TYPES_BYTE) { + Check_Type(v_newValue, T_FIXNUM); + UA_Byte newValue = (UA_Byte)NUM2UINT(v_newValue); + values[i].data = UA_malloc(sizeof(UA_Byte)); + *(UA_Byte*)values[i].data = newValue; + values[i].type = &UA_TYPES[uaType]; + } else if (uaType == UA_TYPES_INT32 && RB_TYPE_P(v_newValue, T_ARRAY)) { + size_t arrayLength = RARRAY_LEN(v_newValue); + UA_Int32 *arrayData = UA_malloc(sizeof(UA_Int32) * arrayLength); + + for (size_t j = 0; j < arrayLength; j++) { + VALUE element = rb_ary_entry(v_newValue, j); + Check_Type(element, T_FIXNUM); + arrayData[j] = NUM2INT(element); + } + + values[i].data = arrayData; + values[i].arrayLength = arrayLength; + values[i].type = &UA_TYPES[UA_TYPES_INT32]; + } else { rb_raise(cError, "Unsupported type"); } } @@ -668,7 +687,8 @@ static VALUE rb_writeUaValue(VALUE self, VALUE v_nsIndex, VALUE v_name, VALUE v_ value.data = UA_malloc(sizeof(UA_Byte)); *(UA_Byte*)value.data = newValue; value.type = &UA_TYPES[UA_TYPES_BYTE]; - } else { + } + else { rb_raise(cError, "Unsupported type"); } From 8c04c851a9a59768d376f15678c2fa2b2cfbdea8 Mon Sep 17 00:00:00 2001 From: Jelena Mihajlovic Date: Thu, 12 Jun 2025 14:22:14 +0300 Subject: [PATCH 13/13] Move up int32 list condition --- ext/opcua_client/opcua_client.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/ext/opcua_client/opcua_client.c b/ext/opcua_client/opcua_client.c index ffa8863..ce3cae8 100644 --- a/ext/opcua_client/opcua_client.c +++ b/ext/opcua_client/opcua_client.c @@ -511,6 +511,19 @@ static VALUE rb_writeUaValues(VALUE self, VALUE v_nsIndex, VALUE v_aryNames, VAL values[i].data = UA_malloc(sizeof(UA_UInt32)); *(UA_UInt32*)values[i].data = newValue; values[i].type = &UA_TYPES[uaType]; + } else if (uaType == UA_TYPES_INT32 && RB_TYPE_P(v_newValue, T_ARRAY)) { + size_t arrayLength = RARRAY_LEN(v_newValue); + UA_Int32 *arrayData = UA_malloc(sizeof(UA_Int32) * arrayLength); + + for (size_t j = 0; j < arrayLength; j++) { + VALUE element = rb_ary_entry(v_newValue, j); + Check_Type(element, T_FIXNUM); + arrayData[j] = NUM2INT(element); + } + + values[i].data = arrayData; + values[i].arrayLength = arrayLength; + values[i].type = &UA_TYPES[UA_TYPES_INT32]; } else if (uaType == UA_TYPES_INT32) { Check_Type(v_newValue, T_FIXNUM); UA_Int32 newValue = NUM2INT(v_newValue); @@ -549,20 +562,7 @@ static VALUE rb_writeUaValues(VALUE self, VALUE v_nsIndex, VALUE v_aryNames, VAL values[i].data = UA_malloc(sizeof(UA_Byte)); *(UA_Byte*)values[i].data = newValue; values[i].type = &UA_TYPES[uaType]; - } else if (uaType == UA_TYPES_INT32 && RB_TYPE_P(v_newValue, T_ARRAY)) { - size_t arrayLength = RARRAY_LEN(v_newValue); - UA_Int32 *arrayData = UA_malloc(sizeof(UA_Int32) * arrayLength); - - for (size_t j = 0; j < arrayLength; j++) { - VALUE element = rb_ary_entry(v_newValue, j); - Check_Type(element, T_FIXNUM); - arrayData[j] = NUM2INT(element); - } - - values[i].data = arrayData; - values[i].arrayLength = arrayLength; - values[i].type = &UA_TYPES[UA_TYPES_INT32]; - } else { + } else { rb_raise(cError, "Unsupported type"); } }