generate_model.py
Go to the documentation of this file.
00001 """
00002 Generate address space c++ code from xml file specification
00003 """
00004 import sys
00005 from copy import copy
00006 
00007 import xml.etree.ElementTree as ET
00008 
00009 from IPython import embed
00010 
00011 #by default we split requests and respons in header and parameters, but some are so simple we do not split them
00012 
00013 #structs that end with Request or Response but are not
00014 NotRequest = ["MonitoredItemCreateRequest", "MonitoredItemModifyRequest", "CallMethodRequest"]
00015 
00016 #some object are defined in extensionobjects in spec but seems not to be in reality
00017 #in addition to this list all request and response and descriptions will not inherit
00018 #NoInherit = ["RequestHeader", "ResponseHeader", "ChannelSecurityToken", "UserTokenPolicy", "SignatureData", "BrowseResult", "ReadValueId", "WriteValue", "BrowsePath", "BrowsePathTarget", "RelativePath", "RelativePathElement", "BrowsePathResult"]#, "ApplicationDescription", "EndpointDescription"
00019 # many objects are defined as inheriting while inheriting ExtensionObjects while they do not so harcode those who really do
00020 InheritExtensionObjects = ["UserIdentityToken", "NodeAttributes"]#"SignatureData"]
00021 
00022 
00023 class Bit(object):
00024     def __init__(self):
00025         self.name = None
00026         self.idx = None
00027         self.container = None
00028         self.length = 1
00029 
00030     def __str__(self):
00031         return "(Bit: {}, container:{}, idx:{})".format(self.name, self.container, self.idx)
00032     __repr__ = __str__
00033 
00034 class Struct(object):
00035     def __init__(self):
00036         self.name = None
00037         self.basetype = None
00038         self.doc = ""
00039         self.fields = []
00040         self.bits = {}
00041         self.needconstructor = None
00042         self.isrequest = False
00043         self.needoverride = False
00044         self.children = []
00045         self.parents = []
00046         self.extensionobject = False #used for struct which are not pure extension objects
00047 
00048     def get_field(self, name):
00049         for f in self.fields:
00050             if f.name == name:
00051                 return f
00052         raise Exception("field not found: " + name)
00053     
00054     def __str__(self):
00055         return "Struct {}:{}".format(self.name, self.basetype)
00056 
00057     __repr__ = __str__
00058 
00059 
00060 class Field(object):
00061     def __init__(self):
00062         self.name = None
00063         self.uatype = None
00064         self.length = None
00065         self.sourcetype = None
00066         self.switchfield = None
00067         self.switchvalue = None
00068         self.bitlength = 1 
00069 
00070     def __str__(self):
00071         return "Field {}({})".format(self.name, self.uatype)
00072 
00073     __repr__ = __str__
00074 
00075     def is_native_type(self):
00076         if self.uatype in ("Char", "SByte", "Int8", "Int16", "Int32", "Int64", "UInt8", "UInt16", "UInt32", "UInt64", "Boolean", "Double", "Float", "Byte", "String", "CharArray", "ByteString", "DateTime"):
00077             return True
00078         return False
00079 
00080     def get_ctype(self):
00081         if self.uatype == "String":
00082             ty = "std::string"
00083         elif self.uatype == "CharArray":
00084             ty = "std::string"
00085         elif self.uatype == "Char":
00086             ty = "uint8_t"
00087         elif self.uatype == "SByte":
00088             ty = "uint8_t"
00089         elif self.uatype == "Int8":
00090             ty = "int8_t"
00091         elif self.uatype == "Int16":
00092             ty = "int16_t"
00093         elif self.uatype == "Int32":
00094             ty = "int32_t"
00095         elif self.uatype == "Int64":
00096             ty = "int64_t"
00097         elif self.uatype == "UInt8":
00098             ty = "uint8_t"
00099         elif self.uatype == "UInt16":
00100             ty = "uint16_t"
00101         elif self.uatype == "UInt32":
00102             ty = "uint32_t"
00103         elif self.uatype == "UInt64":
00104             ty = "uint64_t"
00105         elif self.uatype == "DateTime":
00106             ty = "OpcUa::DateTime"
00107         elif self.uatype == "Boolean":
00108             ty = "bool"
00109         elif self.uatype == "Double":
00110             ty = "double"
00111         elif self.uatype == "Float":
00112             ty = "float"
00113         elif self.uatype == "ByteString":
00114             ty = "OpcUa::ByteString"
00115         elif self.uatype == "Byte":
00116             ty = "uint8_t"
00117         else:
00118             ty = "OpcUa::" + self.uatype
00119         if self.length:
00120             ty = "std::vector<{}>".format(ty)
00121         return ty
00122 
00123 class Enum(object):
00124     def __init__(self):
00125         self.name = None
00126         self.uatype = None
00127         self.values = []
00128         self.doc = ""
00129 
00130     def get_ctype(self):
00131         return "{}_t".format(self.uatype.lower())
00132 
00133 class EnumValue(object):
00134     def __init__(self):
00135         self.name = None
00136         self.value = None
00137 
00138 
00139 class Model(object):
00140     def __init__(self):
00141         self.structs = []
00142         self.enums = []
00143         self.struct_list = []
00144         self.enum_list = []
00145 
00146     def get_struct(self, name):
00147         for struct in self.structs:
00148             if name == struct.name:
00149                 return struct
00150         raise Exception("No struct named: " + str(name))
00151 
00152     def get_enum(self, name):
00153         for s in self.enums:
00154             if name == s.name:
00155                 return s
00156         raise Exception("No enum named: " + str(name))
00157 
00158 
00159 def remove_duplicates(model):
00160     for struct in model.structs:
00161         fields = []
00162         names = []
00163         for field in struct.fields:
00164             if field.name not in names:
00165                 names.append(field.name)
00166                 fields.append(field)
00167         struct.fields = fields
00168 
00169 
00170 def add_encoding_field(model):
00171     for struct in model.structs:
00172         newfields = []
00173         container = None
00174         idx = 0
00175         for field in struct.fields:
00176             if field.uatype in ("UInt6", "NodeIdType"):
00177                 container = field.name
00178                 b = Bit()
00179                 b.name = field.name
00180                 b.idx = 0
00181                 b.container = container
00182                 b.length = 6 
00183                 idx = b.length
00184                 struct.bits[b.name] = b
00185 
00186             if field.uatype == "Bit":
00187                 if not container or idx > 7:
00188                     container = "Encoding"
00189                     idx = 0
00190                     f = Field()
00191                     f.sourcetype = field.sourcetype
00192                     f.name = "Encoding"
00193                     f.uatype = "UInt8"
00194                     newfields.append(f)
00195 
00196                 b = Bit()
00197                 b.name = field.name
00198                 b.idx = idx
00199                 b.container = container
00200                 b.length = field.bitlength
00201                 idx += field.bitlength
00202                 struct.bits[b.name] = b
00203             else:
00204                 newfields.append(field)
00205         struct.fields = newfields
00206 
00207 def remove_vector_length(model):
00208     for struct in model.structs:
00209         new = []
00210         for field in struct.fields:
00211             if not field.name.startswith("NoOf"):
00212                 new.append(field)
00213         struct.fields = new
00214 
00215 def remove_body_length(model):
00216     for struct in model.structs:
00217         new = []
00218         for field in struct.fields:
00219             if not field.name == "BodyLength":
00220                 new.append(field)
00221         struct.fields = new
00222 
00223 #def remove_extensionobject_fields(model):
00224     #for obj in model.structs:
00225         #if obj.name.endswith("Request") or obj.name.endswith("Response"):
00226             #obj.fields = [el for el in obj.fields if el.name not in ("TypeId", "Body", "Encoding")]
00227 
00228 def split_requests(model, NoSplitStruct):
00229     structs = []
00230     for struct in model.structs:
00231         structtype = None
00232         if struct.name.endswith("Request") and not struct.name in NotRequest:
00233             structtype = "Request"
00234         elif struct.name.endswith("Response") or struct.name == "ServiceFault":
00235             structtype = "Response"
00236         if structtype:
00237             #for field in struct.fields:
00238                 #if field.name == "Encoding":
00239                     #struct.fields.remove(field)
00240                     #break
00241             #for field in struct.fields:
00242                 #if field.name == "BodyLength":
00243                     #struct.fields.remove(field)
00244                     #break
00245             struct.isrequest = True
00246             struct.needconstructor = True
00247             field = Field()
00248             field.name = "TypeId"
00249             field.uatype = "NodeId"
00250             struct.fields.insert(0, field)
00251 
00252         if structtype and not struct.name in NoSplitStruct:
00253             paramstruct = Struct()
00254             if structtype == "Request":
00255                 basename = struct.name.replace("Request", "") + "Parameters"
00256                 paramstruct.name = basename 
00257             else:
00258                 basename = struct.name.replace("Response", "") + "Result"
00259                 paramstruct.name = basename 
00260             paramstruct.fields = struct.fields[2:]
00261             paramstruct.bits = struct.bits
00262 
00263             struct.fields = struct.fields[:2]
00264             #struct.bits = {}
00265             structs.append(paramstruct)
00266 
00267             typeid = Field()
00268             typeid.name = "Parameters" 
00269             typeid.uatype = paramstruct.name 
00270             struct.fields.append(typeid)
00271         structs.append(struct)
00272     model.structs = structs
00273     model.struct_list = [s.name for s in model.structs]
00274 
00275 
00276 class Parser(object):
00277     def __init__(self, path):
00278         self.path = path
00279         self.model = None
00280 
00281     def parse(self):
00282         print("Parsing: ", self.path)
00283         self.model = Model()
00284         tree = ET.parse(self.path)
00285         root = tree.getroot()
00286         self.add_extension_object()
00287         for child in root:
00288             tag = child.tag[40:]
00289             if tag == "StructuredType":
00290                 struct = self.parse_struct(child)
00291                 if struct.name != "ExtensionObject":
00292                     self.model.structs.append(struct)
00293                     self.model.struct_list.append(struct.name)
00294             elif tag == "EnumeratedType":
00295                 enum = self.parse_enum(child)
00296                 self.model.enums.append(enum)
00297                 self.model.enum_list.append(enum.name)
00298             #else:
00299                 #print("Not implemented node type: " + tag + "\n")
00300         return self.model
00301 
00302     def add_extension_object(self):
00303         obj = Struct()
00304         obj.name = "ExtensionObject"
00305         f = Field()
00306         f.name = "TypeId"
00307         f.uatype = "NodeId"
00308         obj.fields.append(f)
00309         f = Field()
00310         f.name = "BinaryBody"
00311         f.uatype = "Bit"
00312         obj.fields.append(f)
00313         f = Field()
00314         f.name = "XmlBody"
00315         f.uatype = "Bit"
00316         obj.fields.append(f)
00317         f = Field()
00318         f.name = "Body"
00319         f.uatype = "ByteString"
00320         f.switchfield = "BinaryBody"
00321         obj.fields.append(f)
00322         self.model.struct_list.append(obj.name)
00323 
00324         self.model.structs.append(obj)
00325 
00326     def parse_struct(self, child):
00327         tag = child.tag[40:]
00328         struct = Struct()
00329         for key, val in child.attrib.items():
00330             if key == "Name":
00331                 struct.name = val
00332             elif key == "BaseType":
00333                 if ":" in val:
00334                     prefix, val = val.split(":")
00335                 struct.basetype = val
00336                 tmp = struct
00337                 while tmp.basetype:
00338                     struct.parents.append(tmp.basetype)
00339                     tmp = self.model.get_struct(tmp.basetype)
00340             else:
00341                 print("Error unknown key: ", key)
00342         for el in child:
00343             tag = el.tag[40:]
00344             if tag == "Field":
00345                 field = Field()
00346                 for key, val in el.attrib.items():
00347                     if key == "Name":
00348                         field.name = val
00349                     elif key == "TypeName":
00350                         field.uatype = val.split(":")[1]
00351                     elif key == "LengthField":
00352                         field.length = val
00353                     elif key == "SourceType":
00354                         field.sourcetype = val
00355                     elif key == "SwitchField":
00356                         field.switchfield = val
00357                     elif key == "SwitchValue":
00358                         field.switchvalue = val
00359                     elif key == "Length":
00360                         field.bitlength = int(val)
00361                     else:
00362                         print("Uknown field item: ", struct.name, key) 
00363 
00364                 struct.fields.append(field)
00365             elif tag == "Documentation":
00366                 struct.doc = el.text
00367             else:
00368                 print("Uknown tag: ", tag)
00369 
00370         return struct
00371 
00372     def parse_enum(self, child):
00373         tag = child.tag[40:]
00374         enum = Enum()
00375         for k, v in child.items():
00376             if k == "Name":
00377                 enum.name = v
00378             elif k == "LengthInBits":
00379                 enum.uatype = "UInt" + v
00380             else:
00381                 print("Unknown attr for enum: ", k)
00382         for el in child:
00383             tag = el.tag[40:]
00384             if tag == "EnumeratedValue":
00385                 ev = EnumValue()
00386                 for k, v in el.attrib.items():
00387                     if k == "Name":
00388                         ev.name = v
00389                     elif k == "Value":
00390                         ev.value = v
00391                     else:
00392                         print("Uknown field attrib: ", k) 
00393                 enum.values.append(ev)
00394             elif tag == "Documentation":
00395                 enum.doc = el.text
00396             else:
00397                 print("Unknown enum tag: ", tag)
00398         return enum
00399 
00400 
00401 #"def reorder_extobjects(model):
00402     #ext = model.get_struct("ExtensionObject")
00403     #print(ext)
00404     #typeid = ext.fields[4]
00405     #ext.fields.remove(typeid)
00406     #ext.fields.insert(0, typeid)
00407 
00408 def add_basetype_members(model):
00409     for struct in model.structs:
00410         if not struct.basetype:
00411             continue
00412         emptystruct = False
00413         if len(struct.fields) == 0:
00414             emptystruct = True
00415         if not emptystruct and struct.basetype in ("ExtensionObject") and not struct.name in InheritExtensionObjects:
00416         #if struct.name in NoInherit or struct.name.endswith("Request") or struct.name.endswith("Response") or struct.name.endswith("Description"):
00417             struct.parents.remove(struct.basetype)
00418             struct.basetype = None
00419             continue
00420         base = model.get_struct(struct.basetype)
00421         #if struct.basetype == "ExtensionObject" and len(struct.fields) != 0:
00422         #if struct.basetype == "ExtensionObject" and len(struct.fields) != 0:
00423             #if struc
00424             #for f in base.fields:
00425                 #if f.name == "TypeId":
00426                     #f2 = copy(f)
00427                     #f2.switchfield = None
00428                     #struct.fields.insert(0, f2)
00429                     #break
00430             #continue
00431         for name, bit in base.bits.items():
00432             struct.bits[name] = bit
00433         for idx, field in enumerate(base.fields):
00434             field = copy(field)
00435             if field.name == "Body" and not emptystruct:
00436                 #print("Field is names Body", struct.name, field.name)
00437                 struct.extensionobject = True
00438                 field.name = "BodyLength"
00439                 field.uatype = "Int32"
00440                 field.length = None
00441                 field.switchfield = None
00442                 #print("Field is names Body 2", struct.name, field.name)
00443             #HACK EXTENSIONOBJECT
00444             #if base.name == "ExtensionObject":
00445                 #continue
00446                 #if field.uatype == "Bit":
00447                     #continue
00448                 #if field.name == "Body":
00449                     #continue
00450                 #if field.name == "TypeId":
00451                     #field.switchfield = None
00452             #END HACK
00453             if not field.sourcetype:
00454                 field.sourcetype = base.name
00455             struct.fields.insert(idx, field)
00456 
00457 
00458 
00459 
00460 


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