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
00012
00013
00014 NotRequest = ["MonitoredItemCreateRequest", "MonitoredItemModifyRequest", "CallMethodRequest"]
00015
00016
00017
00018
00019
00020 InheritExtensionObjects = ["UserIdentityToken", "NodeAttributes"]
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
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
00224
00225
00226
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
00238
00239
00240
00241
00242
00243
00244
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
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
00299
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
00402
00403
00404
00405
00406
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
00417 struct.parents.remove(struct.basetype)
00418 struct.basetype = None
00419 continue
00420 base = model.get_struct(struct.basetype)
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
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
00437 struct.extensionobject = True
00438 field.name = "BodyLength"
00439 field.uatype = "Int32"
00440 field.length = None
00441 field.switchfield = None
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453 if not field.sourcetype:
00454 field.sourcetype = base.name
00455 struct.fields.insert(idx, field)
00456
00457
00458
00459
00460