Browse Source

Functions UA_Variant_borrowSetValue and ..Array

This allows to define variants whose payload will not be deleted.
It is achieved by a second vtable. This functionality can be used
e.g. when UA_VariableNodes point into a "father" structured object
that is stored in an UA_VariableNode itself.
Julius Pfrommer 10 years ago
parent
commit
46485918e3
4 changed files with 60 additions and 61 deletions
  1. 8 2
      include/ua_basictypes.h
  2. 4 4
      src/ua_basictypes.c
  3. 2 1
      src/ua_services_attribute.c
  4. 46 54
      tools/generate_namespace.py

+ 8 - 2
include/ua_basictypes.h

@@ -240,11 +240,17 @@ typedef struct UA_Variant {
 } UA_Variant;
 UA_TYPE_METHOD_PROTOTYPES (UA_Variant)
 
-UA_Int32 UA_Variant_setValue(UA_Variant *v, UA_Int32 type, const void* data); // Take care! Data is freed together with the Variant
 UA_Int32 UA_Variant_copySetValue(UA_Variant *v, UA_Int32 type, const void* data);
-UA_Int32 UA_Variant_setArray(UA_Variant *v, UA_Int32 type, UA_Int32 arrayLength, const void* data); // Take care! Data is freed together with the Variant
 UA_Int32 UA_Variant_copySetArray(UA_Variant *v, UA_Int32 type_id, UA_Int32 arrayLength, UA_UInt32 elementSize, const void* array);
 
+/**
+   @brief Functions UA_Variant_borrowSetValue and ..Array allow to define
+ variants whose payload will not be deleted. This is achieved by a second
+ vtable. The functionality can be used e.g. when UA_VariableNodes point into a
+ "father" structured object that is stored in an UA_VariableNode itself. */
+UA_Int32 UA_Variant_borrowSetValue(UA_Variant *v, UA_Int32 type, const void* data); // Take care not to free the data before the variant.
+UA_Int32 UA_Variant_borrowSetArray(UA_Variant *v, UA_Int32 type, UA_Int32 arrayLength, const void* data); // Take care not to free the data before the variant.
+
 /* String - Part: 6, Chapter: 5.2.2.4, Page: 16 */
 typedef struct UA_String
 {

+ 4 - 4
src/ua_basictypes.c

@@ -1529,10 +1529,10 @@ UA_Int32 UA_Variant_copy(UA_Variant const *src, UA_Variant *dst)
 	return retval;
 }
 
-UA_Int32 UA_Variant_setValue(UA_Variant *v, UA_Int32 type_id, const void* value) {
+UA_Int32 UA_Variant_borrowSetValue(UA_Variant *v, UA_Int32 type_id, const void* value) {
 	v->encodingMask = type_id & UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK;
 	if(UA_VTable_isValidType(type_id) != UA_SUCCESS) return UA_INVALIDTYPE;
-	v->vt = &UA_[type_id];
+	v->vt = &UA_noDelete_[type_id];
 	v->data = (void*) value;
 	return UA_SUCCESS;
 }
@@ -1544,10 +1544,10 @@ UA_Int32 UA_Variant_copySetValue(UA_Variant *v, UA_Int32 type_id, const void* va
 	return v->vt->copy(value, v->data);
 }
 
-UA_Int32 UA_Variant_setArray(UA_Variant *v, UA_Int32 type_id, UA_Int32 arrayLength, const void* array) {
+UA_Int32 UA_Variant_borrowSetArray(UA_Variant *v, UA_Int32 type_id, UA_Int32 arrayLength, const void* array) {
 	v->encodingMask = (type_id & UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK) | UA_VARIANT_ENCODINGMASKTYPE_ARRAY;
 	if(UA_VTable_isValidType(type_id) != UA_SUCCESS) return UA_INVALIDTYPE;
-	v->vt = &UA_[type_id];
+	v->vt = &UA_noDelete_[type_id];
 	v->arrayLength = arrayLength;
 	v->data = (void*) array;
 	return UA_SUCCESS;

+ 2 - 1
src/ua_services_attribute.c

@@ -120,7 +120,8 @@ static UA_DataValue *service_read_node(Application * app, const UA_ReadValueId *
 	case UA_ATTRIBUTEID_VALUE:
 		CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
 		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
-		retval |= UA_Variant_copy(&((UA_VariableNode *) node)->value, &v->value);
+		// TODO: Ensure that the borrowed value is not freed prematurely (multithreading)
+		retval |= UA_Variant_borrowSetValue(&v->value, UA_VARIANT, &((UA_VariableNode *) node)->value);
 		break;
 	case UA_ATTRIBUTEID_DATATYPE:
 		CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);

+ 46 - 54
tools/generate_namespace.py

@@ -2,20 +2,15 @@ from __future__ import print_function
 import sys
 import platform
 import getpass
-from collections import OrderedDict
 import time
-import re
-import csv
-from itertools import tee
 
 if len(sys.argv) != 3:
     print("Usage: python generate_namespace.py <path/to/NodeIds.csv> <outfile w/o extension>", file=sys.stdout)
     exit(0)
 
 # types that are to be excluded
-exclude_kind = set(["Object","ObjectType","Variable","Method","ReferenceType"])
-exclude_types = set(["Number", 
-    "Integer", "UInteger", "Enumeration",
+exclude_kinds = set(["Object","ObjectType","Variable","Method","ReferenceType"])
+exclude_types = set(["Number", "Integer", "UInteger", "Enumeration",
 	"Image", "ImageBMP", "ImageGIF", "ImageJPG", "ImagePNG",
 	"References", "BaseVariableType", "BaseDataVariableType", 
 	"PropertyType", "DataTypeDescriptionType", "DataTypeDictionaryType", "NamingRuleType",
@@ -31,24 +26,16 @@ exclude_types = set(["Number",
 	"MultiStateDiscreteType", "ProgramDiagnosticType", "StateVariableType", "FiniteStateVariableType",
 	"TransitionVariableType", "FiniteTransitionVariableType", "BuildInfoType", "TwoStateVariableType",
 	"ConditionVariableType", "MultiStateValueDiscreteType", "OptionSetType", "ArrayItemType",
-	"YArrayItemType", "XYArrayItemType", "ImageItemType", "CubeItemType", "NDimensionArrayItemType"
-	])
-	
-def skipKind(name):
-    if name in exclude_kind:
-        return True
-    return False
-    
-def skipType(name):
-    if name in exclude_types:
-        return True
-    return False
+	"YArrayItemType", "XYArrayItemType", "ImageItemType", "CubeItemType", "NDimensionArrayItemType"])
 
 f = open(sys.argv[1])
-rows1, rows2, rows3 = tee(csv.reader(f), 3)
+input_str = "InvalidType,0,DataType\n" + f.read()
+input_str = input_str.replace('\r','')
+rows = map(lambda x:tuple(x.split(',')), input_str.split('\n'))
+f.close()
 
-fh = open(sys.argv[2] + ".hgen",'w');
-fc = open(sys.argv[2] + ".cgen",'w');
+fh = open(sys.argv[2] + ".hgen",'w')
+fc = open(sys.argv[2] + ".cgen",'w')
 
 print('''/**********************************************************
  * '''+sys.argv[2]+'''.hgen -- do not modify
@@ -60,11 +47,14 @@ print('''/**********************************************************
 #ifndef OPCUA_NAMESPACE_0_H_
 #define OPCUA_NAMESPACE_0_H_
 
-#include "opcua.h"  // definition of UA_VTable and basic UA_Types
+#include "ua_basictypes.h"  // definition of UA_VTable and basic UA_Types
 
 UA_Int32 UA_ns0ToVTableIndex(UA_Int32 id);
 extern UA_VTable UA_[]; 
 
+static UA_Int32 phantom_delete(void * p) { return UA_SUCCESS; }
+extern UA_VTable UA_noDelete_[];
+
 enum UA_VTableIndex_enum {''', end='\n', file=fh)
 
 print('''/**********************************************************
@@ -81,44 +71,36 @@ UA_Int32 UA_ns0ToVTableIndex(UA_Int32 id) {
     switch (id) { ''', end='\n',file=fc)
 
 i = 0
-for row in rows1:
-    if skipKind(row[2]):
-	continue
-
-    if skipType(row[0]):
-	continue
-	
+for row in rows:
+    if row[0] == "" or row[0] in exclude_types or row[2] in exclude_kinds:
+        continue
     if row[0] == "BaseDataType":
     	name = "UA_Variant"
     elif row[0] == "Structure":
-    	name = "UA_ExtensionObject" 
-    else:	
+        name = "UA_ExtensionObject"
+    else:
 	name = "UA_" + row[0]
 	
-    print("\t"+name.upper()+"="+str(i)+",", file=fh)
+    print("\t"+name.upper()+" = "+str(i)+",", file=fh)
     print('\tcase '+row[1]+': retval='+name.upper()+'; break; //'+row[2], file=fc)
     i = i+1
 
-print('\tUA_INVALIDTYPE = '+str(i)+'\n};\n', file=fh)
-print('''\tcase 0: retval=UA_INVALIDTYPE; break;
+print("};\n", file=fh)
+print('''
     }
     return retval;
 }
 
 UA_VTable UA_[] = {''', file=fc)
 
-for row in rows2:
-    if skipKind(row[2]):
-	continue
-
-    if skipType(row[0]):
-	continue
-
+for row in rows:
+    if row[0] == "" or row[0] in exclude_types or row[2] in exclude_kinds:
+        continue
     if row[0] == "BaseDataType":
     	name = "UA_Variant"
     elif row[0] == "Structure":
-    	name = "UA_ExtensionObject" 
-    else:	
+        name = "UA_ExtensionObject"
+    else:
 	name = "UA_" + row[0]
 
     print('#define '+name.upper()+'_NS0 '+row[1], file=fh)
@@ -132,21 +114,31 @@ for row in rows2:
 	  ",(UA_Int32(*)(void const * ,void*))"+name+"_copy"+
           ",(UA_Int32(*)(void *))"+name+"_delete"+
           ',(UA_Byte*)"'+name+'"},',end='\n',file=fc) 
-name = "UA_InvalidType"
-print("\t{0" + 
+
+print("};\n\nUA_VTable UA_noDelete_[] = {", end='\n', file=fc)
+
+for row in rows:
+    if row[0] == "" or row[0] in exclude_types or row[2] in exclude_kinds:
+        continue
+    if row[0] == "BaseDataType":
+        name = "UA_Variant"
+    elif row[0] == "Structure":
+        name = "UA_ExtensionObject"
+    else:	
+	name = "UA_" + row[0]
+
+    print("\t{" + row[1] +
           ",(UA_Int32(*)(void const*))"+name+"_calcSize" + 
           ",(UA_Int32(*)(UA_ByteString const*,UA_Int32*,void*))"+name+ "_decodeBinary" +
           ",(UA_Int32(*)(void const*,UA_Int32*,UA_ByteString*))"+name+"_encodeBinary"+
           ",(UA_Int32(*)(void *))"+name+"_init"+
           ",(UA_Int32(*)(void **))"+name+"_new"+
-	  ",(UA_Int32(*)(void const *, void *))"+name+"_copy"+
-          ",(UA_Int32(*)(void *))"+name+"_delete"+
-          ',(UA_Byte*)"'+name+'"}',end='\n',file=fc)
+	  ",(UA_Int32(*)(void const * ,void*))"+name+"_copy"+
+          ",(UA_Int32(*)(void *))phantom_delete"+
+          ',(UA_Byte*)"'+name+'"},',end='\n',file=fc)
 print("};", end='\n', file=fc) 
-print('#define '+name.upper()+'_NS0 0', file=fh)
-print('#endif /* OPCUA_NAMESPACE_0_H_ */', end='\n', file=fh)
+
+print('\n#endif /* OPCUA_NAMESPACE_0_H_ */', end='\n', file=fh)
+
 fh.close()
 fc.close()
-f.close()
-
-2222