generate_address_space.py
Go to the documentation of this file.
00001 """
00002 Generate address space c++ code from xml file specification
00003 """
00004 import sys
00005 
00006 import xml.etree.ElementTree as ET
00007 
00008 class ObjectStruct(object):
00009     def __init__(self):
00010         self.nodetype = None
00011         self.nodeid = None
00012         self.browsename = None 
00013         self.displayname = None
00014         self.symname = None
00015         self.parent = None
00016         self.parentlink = None
00017         self.desc = ""
00018         self.typedef = None
00019         self.refs = []
00020         self.nodeclass = None
00021         self.eventnotifier = 0 
00022 
00023         #variable
00024         self.datatype = None
00025         self.rank = -1 # checl default value
00026         self.value = []
00027         self.dimensions = None
00028         self.accesslevel = None 
00029         self.useraccesslevel = None
00030         self.minsample = None
00031 
00032         #referencetype
00033         self.inversename = ""
00034         self.abstract = "false"
00035         self.symmetric = "false"
00036 
00037         #datatype
00038         self.definition = []
00039 
00040         #types
00041 
00042 
00043 class RefStruct():
00044     def __init__(self):
00045         self.reftype = None
00046         self.forward = "true"
00047         self.target = None
00048 
00049 
00050 class CodeGenerator(object):
00051     def __init__(self, input_path, output_path):
00052         self.input_path = input_path
00053         self.output_path = output_path
00054         self.output_file = None
00055         self.part = self.input_path.split(".")[-2]
00056 
00057     def run(self):
00058         sys.stderr.write("Generating C++ {} for XML file {}".format(self.output_path, self.input_path) + "\n")
00059         self.output_file = open(self.output_path, "w")
00060         self.make_header()
00061         tree = ET.parse(xmlpath)
00062         root = tree.getroot()
00063         for child in root:
00064             if child.tag[51:] == 'UAObject':
00065                 node = self.parse_node(child)
00066                 self.make_object_code(node)
00067             elif child.tag[51:] == 'UAObjectType':
00068                 node = self.parse_node(child)
00069                 self.make_object_type_code(node)
00070             elif child.tag[51:] == 'UAVariable':
00071                 node = self.parse_node(child)
00072                 self.make_variable_code(node)
00073             elif child.tag[51:] == 'UAVariableType':
00074                 node = self.parse_node(child)
00075                 self.make_variable_type_code(node)
00076             elif child.tag[51:] == 'UAReferenceType':
00077                 node = self.parse_node(child)
00078                 self.make_reference_code(node)
00079             elif child.tag[51:] == 'UADataType':
00080                 node = self.parse_node(child)
00081                 self.make_datatype_code(node)
00082             else:
00083                 sys.stderr.write("Not implemented node type: " + child.tag[51:] + "\n")
00084         self.make_footer()
00085 
00086     def writecode(self, *args):
00087         self.output_file.write(" ".join(args) + "\n")
00088 
00089     def make_header(self, ):
00090         self.writecode('''
00091 // DO NOT EDIT THIS FILE!
00092 // It is automatically generated from opcfoundation.org schemas.
00093 //
00094 
00095 #include "standard_address_space_parts.h"
00096 #include <opc/ua/protocol/string_utils.h>
00097 #include <opc/common/addons_core/addon.h>
00098 #include <opc/ua/protocol/strings.h>
00099 #include <opc/ua/protocol/variable_access_level.h>
00100 #include <opc/ua/services/node_management.h>
00101 
00102 #include <algorithm>
00103 #include <iostream>
00104 #include <map>
00105 
00106 namespace OpcUa
00107 {
00108   void CreateAddressSpace%s(OpcUa::NodeManagementServices& registry)
00109   {''' % (self.part))
00110 
00111     def make_footer(self, ):
00112         self.writecode('''
00113    }
00114 
00115 } // namespace
00116     ''')
00117 
00118 
00119     def parse_node(self, child):
00120         obj = ObjectStruct()
00121         obj.nodetype = child.tag[53:]
00122         for key, val in child.attrib.items():
00123             if key == "NodeId":
00124                 obj.nodeid = val
00125             elif key == "BrowseName":
00126                 obj.browsename = val
00127             elif key == "SymbolicName":
00128                 obj.symname = val
00129             elif key == "ParentNodeId":
00130                 obj.parent = val
00131             elif key == "DataType":
00132                 obj.datatype = val
00133             elif key == "IsAbstract":
00134                 obj.abstract = val
00135             elif key == "EventNotifier":
00136                 obj.eventnotifier = val
00137             elif key == "ValueRank":
00138                 obj.rank = val
00139             elif key == "ArrayDimensions":
00140                 obj.dimensions = val
00141             elif key == "MinimumSamplingInterval":
00142                 obj.minsample = val
00143             elif key == "AccessLevel":
00144                 obj.accesslevel = val
00145             elif key == "UserAccessLevel":
00146                 obj.useraccesslevel = val
00147             elif key == "Symmetric":
00148                 obj.symmetric = val
00149             else:
00150                 sys.stderr.write("Attribute not implemented: " + key + " " + val + "\n")
00151 
00152         obj.displayname = obj.browsename#FIXME
00153         for el in child:
00154             tag = el.tag[51:]
00155 
00156             if tag == "DisplayName":
00157                 obj.displayname = el.text
00158             elif tag == "Description":
00159                 obj.desc = el.text
00160             elif tag == "References":
00161                 for ref in el:
00162                     #self.writecode("ref", ref, "IsForward" in ref, ref.text )
00163                     if ref.attrib["ReferenceType"] == "HasTypeDefinition":
00164                         obj.typedef = ref.text
00165                     elif "IsForward" in ref.attrib and ref.attrib["IsForward"] == "false":
00166                         #if obj.parent:
00167                             #sys.stderr.write("Parent is already set with: "+ obj.parent + " " + ref.text + "\n") 
00168                         obj.parent = ref.text
00169                         obj.parentlink = ref.attrib["ReferenceType"]
00170                     else:
00171                         struct = RefStruct()
00172                         if "IsForward" in ref.attrib: struct.forward = ref.attrib["IsForward"]
00173                         struct.target = ref.text
00174                         struct.reftype = ref.attrib["ReferenceType"] 
00175                         obj.refs.append(struct)
00176             elif tag == "Value":
00177                 for val in el:
00178                     ntag = val.tag[47:]
00179                     if ntag == "Int32":
00180                         obj.value.append("(int32_t) " + val.text)
00181                     elif ntag == "UInt32":
00182                         obj.value.append("(uint32_t) " + val.text)
00183                     elif ntag in ('ByteString', 'String'):
00184                         mytext = val.text.replace('\r', '')
00185                         if len(mytext) < 65535:
00186                             mytext = ['"{}"'.format(x) for x in val.text.replace('\r', '').splitlines()]
00187                             mytext = '\n'.join(mytext)
00188                             obj.value.append('+{}'.format(mytext))
00189                         else:
00190                             def batch_gen(data, batch_size):
00191                                 for i in xrange(0, len(data), batch_size):
00192                                     yield data[i:i+batch_size]
00193                             mytext = '({}).c_str()'.format(
00194                                 ' +\n'.join(
00195                                     ['std::string({})'.format(
00196                                         '\n'.join(
00197                                             ['"{}"'.format(x) for x in segment.splitlines()]
00198                                         )
00199                                      ) for segment in batch_gen(mytext, 65000)
00200                                     ]
00201                                 )
00202                             )
00203                     elif ntag == "ListOfExtensionObject":
00204                         pass
00205                     elif ntag == "ListOfLocalizedText":
00206                         pass
00207                     else:
00208                         self.writecode("Missing type: ", ntag)
00209             elif tag == "InverseName":
00210                 obj.inversename = el.text
00211             elif tag == "Definition":
00212                 for field in el:
00213                     obj.definition.append(field)
00214             else:
00215                 sys.stderr.write("Not implemented tag: "+ str(el) + "\n")
00216         return obj
00217 
00218     def make_node_code(self, obj, indent):
00219         self.writecode(indent, 'AddNodesItem node;')
00220         self.writecode(indent, 'node.RequestedNewNodeId = ToNodeId("{}");'.format(obj.nodeid))
00221         self.writecode(indent, 'node.BrowseName = ToQualifiedName("{}");'.format(obj.browsename))
00222         self.writecode(indent, 'node.Class = NodeClass::{};'.format(obj.nodetype))
00223         if obj.parent: self.writecode(indent, 'node.ParentNodeId = ToNodeId("{}");'.format(obj.parent))
00224         if obj.parent: self.writecode(indent, 'node.ReferenceTypeId = {};'.format(self.to_ref_type(obj.parentlink)))
00225         if obj.typedef: self.writecode(indent, 'node.TypeDefinition = ToNodeId("{}");'.format(obj.typedef))
00226 
00227     def to_vector(self, dims):
00228         s = "std::vector<uint32_t>{"
00229         s += dims
00230         s+= "}"
00231         return s
00232 
00233     def to_data_type(self, nodeid):
00234         if not nodeid:
00235             return "ObjectId::String"
00236         if "=" in nodeid:
00237             return 'ToNodeId("{}")'.format(nodeid)
00238         else:
00239             return 'ObjectId::{}'.format(nodeid)
00240 
00241     def to_ref_type(self, nodeid):
00242         if "=" in nodeid:
00243             return 'ToNodeId("{}")'.format(nodeid)
00244         else:
00245             return 'ReferenceId::{}'.format(nodeid)
00246 
00247     def make_object_code(self, obj):
00248         indent = "       "
00249         self.writecode(indent)
00250         self.writecode(indent, "{")
00251         self.make_node_code(obj, indent)
00252         self.writecode(indent, 'ObjectAttributes attrs;')
00253         if obj.desc: self.writecode(indent, 'attrs.Description = LocalizedText("{}");'.format(obj.desc))
00254         self.writecode(indent, 'attrs.DisplayName = LocalizedText("{}");'.format(obj.displayname))
00255         self.writecode(indent, 'attrs.EventNotifier = {};'.format(obj.eventnotifier))
00256         self.writecode(indent, 'node.Attributes = attrs;')
00257         self.writecode(indent, 'registry.AddNodes(std::vector<AddNodesItem>{node});')
00258         self.make_refs_code(obj, indent)
00259         self.writecode(indent, "}")
00260 
00261     def make_object_type_code(self, obj):
00262         indent = "       "
00263         self.writecode(indent)
00264         self.writecode(indent, "{")
00265         self.make_node_code(obj, indent)
00266         self.writecode(indent, 'ObjectTypeAttributes attrs;')
00267         if obj.desc: self.writecode(indent, 'attrs.Description = LocalizedText("{}");'.format(obj.desc))
00268         self.writecode(indent, 'attrs.DisplayName = LocalizedText("{}");'.format(obj.displayname))
00269         self.writecode(indent, 'attrs.IsAbstract = {};'.format(obj.abstract))
00270         self.writecode(indent, 'node.Attributes = attrs;')
00271         self.writecode(indent, 'registry.AddNodes(std::vector<AddNodesItem>{node});')
00272         self.make_refs_code(obj, indent)
00273         self.writecode(indent, "}")
00274 
00275 
00276     def make_variable_code(self, obj):
00277         indent = "       "
00278         self.writecode(indent)
00279         self.writecode(indent, "{")
00280         self.make_node_code(obj, indent)
00281         self.writecode(indent, 'VariableAttributes attrs;')
00282         if obj.desc: self.writecode(indent, 'attrs.Description = LocalizedText("{}");'.format(obj.desc))
00283         self.writecode(indent, 'attrs.DisplayName = LocalizedText("{}");'.format(obj.displayname))
00284         self.writecode(indent, 'attrs.Type = {};'.format(self.to_data_type(obj.datatype)))
00285         if obj.value and len(obj.value) == 1: self.writecode(indent, 'attrs.Value = {};'.format(obj.value[0]))
00286         if obj.rank: self.writecode(indent, 'attrs.Rank = {};'.format(obj.rank))
00287         if obj.accesslevel: self.writecode(indent, 'attrs.AccessLevel = (VariableAccessLevel) {};'.format(obj.accesslevel))
00288         if obj.useraccesslevel: self.writecode(indent, 'attrs.UserAccessLevel = (VariableAccessLevel) {};'.format(obj.useraccesslevel))
00289         if obj.minsample: self.writecode(indent, 'attrs.MinimumSamplingInterval = {};'.format(obj.minsample))
00290         if obj.dimensions: self.writecode(indent, 'attrs.Dimensions = {};'.format(self.to_vector(obj.dimensions)))
00291         self.writecode(indent, 'node.Attributes = attrs;')
00292         self.writecode(indent, 'registry.AddNodes(std::vector<AddNodesItem>{node});')
00293         self.make_refs_code(obj, indent)
00294         self.writecode(indent, "}")
00295 
00296     def make_variable_type_code(self, obj):
00297         indent = "       "
00298         self.writecode(indent)
00299         self.writecode(indent, "{")
00300         self.make_node_code(obj, indent)
00301         self.writecode(indent, 'VariableTypeAttributes attrs;')
00302         if obj.desc: self.writecode(indent, 'attrs.Description = LocalizedText("{}");'.format(obj.desc))
00303         self.writecode(indent, 'attrs.DisplayName = LocalizedText("{}");'.format(obj.displayname))
00304         self.writecode(indent, 'attrs.Type = {};'.format(self.to_data_type(obj.datatype)))
00305         if obj.value and len(obj.value) == 1: self.writecode(indent, 'attrs.Value = {};'.format(obj.value[0]))
00306         if obj.rank: self.writecode(indent, 'attrs.Rank = {};'.format(obj.rank))
00307         if obj.abstract: self.writecode(indent, 'attrs.IsAbstract = {};'.format(obj.abstract))
00308         if obj.dimensions: self.writecode(indent, 'attrs.Dimensions = {};'.format(self.to_vector(obj.dimensions)))
00309         self.writecode(indent, 'node.Attributes = attrs;')
00310         self.writecode(indent, 'registry.AddNodes(std::vector<AddNodesItem>{node});')
00311         self.make_refs_code(obj, indent)
00312         self.writecode(indent, "}")
00313 
00314 
00315 
00316     def make_reference_code(self, obj):
00317         indent = "       "
00318         self.writecode(indent)
00319         self.writecode(indent, "{")
00320         self.make_node_code(obj, indent)
00321         self.writecode(indent, 'ReferenceTypeAttributes attrs;')
00322         if obj.desc: self.writecode(indent, 'attrs.Description = LocalizedText("{}");'.format(obj.desc))
00323         self.writecode(indent, 'attrs.DisplayName = LocalizedText("{}");'.format(obj.displayname))
00324         if obj. inversename: self.writecode(indent, 'attrs.InverseName = LocalizedText("{}");'.format(obj.inversename))
00325         if obj.abstract: self.writecode(indent, 'attrs.IsAbstract = {};'.format(obj.abstract))
00326         if obj.symmetric: self.writecode(indent, 'attrs.Symmetric = {};'.format(obj.symmetric))
00327         self.writecode(indent, 'node.Attributes = attrs;')
00328         self.writecode(indent, 'registry.AddNodes(std::vector<AddNodesItem>{node});')
00329         self.make_refs_code(obj, indent)
00330         self.writecode(indent, "}")
00331 
00332     def make_datatype_code(self, obj):
00333         indent = "       "
00334         self.writecode(indent)
00335         self.writecode(indent, "{")
00336         self.make_node_code(obj, indent)
00337         self.writecode(indent, 'DataTypeAttributes attrs;')
00338         if obj.desc: self.writecode(indent, u'attrs.Description = LocalizedText("{}");'.format(obj.desc.encode('ascii', 'replace')))
00339         self.writecode(indent, 'attrs.DisplayName = LocalizedText("{}");'.format(obj.displayname))
00340         if obj.abstract: self.writecode(indent, 'attrs.IsAbstract = {};'.format(obj.abstract))
00341         self.writecode(indent, 'node.Attributes = attrs;')
00342         self.writecode(indent, 'registry.AddNodes(std::vector<AddNodesItem>{node});')
00343         self.make_refs_code(obj, indent)
00344         self.writecode(indent, "}")
00345 
00346     def make_refs_code(self, obj, indent):
00347         if not obj.refs:
00348             return
00349         self.writecode(indent, "std::vector<AddReferencesItem> refs;")
00350         for ref in obj.refs:
00351             self.writecode(indent, "{")
00352             self.writecode(indent, 'AddReferencesItem ref;')
00353             self.writecode(indent, 'ref.IsForward = true;')
00354             self.writecode(indent, 'ref.ReferenceTypeId = {};'.format(self.to_ref_type(ref.reftype)))
00355             self.writecode(indent, 'ref.SourceNodeId = ToNodeId("{}");'.format(obj.nodeid))
00356             self.writecode(indent, 'ref.TargetNodeClass = NodeClass::DataType;')
00357             self.writecode(indent, 'ref.TargetNodeId = ToNodeId("{}");'.format(ref.target))
00358             self.writecode(indent, "refs.push_back(ref);")
00359             self.writecode(indent, "}")
00360         self.writecode(indent, 'registry.AddReferences(refs);')
00361 
00362 
00363 if __name__ == "__main__":
00364     if len(sys.argv) == 2 and sys.argv[1] == "all":
00365         for i in (3, 4, 5, 8, 9, 10, 11, 13):
00366             xmlpath = "Opc.Ua.NodeSet2.Part{}.xml".format(str(i))
00367             cpppath = "../src/server/standard_address_space_part{}.cpp".format(str(i))
00368             c = CodeGenerator(xmlpath, cpppath)
00369             c.run()
00370 
00371 
00372     elif len(sys.argv) != 3:
00373         print(sys.argv)
00374         print("usage: generate_address_space.py xml_input_file cpp_output_file")
00375         print(" or generate_address_space.py all")
00376         sys.exit(1)
00377     else:
00378         xmlpath = sys.argv[1] 
00379         cpppath = sys.argv[2]
00380     c = CodeGenerator(xmlpath, cpppath)
00381     c.run()
00382 


ros_opcua_impl_freeopcua
Author(s): Denis Štogl
autogenerated on Sat Jun 8 2019 18:24:40