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 NeedOverride = []
00012 NeedConstructor = []#["RelativePathElement", "ReadValueId", "OpenSecureChannelParameters", "UserIdentityToken", "RequestHeader", "ResponseHeader", "ReadParameters", "UserIdentityToken", "BrowseDescription", "ReferenceDescription", "CreateSubscriptionParameters", "PublishResult", "NotificationMessage", "SetPublishingModeParameters"]
00013 IgnoredEnums = []#["IdType", "NodeIdType"]
00014 #we want to implement som struct by hand, to make better interface or simply because they are too complicated
00015 IgnoredStructs = []#["NodeId", "ExpandedNodeId", "Variant", "QualifiedName", "DataValue", "LocalizedText"]#, "ExtensionObject"]
00016 #by default we split requests and respons in header and parameters, but some are so simple we do not split them
00017 NoSplitStruct = ["GetEndpointsResponse", "CloseSessionRequest", "AddNodesResponse", "DeleteNodesResponse", "BrowseResponse", "HistoryReadResponse", "HistoryUpdateResponse", "RegisterServerResponse", "CloseSecureChannelRequest", "CloseSecureChannelResponse", "CloseSessionRequest", "CloseSessionResponse", "UnregisterNodesResponse", "MonitoredItemModifyRequest", "MonitoredItemsCreateRequest", "ReadResponse", "WriteResponse", "TranslateBrowsePathsToNodeIdsResponse", "DeleteSubscriptionsResponse", "DeleteMonitoredItemsResponse", "CreateMonitoredItemsResponse", "ServiceFault", "AddReferencesRequest", "AddReferencesResponse", "ModifyMonitoredItemsResponse", "RepublishResponse", "CallResponse", "FindServersResponse", "RegisterServerRequest", "RegisterServer2Response"]
00018 #structs that end with Request or Response but are not
00019 NotRequest = ["MonitoredItemCreateRequest", "MonitoredItemModifyRequest", "CallMethodRequest"]
00020 OverrideTypes = {}#AttributeId": "AttributeID",  "ResultMask": "BrowseResultMask", "NodeClassMask": "NodeClass", "AccessLevel": "VariableAccessLevel", "UserAccessLevel": "VariableAccessLevel", "NotificationData": "NotificationData"}
00021 OverrideNames = {}#{"RequestHeader": "Header", "ResponseHeader": "Header", "StatusCode": "Status", "NodesToRead": "AttributesToRead"} # "MonitoringMode": "Mode",, "NotificationMessage": "Notification", "NodeIdType": "Type"}
00022 
00023 #some object are defined in extensionobjects in spec but seems not to be in reality
00024 #in addition to this list all request and response and descriptions will not inherit
00025 #NoInherit = ["RequestHeader", "ResponseHeader", "ChannelSecurityToken", "UserTokenPolicy", "SignatureData", "BrowseResult", "ReadValueId", "WriteValue", "BrowsePath", "BrowsePathTarget", "RelativePath", "RelativePathElement", "BrowsePathResult"]#, "ApplicationDescription", "EndpointDescription"
00026 
00027 
00028 class Bit(object):
00029     def __init__(self):
00030         self.name = None
00031         self.idx = None
00032         self.container = None
00033         self.length = 1
00034 
00035     def __str__(self):
00036         return "(Bit: {0}, container:{1}, idx:{2})".format(self.name, self.container, self.idx)
00037     __repr__ = __str__
00038 
00039 class Struct(object):
00040     def __init__(self):
00041         self.name = None
00042         self.basetype = None
00043         self.doc = ""
00044         self.fields = []
00045         self.bits = {}
00046         self.needconstructor = None
00047         self.needoverride = False
00048         self.children = []
00049         self.parents = []
00050         self.extensionobject = False #used for struct which are not pure extension objects
00051 
00052     def get_field(self, name):
00053         for f in self.fields:
00054             if f.name == name:
00055                 return f
00056         raise Exception("field not found: " + name)
00057 
00058     def __str__(self):
00059         return "Struct {0}:{1}".format(self.name, self.basetype)
00060 
00061     __repr__ = __str__
00062 
00063 
00064 class Field(object):
00065     def __init__(self):
00066         self.name = None
00067         self.uatype = None
00068         self.length = None
00069         self.sourcetype = None
00070         self.switchfield = None
00071         self.switchvalue = None
00072         self.bitlength = 1
00073 
00074     def __str__(self):
00075         return "Field {0}({1})".format(self.name, self.uatype)
00076 
00077     __repr__ = __str__
00078 
00079     def is_native_type(self):
00080         if self.uatype in ("Char", "SByte", "Int8", "Int16", "Int32", "Int64", "UInt8", "UInt16", "UInt32", "UInt64", "Boolean", "Double", "Float", "Byte", "String", "CharArray", "ByteString", "DateTime"):
00081             return True
00082         return False
00083 
00084     def get_ctype(self):
00085         if self.uatype == "String":
00086             ty = "std::string"
00087         elif self.uatype == "CharArray":
00088             ty = "std::string"
00089         elif self.uatype == "Char":
00090             ty = "char"
00091         elif self.uatype == "SByte":
00092             ty = "char"
00093         elif self.uatype == "Int8":
00094             ty = "int8_t"
00095         elif self.uatype == "Int16":
00096             ty = "int16_t"
00097         elif self.uatype == "Int32":
00098             ty = "int32_t"
00099         elif self.uatype == "Int64":
00100             ty = "int64_t"
00101         elif self.uatype == "UInt8":
00102             ty = "uint8_t"
00103         elif self.uatype == "UInt16":
00104             ty = "uint16_t"
00105         elif self.uatype == "UInt32":
00106             ty = "uint32_t"
00107         elif self.uatype == "UInt64":
00108             ty = "uint64_t"
00109         elif self.uatype == "DateTime":
00110             ty = "OpcUa::DateTime"
00111         elif self.uatype == "Boolean":
00112             ty = "bool"
00113         elif self.uatype == "Double":
00114             ty = "double"
00115         elif self.uatype == "Float":
00116             ty = "float"
00117         elif self.uatype == "ByteString":
00118             ty = "OpcUa::ByteString"
00119         elif self.uatype == "Byte":
00120             ty = "uint8_t"
00121         else:
00122             ty = "OpcUa::" + self.uatype
00123         if self.length:
00124             ty = "std::vector<{0}>".format(ty)
00125         return ty
00126 
00127 class Enum(object):
00128     def __init__(self):
00129         self.name = None
00130         self.uatype = None
00131         self.values = []
00132         self.doc = ""
00133 
00134     def get_ctype(self):
00135         return "uint{0}_t".format(self.uatype)
00136 
00137 class EnumValue(object):
00138     def __init__(self):
00139         self.name = None
00140         self.value = None
00141 
00142 class Model(object):
00143     def __init__(self):
00144         self.structs = []
00145         self.enums = []
00146         self.struct_list = []
00147         self.enum_list = []
00148 
00149     def get_struct(self, name):
00150         for struct in self.structs:
00151             if name == struct.name:
00152                 return struct
00153         raise Exception("No struct named: " + str(name))
00154 
00155     def get_enum(self, name):
00156         for s in self.enums:
00157             if name == s.name:
00158                 return s
00159         raise Exception("No enum named: " + str(name))
00160 
00161 
00162 
00163 
00164 def reorder_structs(model):
00165     types = IgnoredStructs + IgnoredEnums + ["Bit", "Char", "CharArray", "Guid", "SByte", "Int8", "Int16", "Int32", "Int64", "UInt8", "UInt16", "UInt32", "UInt64", "DateTime", "Boolean", "Double", "Float", "ByteString", "Byte", "StatusCode", "DiagnosticInfo", "String", "AttributeID"] + [enum.name for enum in model.enums] + ["VariableAccessLevel"]
00166     waiting = {}
00167     newstructs = []
00168     for s in model.structs:
00169         types.append(s.name)
00170         s.waitingfor = []
00171         ok = True
00172         for f in s.fields:
00173             if f.uatype not in types:
00174                 if f.uatype in waiting.keys():
00175                     waiting[f.uatype].append(s)
00176                     s.waitingfor.append(f.uatype)
00177                 else:
00178                     waiting[f.uatype] = [s]
00179                     s.waitingfor.append(f.uatype)
00180                 ok = False
00181         if ok:
00182             newstructs.append(s)
00183             waitings = waiting.pop(s.name, None)
00184             if waitings:
00185                 for s2 in waitings:
00186                     s2.waitingfor.remove(s.name)
00187                     if not s2.waitingfor:
00188                         newstructs.append(s2)
00189     if len(model.structs) != len(newstructs):
00190         print("Error while reordering structs, some structs could not be reinserted, had {0} structs, we now have {1} structs".format(len(model.structs), len(newstructs)))
00191         s1 = set(model.structs)
00192         s2 = set(newstructs)
00193         rest = s1 -s2
00194         print("Variant" in types)
00195         for s in s1-s2:
00196             print("{0} is waiting for: {1}".format(s, s.waitingfor))
00197         #print(s1 -s2)
00198         #print(waiting)
00199     model.structs = newstructs
00200 
00201 def override_types(model):
00202     for struct in model.structs:
00203         for field in struct.fields:
00204             if field.name in OverrideTypes.keys():
00205                 field.uatype = OverrideTypes[field.name]
00206 
00207 def remove_duplicates(model):
00208     for struct in model.structs:
00209         fields = []
00210         names = []
00211         for field in struct.fields:
00212             if field.name not in names:
00213                 names.append(field.name)
00214                 fields.append(field)
00215         struct.fields = fields
00216 
00217 def add_encoding_field(model):
00218     for struct in model.structs:
00219         newfields = []
00220         container = None
00221         idx = 0
00222         for field in struct.fields:
00223             if field.uatype in ("UInt6", "NodeIdType"):
00224                 container = field.name
00225                 b = Bit()
00226                 b.name = field.name
00227                 b.idx = 0
00228                 b.container = container
00229                 b.length = 6
00230                 idx = b.length
00231                 struct.bits[b.name] = b
00232 
00233             if field.uatype == "Bit":
00234                 if not container or idx > 7:
00235                     container = "Encoding"
00236                     idx = 0
00237                     f = Field()
00238                     f.sourcetype = field.sourcetype
00239                     f.name = "Encoding"
00240                     f.uatype = "UInt8"
00241                     newfields.append(f)
00242 
00243                 b = Bit()
00244                 b.name = field.name
00245                 b.idx = idx
00246                 b.container = container
00247                 b.length = field.bitlength
00248                 idx += field.bitlength
00249                 struct.bits[b.name] = b
00250             else:
00251                 newfields.append(field)
00252         struct.fields = newfields
00253 
00254 def remove_vector_length(model):
00255     for struct in model.structs:
00256         new = []
00257         for field in struct.fields:
00258             if not field.name.startswith("NoOf"):
00259                 new.append(field)
00260         struct.fields = new
00261 
00262 def remove_body_length(model):
00263     for struct in model.structs:
00264         new = []
00265         for field in struct.fields:
00266             if not field.name == "BodyLength":
00267                 new.append(field)
00268         struct.fields = new
00269 
00270 #def remove_extensionobject_fields(model):
00271     #for obj in model.structs:
00272         #if obj.name.endswith("Request") or obj.name.endswith("Response"):
00273             #obj.fields = [el for el in obj.fields if el.name not in ("TypeId", "Body", "Encoding")]
00274 
00275 def split_requests(model):
00276     structs = []
00277     for struct in model.structs:
00278         structtype = None
00279         if struct.name.endswith("Request") and not struct.name in NotRequest:
00280             structtype = "Request"
00281         elif struct.name.endswith("Response") or struct.name == "ServiceFault":
00282             structtype = "Response"
00283         if structtype:
00284             #for field in struct.fields:
00285                 #if field.name == "Encoding":
00286                     #struct.fields.remove(field)
00287                     #break
00288             #for field in struct.fields:
00289                 #if field.name == "BodyLength":
00290                     #struct.fields.remove(field)
00291                     #break
00292             struct.needconstructor = True
00293             field = Field()
00294             field.name = "TypeId"
00295             field.uatype = "NodeId"
00296             struct.fields.insert(0, field)
00297 
00298         if structtype and not struct.name in NoSplitStruct:
00299             paramstruct = Struct()
00300             if structtype == "Request":
00301                 basename = struct.name.replace("Request", "") + "Parameters"
00302                 paramstruct.name = basename
00303             else:
00304                 basename = struct.name.replace("Response", "") + "Result"
00305                 paramstruct.name = basename
00306             paramstruct.fields = struct.fields[2:]
00307             paramstruct.bits = struct.bits
00308 
00309             struct.fields = struct.fields[:2]
00310             #struct.bits = {}
00311             structs.append(paramstruct)
00312 
00313             typeid = Field()
00314             typeid.name = "Parameters"
00315             typeid.uatype = paramstruct.name
00316             struct.fields.append(typeid)
00317         structs.append(struct)
00318     model.structs = structs
00319 
00320 
00321 class Parser(object):
00322     def __init__(self, path):
00323         self.path = path
00324         self.model = None
00325 
00326     def parse(self):
00327         print("Parsing: ", self.path)
00328         self.model = Model()
00329         tree = ET.parse(self.path)
00330         root = tree.getroot()
00331         self.add_extension_object()
00332         for child in root:
00333             tag = child.tag[40:]
00334             if tag == "StructuredType":
00335                 struct = self.parse_struct(child)
00336                 if struct.name != "ExtensionObject":
00337                     self.model.structs.append(struct)
00338                     self.model.struct_list.append(struct.name)
00339             elif tag == "EnumeratedType":
00340                 enum = self.parse_enum(child)
00341                 self.model.enums.append(enum)
00342                 self.model.enum_list.append(enum.name)
00343             #else:
00344                 #print("Not implemented node type: " + tag + "\n")
00345         return self.model
00346 
00347     def add_extension_object(self):
00348         obj = Struct()
00349         obj.name = "ExtensionObject"
00350         f = Field()
00351         f.name = "TypeId"
00352         f.uatype = "NodeId"
00353         obj.fields.append(f)
00354         f = Field()
00355         f.name = "BinaryBody"
00356         f.uatype = "Bit"
00357         obj.fields.append(f)
00358         f = Field()
00359         f.name = "XmlBody"
00360         f.uatype = "Bit"
00361         obj.fields.append(f)
00362         f = Field()
00363         f.name = "Body"
00364         f.uatype = "ByteString"
00365         f.switchfield = "BinaryBody"
00366         obj.fields.append(f)
00367         self.model.struct_list.append(obj.name)
00368 
00369         self.model.structs.append(obj)
00370 
00371     def parse_struct(self, child):
00372         tag = child.tag[40:]
00373         struct = Struct()
00374         for key, val in child.attrib.items():
00375             if key == "Name":
00376                 struct.name = val
00377             elif key == "BaseType":
00378                 if ":" in val:
00379                     prefix, val = val.split(":")
00380                 struct.basetype = val
00381                 tmp = struct
00382                 while tmp.basetype:
00383                     struct.parents.append(tmp.basetype)
00384                     tmp = self.model.get_struct(tmp.basetype)
00385             else:
00386                 print("Error unknown key: ", key)
00387         for el in child:
00388             tag = el.tag[40:]
00389             if tag == "Field":
00390                 field = Field()
00391                 for key, val in el.attrib.items():
00392                     if key == "Name":
00393                         field.name = val
00394                     elif key == "TypeName":
00395                         field.uatype = val.split(":")[1]
00396                     elif key == "LengthField":
00397                         field.length = val
00398                     elif key == "SourceType":
00399                         field.sourcetype = val
00400                     elif key == "SwitchField":
00401                         field.switchfield = val
00402                     elif key == "SwitchValue":
00403                         field.switchvalue = val
00404                     elif key == "Length":
00405                         field.bitlength = int(val)
00406                     else:
00407                         print("Unknown field item: ", struct.name, key)
00408 
00409                 struct.fields.append(field)
00410             elif tag == "Documentation":
00411                 struct.doc = el.text
00412             else:
00413                 print("Unknown tag: ", tag)
00414 
00415         return struct
00416 
00417     def parse_enum(self, child):
00418         tag = child.tag[40:]
00419         enum = Enum()
00420         for k, v in child.items():
00421             if k == "Name":
00422                 enum.name = v
00423             elif k == "LengthInBits":
00424                 enum.uatype = "UInt" + v
00425             else:
00426                 print("Unknown attr for enum: ", k)
00427         for el in child:
00428             tag = el.tag[40:]
00429             if tag == "EnumeratedValue":
00430                 ev = EnumValue()
00431                 for k, v in el.attrib.items():
00432                     if k == "Name":
00433                         ev.name = v
00434                     elif k == "Value":
00435                         ev.value = v
00436                     else:
00437                         print("Unknown field attrib: ", k)
00438                 enum.values.append(ev)
00439             elif tag == "Documentation":
00440                 enum.doc = el.text
00441             else:
00442                 print("Unknown enum tag: ", tag)
00443         return enum
00444 
00445 
00446 #"def reorder_extobjects(model):
00447     #ext = model.get_struct("ExtensionObject")
00448     #print(ext)
00449     #typeid = ext.fields[4]
00450     #ext.fields.remove(typeid)
00451     #ext.fields.insert(0, typeid)
00452 
00453 def add_basetype_members(model):
00454     for struct in model.structs:
00455         if not struct.basetype:
00456             continue
00457         emptystruct = False
00458         if len(struct.fields) == 0:
00459             emptystruct = True
00460         if struct.basetype in ("ExtensionObject"):
00461             struct.basetype = None
00462             continue
00463         base = model.get_struct(struct.basetype)
00464         #if struct.basetype == "ExtensionObject" and len(struct.fields) != 0:
00465         #if struct.basetype == "ExtensionObject" and len(struct.fields) != 0:
00466             #if struc
00467             #for f in base.fields:
00468                 #if f.name == "TypeId":
00469                     #f2 = copy(f)
00470                     #f2.switchfield = None
00471                     #struct.fields.insert(0, f2)
00472                     #break
00473             #continue
00474         for name, bit in base.bits.items():
00475             struct.bits[name] = bit
00476         for idx, field in enumerate(base.fields):
00477             field = copy(field)
00478             if field.name == "Body" and not emptystruct:
00479                 #print("Field is names Body", struct.name, field.name)
00480                 struct.extensionobject = True
00481                 field.name = "BodyLength"
00482                 field.uatype = "Int32"
00483                 field.length = None
00484                 field.switchfield = None
00485                 #print("Field is names Body 2", struct.name, field.name)
00486             #HACK EXTENSIONOBJECT
00487             #if base.name == "ExtensionObject":
00488                 #continue
00489                 #if field.uatype == "Bit":
00490                     #continue
00491                 #if field.name == "Body":
00492                     #continue
00493                 #if field.name == "TypeId":
00494                     #field.switchfield = None
00495             #END HACK
00496             if not field.sourcetype:
00497                 field.sourcetype = base.name
00498             struct.fields.insert(idx, field)
00499 
00500 
00501 
00502 
00503 


ros_opcua_impl_python_opcua
Author(s): Denis Štogl , Daniel Draper
autogenerated on Sat Jun 8 2019 18:26:23