generate_model.py
Go to the documentation of this file.
1 """
2 Generate address space c++ code from xml file specification
3 """
4 import sys
5 from copy import copy
6 
7 import xml.etree.ElementTree as ET
8 
9 from IPython import embed
10 
11 #by default we split requests and respons in header and parameters, but some are so simple we do not split them
12 
13 #structs that end with Request or Response but are not
14 NotRequest = ["MonitoredItemCreateRequest", "MonitoredItemModifyRequest", "CallMethodRequest"]
15 
16 #some object are defined in extensionobjects in spec but seems not to be in reality
17 #in addition to this list all request and response and descriptions will not inherit
18 #NoInherit = ["RequestHeader", "ResponseHeader", "ChannelSecurityToken", "UserTokenPolicy", "SignatureData", "BrowseResult", "ReadValueId", "WriteValue", "BrowsePath", "BrowsePathTarget", "RelativePath", "RelativePathElement", "BrowsePathResult"]#, "ApplicationDescription", "EndpointDescription"
19 # many objects are defined as inheriting while inheriting ExtensionObjects while they do not so harcode those who really do
20 InheritExtensionObjects = ["UserIdentityToken", "NodeAttributes"]#"SignatureData"]
21 
22 
23 class Bit(object):
24  def __init__(self):
25  self.name = None
26  self.idx = None
27  self.container = None
28  self.length = 1
29 
30  def __str__(self):
31  return "(Bit: {}, container:{}, idx:{})".format(self.name, self.container, self.idx)
32  __repr__ = __str__
33 
34 class Struct(object):
35  def __init__(self):
36  self.name = None
37  self.basetype = None
38  self.doc = ""
39  self.fields = []
40  self.bits = {}
41  self.needconstructor = None
42  self.isrequest = False
43  self.needoverride = False
44  self.children = []
45  self.parents = []
46  self.extensionobject = False #used for struct which are not pure extension objects
47 
48  def get_field(self, name):
49  for f in self.fields:
50  if f.name == name:
51  return f
52  raise Exception("field not found: " + name)
53 
54  def __str__(self):
55  return "Struct {}:{}".format(self.name, self.basetype)
56 
57  __repr__ = __str__
58 
59 
60 class Field(object):
61  def __init__(self):
62  self.name = None
63  self.uatype = None
64  self.length = None
65  self.sourcetype = None
66  self.switchfield = None
67  self.switchvalue = None
68  self.bitlength = 1
69 
70  def __str__(self):
71  return "Field {}({})".format(self.name, self.uatype)
72 
73  __repr__ = __str__
74 
75  def is_native_type(self):
76  if self.uatype in ("Char", "SByte", "Int8", "Int16", "Int32", "Int64", "UInt8", "UInt16", "UInt32", "UInt64", "Boolean", "Double", "Float", "Byte", "String", "CharArray", "ByteString", "DateTime"):
77  return True
78  return False
79 
80  def get_ctype(self):
81  if self.uatype == "String":
82  ty = "std::string"
83  elif self.uatype == "CharArray":
84  ty = "std::string"
85  elif self.uatype == "Char":
86  ty = "uint8_t"
87  elif self.uatype == "SByte":
88  ty = "uint8_t"
89  elif self.uatype == "Int8":
90  ty = "int8_t"
91  elif self.uatype == "Int16":
92  ty = "int16_t"
93  elif self.uatype == "Int32":
94  ty = "int32_t"
95  elif self.uatype == "Int64":
96  ty = "int64_t"
97  elif self.uatype == "UInt8":
98  ty = "uint8_t"
99  elif self.uatype == "UInt16":
100  ty = "uint16_t"
101  elif self.uatype == "UInt32":
102  ty = "uint32_t"
103  elif self.uatype == "UInt64":
104  ty = "uint64_t"
105  elif self.uatype == "DateTime":
106  ty = "OpcUa::DateTime"
107  elif self.uatype == "Boolean":
108  ty = "bool"
109  elif self.uatype == "Double":
110  ty = "double"
111  elif self.uatype == "Float":
112  ty = "float"
113  elif self.uatype == "ByteString":
114  ty = "OpcUa::ByteString"
115  elif self.uatype == "Byte":
116  ty = "uint8_t"
117  else:
118  ty = "OpcUa::" + self.uatype
119  if self.length:
120  ty = "std::vector<{}>".format(ty)
121  return ty
122 
123 class Enum(object):
124  def __init__(self):
125  self.name = None
126  self.uatype = None
127  self.values = []
128  self.doc = ""
129 
130  def get_ctype(self):
131  return "{}_t".format(self.uatype.lower())
132 
133 class EnumValue(object):
134  def __init__(self):
135  self.name = None
136  self.value = None
137 
138 
139 class Model(object):
140  def __init__(self):
141  self.structs = []
142  self.enums = []
143  self.struct_list = []
144  self.enum_list = []
145 
146  def get_struct(self, name):
147  for struct in self.structs:
148  if name == struct.name:
149  return struct
150  raise Exception("No struct named: " + str(name))
151 
152  def get_enum(self, name):
153  for s in self.enums:
154  if name == s.name:
155  return s
156  raise Exception("No enum named: " + str(name))
157 
158 
159 def remove_duplicates(model):
160  for struct in model.structs:
161  fields = []
162  names = []
163  for field in struct.fields:
164  if field.name not in names:
165  names.append(field.name)
166  fields.append(field)
167  struct.fields = fields
168 
169 
171  for struct in model.structs:
172  newfields = []
173  container = None
174  idx = 0
175  for field in struct.fields:
176  if field.uatype in ("UInt6", "NodeIdType"):
177  container = field.name
178  b = Bit()
179  b.name = field.name
180  b.idx = 0
181  b.container = container
182  b.length = 6
183  idx = b.length
184  struct.bits[b.name] = b
185 
186  if field.uatype == "Bit":
187  if not container or idx > 7:
188  container = "Encoding"
189  idx = 0
190  f = Field()
191  f.sourcetype = field.sourcetype
192  f.name = "Encoding"
193  f.uatype = "UInt8"
194  newfields.append(f)
195 
196  b = Bit()
197  b.name = field.name
198  b.idx = idx
199  b.container = container
200  b.length = field.bitlength
201  idx += field.bitlength
202  struct.bits[b.name] = b
203  else:
204  newfields.append(field)
205  struct.fields = newfields
206 
208  for struct in model.structs:
209  new = []
210  for field in struct.fields:
211  if not field.name.startswith("NoOf"):
212  new.append(field)
213  struct.fields = new
214 
216  for struct in model.structs:
217  new = []
218  for field in struct.fields:
219  if not field.name == "BodyLength":
220  new.append(field)
221  struct.fields = new
222 
223 #def remove_extensionobject_fields(model):
224  #for obj in model.structs:
225  #if obj.name.endswith("Request") or obj.name.endswith("Response"):
226  #obj.fields = [el for el in obj.fields if el.name not in ("TypeId", "Body", "Encoding")]
227 
228 def split_requests(model, NoSplitStruct):
229  structs = []
230  for struct in model.structs:
231  structtype = None
232  if struct.name.endswith("Request") and not struct.name in NotRequest:
233  structtype = "Request"
234  elif struct.name.endswith("Response") or struct.name == "ServiceFault":
235  structtype = "Response"
236  if structtype:
237  #for field in struct.fields:
238  #if field.name == "Encoding":
239  #struct.fields.remove(field)
240  #break
241  #for field in struct.fields:
242  #if field.name == "BodyLength":
243  #struct.fields.remove(field)
244  #break
245  struct.isrequest = True
246  struct.needconstructor = True
247  field = Field()
248  field.name = "TypeId"
249  field.uatype = "NodeId"
250  struct.fields.insert(0, field)
251 
252  if structtype and not struct.name in NoSplitStruct:
253  paramstruct = Struct()
254  if structtype == "Request":
255  basename = struct.name.replace("Request", "") + "Parameters"
256  paramstruct.name = basename
257  else:
258  basename = struct.name.replace("Response", "") + "Result"
259  paramstruct.name = basename
260  paramstruct.fields = struct.fields[2:]
261  paramstruct.bits = struct.bits
262 
263  struct.fields = struct.fields[:2]
264  #struct.bits = {}
265  structs.append(paramstruct)
266 
267  typeid = Field()
268  typeid.name = "Parameters"
269  typeid.uatype = paramstruct.name
270  struct.fields.append(typeid)
271  structs.append(struct)
272  model.structs = structs
273  model.struct_list = [s.name for s in model.structs]
274 
275 
276 class Parser(object):
277  def __init__(self, path):
278  self.path = path
279  self.model = None
280 
281  def parse(self):
282  print("Parsing: ", self.path)
283  self.model = Model()
284  tree = ET.parse(self.path)
285  root = tree.getroot()
286  self.add_extension_object()
287  for child in root:
288  tag = child.tag[40:]
289  if tag == "StructuredType":
290  struct = self.parse_struct(child)
291  if struct.name != "ExtensionObject":
292  self.model.structs.append(struct)
293  self.model.struct_list.append(struct.name)
294  elif tag == "EnumeratedType":
295  enum = self.parse_enum(child)
296  self.model.enums.append(enum)
297  self.model.enum_list.append(enum.name)
298  #else:
299  #print("Not implemented node type: " + tag + "\n")
300  return self.model
301 
303  obj = Struct()
304  obj.name = "ExtensionObject"
305  f = Field()
306  f.name = "TypeId"
307  f.uatype = "NodeId"
308  obj.fields.append(f)
309  f = Field()
310  f.name = "BinaryBody"
311  f.uatype = "Bit"
312  obj.fields.append(f)
313  f = Field()
314  f.name = "XmlBody"
315  f.uatype = "Bit"
316  obj.fields.append(f)
317  f = Field()
318  f.name = "Body"
319  f.uatype = "ByteString"
320  f.switchfield = "BinaryBody"
321  obj.fields.append(f)
322  self.model.struct_list.append(obj.name)
323 
324  self.model.structs.append(obj)
325 
326  def parse_struct(self, child):
327  tag = child.tag[40:]
328  struct = Struct()
329  for key, val in child.attrib.items():
330  if key == "Name":
331  struct.name = val
332  elif key == "BaseType":
333  if ":" in val:
334  prefix, val = val.split(":")
335  struct.basetype = val
336  tmp = struct
337  while tmp.basetype:
338  struct.parents.append(tmp.basetype)
339  tmp = self.model.get_struct(tmp.basetype)
340  else:
341  print("Error unknown key: ", key)
342  for el in child:
343  tag = el.tag[40:]
344  if tag == "Field":
345  field = Field()
346  for key, val in el.attrib.items():
347  if key == "Name":
348  field.name = val
349  elif key == "TypeName":
350  field.uatype = val.split(":")[1]
351  elif key == "LengthField":
352  field.length = val
353  elif key == "SourceType":
354  field.sourcetype = val
355  elif key == "SwitchField":
356  field.switchfield = val
357  elif key == "SwitchValue":
358  field.switchvalue = val
359  elif key == "Length":
360  field.bitlength = int(val)
361  else:
362  print("Uknown field item: ", struct.name, key)
363 
364  struct.fields.append(field)
365  elif tag == "Documentation":
366  struct.doc = el.text
367  else:
368  print("Uknown tag: ", tag)
369 
370  return struct
371 
372  def parse_enum(self, child):
373  tag = child.tag[40:]
374  enum = Enum()
375  for k, v in child.items():
376  if k == "Name":
377  enum.name = v
378  elif k == "LengthInBits":
379  enum.uatype = "UInt" + v
380  else:
381  print("Unknown attr for enum: ", k)
382  for el in child:
383  tag = el.tag[40:]
384  if tag == "EnumeratedValue":
385  ev = EnumValue()
386  for k, v in el.attrib.items():
387  if k == "Name":
388  ev.name = v
389  elif k == "Value":
390  ev.value = v
391  else:
392  print("Uknown field attrib: ", k)
393  enum.values.append(ev)
394  elif tag == "Documentation":
395  enum.doc = el.text
396  else:
397  print("Unknown enum tag: ", tag)
398  return enum
399 
400 
401 #"def reorder_extobjects(model):
402  #ext = model.get_struct("ExtensionObject")
403  #print(ext)
404  #typeid = ext.fields[4]
405  #ext.fields.remove(typeid)
406  #ext.fields.insert(0, typeid)
407 
409  for struct in model.structs:
410  if not struct.basetype:
411  continue
412  emptystruct = False
413  if len(struct.fields) == 0:
414  emptystruct = True
415  if not emptystruct and struct.basetype in ("ExtensionObject") and not struct.name in InheritExtensionObjects:
416  #if struct.name in NoInherit or struct.name.endswith("Request") or struct.name.endswith("Response") or struct.name.endswith("Description"):
417  struct.parents.remove(struct.basetype)
418  struct.basetype = None
419  continue
420  base = model.get_struct(struct.basetype)
421  #if struct.basetype == "ExtensionObject" and len(struct.fields) != 0:
422  #if struct.basetype == "ExtensionObject" and len(struct.fields) != 0:
423  #if struc
424  #for f in base.fields:
425  #if f.name == "TypeId":
426  #f2 = copy(f)
427  #f2.switchfield = None
428  #struct.fields.insert(0, f2)
429  #break
430  #continue
431  for name, bit in base.bits.items():
432  struct.bits[name] = bit
433  for idx, field in enumerate(base.fields):
434  field = copy(field)
435  if field.name == "Body" and not emptystruct:
436  #print("Field is names Body", struct.name, field.name)
437  struct.extensionobject = True
438  field.name = "BodyLength"
439  field.uatype = "Int32"
440  field.length = None
441  field.switchfield = None
442  #print("Field is names Body 2", struct.name, field.name)
443  #HACK EXTENSIONOBJECT
444  #if base.name == "ExtensionObject":
445  #continue
446  #if field.uatype == "Bit":
447  #continue
448  #if field.name == "Body":
449  #continue
450  #if field.name == "TypeId":
451  #field.switchfield = None
452  #END HACK
453  if not field.sourcetype:
454  field.sourcetype = base.name
455  struct.fields.insert(idx, field)
456 
457 
458 
459 
460 
def get_enum(self, name)
def parse_enum(self, child)
def remove_duplicates(model)
FMT_API void print(std::FILE *f, CStringRef format_str, ArgList args)
Definition: format.cc:873
def add_basetype_members(model)
std::string format(CStringRef format_str, ArgList args)
Definition: format.h:3686
def get_struct(self, name)
def remove_body_length(model)
def add_encoding_field(model)
def remove_vector_length(model)
def split_requests(model, NoSplitStruct)
def __init__(self, path)
def parse_struct(self, child)
def add_extension_object(self)
def get_field(self, name)


ros_opcua_impl_freeopcua
Author(s): Denis Štogl
autogenerated on Tue Jan 19 2021 03:06:05