Bläddra i källkod

first steps toward generator

Leon Urbas 11 år sedan
förälder
incheckning
bceba6587f
4 ändrade filer med 7584 tillägg och 0 borttagningar
  1. 4879 0
      tool/NodeIds.csv
  2. 2391 0
      tool/Opc.Ua.Types.bsd
  3. 235 0
      tool/generate_bulitin.py
  4. 79 0
      tool/generate_namespace.py

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 4879 - 0
tool/NodeIds.csv


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 2391 - 0
tool/Opc.Ua.Types.bsd


+ 235 - 0
tool/generate_bulitin.py

@@ -0,0 +1,235 @@
+from __future__ import print_function
+import sys
+from collections import OrderedDict
+import re
+from lxml import etree
+
+if len(sys.argv) != 3:
+    print("Usage: python generate_builtin.py <path/to/Opc.Ua.Types.bsd> <outfile w/o extension>", file=sys.stdout)
+    exit(0)
+
+# types that are coded manually
+exclude_types = set(["Boolean", "SByte", "Byte", "Int16", "UInt16", "Int32", "UInt32",
+                    "Int64", "UInt64", "Float", "Double", "String", "DateTime", "Guid",
+                    "ByteString", "XmlElement", "NodeId", "ExpandedNodeId", "StatusCode", 
+                    "QualifiedName", "LocalizedText", "ExtensionObject", "DataValue",
+                     "Variant", "DiagnosticInfo", "RequestHeader", "ResponseHeader", "NodeIdType"])
+
+elementary_size = dict()
+elementary_size["Boolean"] = 1;
+elementary_size["SByte"] = 1;
+elementary_size["Byte"] = 1;
+elementary_size["Int16"] = 2;
+elementary_size["UInt16"] = 2;
+elementary_size["Int32"] = 4;
+elementary_size["UInt32"] = 4;
+elementary_size["Int64"] = 8;
+elementary_size["UInt64"] = 8;
+elementary_size["Float"] = 4;
+elementary_size["Double"] = 8;
+elementary_size["DateTime"] = 8;
+elementary_size["StatusCode"] = 4;
+
+# indefinite_types = ["NodeId", "ExpandedNodeId", "QualifiedName", "LocalizedText", "ExtensionObject", "DataValue", "Variant", "DiagnosticInfo"]
+indefinite_types = ["ExpandedNodeId", "QualifiedName", "ExtensionObject", "DataValue", "Variant", "DiagnosticInfo"]
+enum_types = []
+                   
+# indefinite types cannot be directly contained in a record as they don't have a definite size
+printed_types = exclude_types # types that were already printed and which we can use in the structures to come
+
+# types we do not want to autogenerate
+def skipType(name):
+    if name in exclude_types:
+        return True
+    if re.search("NodeId$", name) != None:
+        return True
+    return False
+
+def stripTypename(tn):
+    return tn[tn.find(":")+1:]
+
+def camlCase2AdaCase(item):
+    (newitem, n) = re.subn("(?<!^)(?<![A-Z])([A-Z])", "_\\1", item)
+    return newitem
+
+# are the prerequisites in place? if not, postpone.
+def printableStructuredType(element):
+    for child in element:
+        if child.tag == "{http://opcfoundation.org/BinarySchema/}Field":
+            typename = stripTypename(child.get("TypeName"))
+            if typename not in printed_types:
+                return False
+    return True
+
+# There three types of types in the bsd file:
+# StructuredType, EnumeratedType OpaqueType
+
+def createEnumerated(element):
+    valuemap = OrderedDict()
+    name = "UA_" + element.get("Name")
+    enum_types.append(name)
+    print("// " + name, end='\n', file=fh)
+    for child in element:
+        if child.tag == "{http://opcfoundation.org/BinarySchema/}Documentation":
+            print("// " + child.text, end='\n', file=fh)
+        if child.tag == "{http://opcfoundation.org/BinarySchema/}EnumeratedValue":
+            valuemap[name + "_" + child.get("Name")] = child.get("Value")
+    valuemap = OrderedDict(sorted(valuemap.iteritems(), key=lambda (k,v): int(v)))
+    print("typedef UA_UInt32 " + name + ";", end='\n', file=fh);
+    print("enum " + name + "_enum { \n" + ",\n\t".join(map(lambda (key, value) : key + " = " + value, valuemap.iteritems())) + "\n};\n", end='\n', file=fh)
+    return
+    
+def createStructured(element):
+    valuemap = OrderedDict()
+    name = "UA_" + element.get("Name")
+    print("// " + name, end='\n', file=fh)
+
+    lengthfields = set()
+    for child in element:
+        if child.get("LengthField"):
+            lengthfields.add(child.get("LengthField"))
+    
+    for child in element:
+        if child.tag == "{http://opcfoundation.org/BinarySchema/}Documentation":
+            print("// " + child.text, end='\n', file=fh)
+        elif child.tag == "{http://opcfoundation.org/BinarySchema/}Field":
+            if child.get("Name") in lengthfields:
+                continue
+            childname = camlCase2AdaCase(child.get("Name"))
+            if childname in printed_types:
+                childname = childname + "_Value" # attributes may not have the name of a type
+            typename = stripTypename(child.get("TypeName"))
+            if childname == "Response_Header" or childname == "Request_Header":
+                continue
+            if typename in indefinite_types:
+                valuemap[childname] = typename + "*"
+            elif child.get("LengthField"):
+                valuemap[childname] = typename + "**"
+            else:
+                valuemap[childname] = typename
+
+    # if "Response" in name[len(name)-9:]:
+    #    print("type " + name + " is new Response_Base with "),
+    # elif "Request" in name[len(name)-9:]:
+    #    print ("type " + name + " is new Request_Base with "),
+    # else:
+    #    print ("type " + name + " is new UA_Builtin with "),
+    print("typedef struct T_" + name + " {", end='\n', file=fh)
+    if len(valuemap) > 0:
+        for n,t in valuemap.iteritems():
+            if t.find("**") != -1:
+	        print("\t" + "UInt32 " + n + "_size;", end='\n', file=fh)
+            print("\t" + "UA_" + t + " " + n + ";", end='\n', file=fh)
+    else:
+        print("// null record", end='\n', file=fh)
+    print("} " + name + ";", end='\n', file=fh)
+
+    print("Int32 " + name + "_calcSize(" + name + " const * ptr);", end='\n', file=fh)
+    print("Int32 " + name + "_encode(" + name + " const * src, Int32* pos, char* dst);", end='\n', file=fh)
+    print("Int32 " + name + "_decode(char const * src, UInt32* pos, " + name + "* dst);", end='\n', file=fh)
+
+    if "Response" in name[len(name)-9:]:
+        print("Int32 "  + name + "_calcSize(" + name + " const * ptr) {\n\treturn UA_ResponseHeader_getSize()", end='', file=fc) 
+    elif "Request" in name[len(name)-9:]:
+        print("Int32 "  + name + "_calcSize(" + name + " const * ptr) {\n\treturn UA_RequestHeader_getSize()", end='', file=fc) 
+    else:
+	# code 
+        print("Int32 "  + name + "_calcSize(" + name + " const * ptr) {\n\treturn 0", end='', file=fc)
+
+    # code _calcSize
+    for n,t in valuemap.iteritems():
+        if t in elementary_size:
+            print('\n\t + sizeof(UA_' + t + ") // " + n, end='', file=fc)
+        else:
+            if t in enum_types:
+                print('\n\t + 4 //' + n, end='', file=fc) # enums are all 32 bit
+            elif t.find("**") != -1:
+		print("\n\t + 4 //" + n + "_size", end='', file=fc),
+		print("\n\t + UA_Array_calcSize(ptr->" + n + "_size, UA_" + t[0:t.find("*")].upper() + ", (void**) ptr->" + n +")", end='', file=fc)
+            elif t.find("*") != -1:
+                print('\n\t + ' + "UA_" + t[0:t.find("*")] + "_calcSize(ptr->" + n + ')', end='', file=fc)
+            else:
+                print('\n\t + ' + "UA_" + t + "_calcSize(&(ptr->" + n + '))', end='', file=fc)
+
+    print("\n\t;\n};\n", end='\n', file=fc)
+
+    print("Int32 "+name+"_encode("+name+" const * src, Int32* pos, char* dst) {\n\tInt32 retval=0;", end='\n', file=fc)
+    # code _encode
+    for n,t in valuemap.iteritems():
+        if t in elementary_size:
+            print('\tretval |= UA_'+t+'_encode(&(src->'+n+'),pos,dst);', end='\n', file=fc)
+        else:
+            if t in enum_types:
+                print('\tretval |= UA_'+t+'_encode(&(src->'+n+'));', end='\n', file=fc)
+            elif t.find("**") != -1:
+                print('\tretval |= UA_Int32_encode(&(src->'+n+'_size)); // encode size', end='\n', file=fc)
+		print("\tretval |= UA_Array_encode((void**) (src->"+n+"),src->"+n+"_size, UA_" + t[0:t.find("*")].upper()+",pos,dst);", end='\n', file=fc)
+            elif t.find("*") != -1:
+                print('\tretval |= UA_' + t[0:t.find("*")] + "_encode(src->" + n + ',pos,dst);', end='\n', file=fc)
+            else:
+                print('\tretval |= UA_'+t+"_encode(&(src->"+n+"),pos,dst);", end='\n', file=fc)
+    print("\treturn retval;\n};\n", end='\n', file=fc)
+        
+def createOpaque(element):
+    name = "UA_" + element.get("Name")
+    print("// " + name , end='\n', file=fh)
+    for child in element:
+        if child.tag == "{http://opcfoundation.org/BinarySchema/}Documentation":
+            print("// " + child.text, end='\n', file=fh)
+
+    print("typedef void* " + name + ";\n", end='\n', file=fh)
+    return
+
+ns = {"opc": "http://opcfoundation.org/BinarySchema/"}
+tree = etree.parse(sys.argv[1])
+types = tree.xpath("/opc:TypeDictionary/*[not(self::opc:Import)]", namespaces=ns)
+
+fh = open(sys.argv[2] + ".h",'w');
+fc = open(sys.argv[2] + ".c",'w');
+print('#include "' + sys.argv[2] + '.h"', end='\n', file=fc);
+
+# types for which we create a vector type
+arraytypes = set()
+fields = tree.xpath("//opc:Field", namespaces=ns)
+for field in fields:
+    if field.get("LengthField"):
+        arraytypes.add(stripTypename(field.get("TypeName")))
+
+deferred_types = OrderedDict()
+
+print('#ifndef OPCUA_H_', end='\n', file=fh)
+print('#define OPCUA_H_', end='\n', file=fh)
+print('#include "opcua_basictypes.h"', end='\n', file=fh)
+print('#include "opcua_namespace_0.h"', end='\n', file=fh);
+
+for element in types:
+    name = element.get("Name")
+    if skipType(name):
+        continue
+        
+    if element.tag == "{http://opcfoundation.org/BinarySchema/}EnumeratedType":
+        createEnumerated(element)
+        printed_types.add(name)
+    elif element.tag == "{http://opcfoundation.org/BinarySchema/}StructuredType":
+        if printableStructuredType(element):
+            createStructured(element)
+            printed_types.add(name)
+        else: # the record contains types that were not yet detailed
+            deferred_types[name] = element
+            continue
+    elif element.tag == "{http://opcfoundation.org/BinarySchema/}OpaqueType":
+        createOpaque(element)
+        printed_types.add(name)
+
+    #if name in arraytypes:
+    #    print "package ListOf" + name + " is new Types.Arrays.UA_Builtin_Arrays(" + name + ");\n"
+
+for name, element in deferred_types.iteritems():
+    createStructured(element)
+    # if name in arraytypes:
+    #    print "package ListOf" + name + " is new Types.Arrays.UA_Builtin_Arrays(" + name + ");\n"
+
+print('#endif /* OPCUA_H_ */', end='\n', file=fh)
+fh.close()
+fc.close()
+

+ 79 - 0
tool/generate_namespace.py

@@ -0,0 +1,79 @@
+from __future__ import print_function
+import sys
+from collections import OrderedDict
+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_types = set(["Object","ObjectType","Variable","Method"])
+
+def skipType(name):
+    if name in exclude_types:
+        return True
+    return False
+
+f = open(sys.argv[1])
+rows1, rows2, rows3 = tee(csv.reader(f), 3)
+
+fh = open(sys.argv[2] + ".h",'w');
+fc = open(sys.argv[2] + ".c",'w');
+
+print('''/* struktur vTable und enumerierung*/
+#ifndef OPCUA_NAMESPACE_0_H_
+#define OPCUA_NAMESPACE_0_H_
+
+#include "opcua.h"
+
+typedef struct _UA_VTable {
+	UA_UInt32 Id;
+	Int32 (*calcSize)(void* ptr);
+	Int32 (*decode)(char const * src, Int32* pos, void* dst);
+	Int32 (*encode)(void const * src, Int32* pos, char* dst);
+} UA_VTable;
+
+Int32 UA_namespace_zero_to_index(Int32 id);
+extern UA_VTable UA_namespace_zero[]; 
+
+enum UA_VTableIndex_enum {''', end='\n', file=fh)
+
+print('''/* Mapping and vTable of Namespace Zero */
+#include "opcua.h"
+Int32 UA_namespace_zero_to_index(Int32 id) {
+    Int32 retval = -1;
+    switch (id) { ''', end='\n',file=fc)
+
+i = 0
+for row in rows1:
+    if skipType(row[2]):
+	continue
+
+    name = "UA_" + row[0]
+    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_NS0_VTABLE_MAX = 0\n};\n', file=fh)
+print('''\t}\n\treturn retval;
+}
+UA_VTable UA_namespace_zero[] = {''', file=fc)
+
+for row in rows2:
+    if skipType(row[2]):
+	continue
+
+    name = "UA_" + row[0]
+    print('#define '+name.upper()+'_NS0 (UA_namespace_zero['+name.upper()+'].Id)', file=fh)
+
+    print("\t{" + row[1] + ", &" + name + "_calcSize, &" + name + "_decode, &" + name + "_encode},",end='\n',file=fc) 
+
+print("\t{0,NULL,NULL,NULL}\n};",file=fc)
+print('#endif /* OPCUA_NAMESPACE_0_H_ */', end='\n', file=fh)
+fh.close()
+fc.close()
+f.close()
+