plcopen/plcopen.py
changeset 1302 7856cd7767d6
parent 1301 fcca121a000f
child 1305 714f1381a09a
equal deleted inserted replaced
1301:fcca121a000f 1302:7856cd7767d6
   239         return [(tuple(parent_infos),) + result for result in TestTextElement(self.getanyText(), criteria)]
   239         return [(tuple(parent_infos),) + result for result in TestTextElement(self.getanyText(), criteria)]
   240     setattr(cls, "Search", Search)
   240     setattr(cls, "Search", Search)
   241     
   241     
   242 cls = PLCOpenParser.GetElementClass("project")
   242 cls = PLCOpenParser.GetElementClass("project")
   243 if cls:
   243 if cls:
   244     cls.ElementUsingTree = {}
       
   245     cls.CustomBlockTypes = OrderedDict()
       
   246     
   244     
   247     def setname(self, name):
   245     def setname(self, name):
   248         self.contentHeader.setname(name)
   246         self.contentHeader.setname(name)
   249     setattr(cls, "setname", setname)
   247     setattr(cls, "setname", setname)
   250         
   248         
   303                 contentheader_obj.setscaling(contentheader["scaling"])
   301                 contentheader_obj.setscaling(contentheader["scaling"])
   304             else:
   302             else:
   305                 setattr(contentheader_obj, attr, value)
   303                 setattr(contentheader_obj, attr, value)
   306     setattr(cls, "setcontentHeader", setcontentHeader)
   304     setattr(cls, "setcontentHeader", setcontentHeader)
   307     
   305     
   308     def gettypeElement(self, element_type, name=None):
   306     def gettypeElement(self, element_type, name):
   309         filter = "[@name='%s']" % name if name is not None else ""
   307         elements = self.xpath(
   310         elements = self.xpath("ppx:types/ppx:%(element_type)ss/ppx:%(element_type)s%(filter)s" % locals(),
   308             "ppx:types/ppx:%(element_type)ss/ppx:%(element_type)s[@name='%(name)s']" % locals(),
   311                 namespaces=PLCOpenParser.NSMAP)
   309             namespaces=PLCOpenParser.NSMAP)
   312         if name is None:
   310         if name is None:
   313             return elements
   311             return elements
   314         elif len(elements) == 1:
   312         elif len(elements) == 1:
   315             return elements[0]
   313             return elements[0]
   316         return None
   314         return None
   317     setattr(cls, "gettypeElement", gettypeElement)
   315     setattr(cls, "gettypeElement", gettypeElement)
   318     
   316     
   319     def getdataTypes(self):
   317     def getdataTypes(self, exclude=None):
   320         return self.getdataType()
   318         return self.xpath(
       
   319             "ppx:types/ppx:dataTypes/ppx:dataType%s" % 
       
   320                 ("[@name!='%s']" % exclude if exclude is not None else ""),
       
   321             namespaces=PLCOpenParser.NSMAP)
   321     setattr(cls, "getdataTypes", getdataTypes)
   322     setattr(cls, "getdataTypes", getdataTypes)
   322     
   323     
   323     def getdataType(self, name=None):
   324     def getdataType(self, name):
   324         return self.gettypeElement("dataType", name)
   325         return self.gettypeElement("dataType", name)
   325     setattr(cls, "getdataType", getdataType)
   326     setattr(cls, "getdataType", getdataType)
   326     
   327     
   327     def appenddataType(self, name):
   328     def appenddataType(self, name):
   328         if self.getdataType(name) is not None:
   329         if self.getdataType(name) is not None:
   334         self.types.insertdataTypeElement(index, datatype)
   335         self.types.insertdataTypeElement(index, datatype)
   335     setattr(cls, "insertdataType", insertdataType)
   336     setattr(cls, "insertdataType", insertdataType)
   336     
   337     
   337     def removedataType(self, name):
   338     def removedataType(self, name):
   338         self.types.removedataTypeElement(name)
   339         self.types.removedataTypeElement(name)
   339         self.RefreshElementUsingTree()
       
   340     setattr(cls, "removedataType", removedataType)
   340     setattr(cls, "removedataType", removedataType)
   341     
   341     
   342     def getpous(self):
   342     def getpous(self, exclude=None, filter=None):
   343         return self.getpou()
   343         return self.xpath(
       
   344             "ppx:types/ppx:pous/ppx:pou%s%s" % 
       
   345                 (("[@name!='%s']" % exclude) if exclude is not None else '',
       
   346                  ("[%s]" % " or ".join(
       
   347                     map(lambda x: "@pouType='%s'" % x, filter)))
       
   348                  if filter is not None else ""),
       
   349             namespaces=PLCOpenParser.NSMAP)
   344     setattr(cls, "getpous", getpous)
   350     setattr(cls, "getpous", getpous)
   345     
   351     
   346     def getpou(self, name=None):
   352     def getpou(self, name):
   347         return self.gettypeElement("pou", name)
   353         return self.gettypeElement("pou", name)
   348     setattr(cls, "getpou", getpou)
   354     setattr(cls, "getpou", getpou)
   349     
   355     
   350     def appendpou(self, name, pou_type, body_type):
   356     def appendpou(self, name, pou_type, body_type):
   351         self.types.appendpouElement(name, pou_type, body_type)
   357         self.types.appendpouElement(name, pou_type, body_type)
   352         self.AddCustomBlockType(self.getpou(name))
       
   353     setattr(cls, "appendpou", appendpou)
   358     setattr(cls, "appendpou", appendpou)
   354         
   359         
   355     def insertpou(self, index, pou):
   360     def insertpou(self, index, pou):
   356         self.types.insertpouElement(index, pou)
   361         self.types.insertpouElement(index, pou)
   357         self.AddCustomBlockType(pou)
       
   358     setattr(cls, "insertpou", insertpou)
   362     setattr(cls, "insertpou", insertpou)
   359     
   363     
   360     def removepou(self, name):
   364     def removepou(self, name):
   361         self.types.removepouElement(name)
   365         self.types.removepouElement(name)
   362         self.RefreshCustomBlockTypes()
       
   363         self.RefreshElementUsingTree()
       
   364     setattr(cls, "removepou", removepou)
   366     setattr(cls, "removepou", removepou)
   365 
   367 
   366     def getconfigurations(self):
   368     def getconfigurations(self):
   367         return self.getconfiguration()
   369         return self.getconfiguration()
   368     setattr(cls, "getconfigurations", getconfigurations)
   370     setattr(cls, "getconfigurations", getconfigurations)
   456             pou.removeVariableByFilter(address_model)
   458             pou.removeVariableByFilter(address_model)
   457         for configuration in self.getconfigurations():
   459         for configuration in self.getconfigurations():
   458             configuration.removeVariableByFilter(address_model)
   460             configuration.removeVariableByFilter(address_model)
   459     setattr(cls, "removeVariableByFilter", removeVariableByFilter)
   461     setattr(cls, "removeVariableByFilter", removeVariableByFilter)
   460 
   462 
   461     # Update Block types with user-defined pou added
       
   462     def RefreshCustomBlockTypes(self):
       
   463         # Reset the tree of user-defined pou cross-use
       
   464         self.CustomBlockTypes = OrderedDict()
       
   465         for pou in self.getpous():
       
   466             self.AddCustomBlockType(pou)
       
   467     setattr(cls, "RefreshCustomBlockTypes", RefreshCustomBlockTypes)
       
   468 
       
   469     def AddCustomBlockType(self, pou): 
       
   470         pou_name = pou.getname()
       
   471         pou_type = pou.getpouType()
       
   472         block_infos = {"name" : pou_name, "type" : pou_type, "extensible" : False,
       
   473                        "inputs" : [], "outputs" : [], "comment" : pou.getdescription(),
       
   474                        "generate" : generate_block, "initialise" : initialise_block}
       
   475         if pou.interface is not None:
       
   476             return_type = pou.interface.getreturnType()
       
   477             if return_type is not None:
       
   478                 var_type = return_type.getcontent()
       
   479                 var_type_name = var_type.getLocalTag()
       
   480                 if var_type_name == "derived":
       
   481                     block_infos["outputs"].append(("OUT", var_type.getname(), "none"))
       
   482                 elif var_type_name in ["string", "wstring"]:
       
   483                     block_infos["outputs"].append(("OUT", var_type_name.upper(), "none"))
       
   484                 else:
       
   485                     block_infos["outputs"].append(("OUT", var_type_name, "none"))
       
   486             for type, varlist in pou.getvars():
       
   487                 if type == "InOut":
       
   488                     for var in varlist.getvariable():
       
   489                         var_type = var.type.getcontent()
       
   490                         var_type_name = var_type.getLocalTag()
       
   491                         if var_type_name == "derived":
       
   492                             block_infos["inputs"].append((var.getname(), var_type.getname(), "none"))
       
   493                             block_infos["outputs"].append((var.getname(), var_type.getname(), "none"))
       
   494                         elif var_type_name in ["string", "wstring"]:
       
   495                             block_infos["inputs"].append((var.getname(), var_type_name.upper(), "none"))
       
   496                             block_infos["outputs"].append((var.getname(), var_type_name.upper(), "none"))
       
   497                         else:
       
   498                             block_infos["inputs"].append((var.getname(), var_type_name, "none"))
       
   499                             block_infos["outputs"].append((var.getname(), var_type_name, "none"))
       
   500                 elif type == "Input":
       
   501                     for var in varlist.getvariable():
       
   502                         var_type = var.type.getcontent()
       
   503                         var_type_name = var_type.getLocalTag()
       
   504                         if var_type_name == "derived":
       
   505                             block_infos["inputs"].append((var.getname(), var_type.getname(), "none"))
       
   506                         elif var_type_name in ["string", "wstring"]:
       
   507                             block_infos["inputs"].append((var.getname(), var_type_name.upper(), "none"))
       
   508                         else:
       
   509                             block_infos["inputs"].append((var.getname(), var_type_name, "none"))
       
   510                 elif type == "Output":
       
   511                     for var in varlist.getvariable():
       
   512                         var_type = var.type.getcontent()
       
   513                         var_type_name = var_type.getLocalTag()
       
   514                         if var_type_name == "derived":
       
   515                             block_infos["outputs"].append((var.getname(), var_type.getname(), "none"))
       
   516                         elif var_type_name in ["string", "wstring"]:
       
   517                             block_infos["outputs"].append((var.getname(), var_type_name.upper(), "none"))
       
   518                         else:
       
   519                             block_infos["outputs"].append((var.getname(), var_type_name, "none"))    
       
   520         block_infos["usage"] = "\n (%s) => (%s)" % (", ".join(["%s:%s" % (input[1], input[0]) for input in block_infos["inputs"]]),
       
   521                                                     ", ".join(["%s:%s" % (output[1], output[0]) for output in block_infos["outputs"]]))
       
   522         self.CustomBlockTypes[pou_name]=block_infos
       
   523     setattr(cls, "AddCustomBlockType", AddCustomBlockType)
       
   524 
       
   525     def AddElementUsingTreeInstance(self, name, type_infos):
       
   526         typename = type_infos.getname()
       
   527         elements = self.ElementUsingTree.setdefault(typename, set())
       
   528         elements.add(name)
       
   529     setattr(cls, "AddElementUsingTreeInstance", AddElementUsingTreeInstance)
       
   530     
       
   531     def RefreshElementUsingTree(self):
       
   532         # Reset the tree of user-defined element cross-use
       
   533         self.ElementUsingTree = {}
       
   534         
       
   535         # Analyze each datatype
       
   536         for datatype in self.getdataTypes():
       
   537             name = datatype.getname()
       
   538             basetype_content = datatype.baseType.getcontent()
       
   539             basetype_content_name = basetype_content.getLocalTag()
       
   540             if basetype_content_name == "derived":
       
   541                 self.AddElementUsingTreeInstance(name, basetype_content)
       
   542             elif basetype_content_name in ["subrangeSigned", "subrangeUnsigned", "array"]:
       
   543                 base_type = basetype_content.baseType.getcontent()
       
   544                 if base_type.getLocalTag() == "derived":
       
   545                     self.AddElementUsingTreeInstance(name, base_type)
       
   546             elif basetype_content_name == "struct":
       
   547                 for element in basetype_content.getvariable():
       
   548                     type_content = element.type.getcontent()
       
   549                     if type_content.getLocalTag() == "derived":
       
   550                         self.AddElementUsingTreeInstance(name, type_content)
       
   551             
       
   552         # Analyze each pou
       
   553         for pou in self.getpous():
       
   554             name = pou.getname()
       
   555             if pou.interface is not None:
       
   556                 # Extract variables from every varLists
       
   557                 for varlist_type, varlist in pou.getvars():
       
   558                     for var in varlist.getvariable():
       
   559                         vartype_content = var.gettype().getcontent()
       
   560                         if vartype_content.getLocalTag() == "derived":
       
   561                             self.AddElementUsingTreeInstance(name, vartype_content)
       
   562         
       
   563     setattr(cls, "RefreshElementUsingTree", RefreshElementUsingTree)
       
   564 
       
   565     # Return if pou given by name is used by another pou
       
   566     def ElementIsUsed(self, name):
       
   567         elements = self.ElementUsingTree.get(name, None)
       
   568         return elements is not None
       
   569     setattr(cls, "ElementIsUsed", ElementIsUsed)
       
   570 
       
   571     # Return if pou given by name is directly or undirectly used by the reference pou
       
   572     def ElementIsUsedBy(self, name, reference):
       
   573         elements = self.ElementUsingTree.get(name, set())
       
   574         # Test if pou is directly used by reference
       
   575         if reference in elements:
       
   576             return True
       
   577         else:
       
   578             # Test if pou is undirectly used by reference, by testing if pous
       
   579             # that directly use pou is directly or undirectly used by reference
       
   580             selffn = self.ElementIsUsedBy
       
   581             for element in elements:
       
   582                 if selffn(element, reference):
       
   583                     return True
       
   584         return False
       
   585     setattr(cls, "ElementIsUsedBy", ElementIsUsedBy)
       
   586 
       
   587     def GetEnumeratedDataTypeValues(self):
   463     def GetEnumeratedDataTypeValues(self):
   588         return [
   464         return [
   589             value.getname() 
   465             value.getname() 
   590             for value in self.xpath(
   466             for value in self.xpath(
   591                 "ppx:types/ppx:dataTypes/ppx:dataType/ppx:baseType/ppx:enum/ppx:values/ppx:value",
   467                 "ppx:types/ppx:dataTypes/ppx:dataType/ppx:baseType/ppx:enum/ppx:values/ppx:value",
   592                 namespaces=PLCOpenParser.NSMAP)]
   468                 namespaces=PLCOpenParser.NSMAP)]
   593     setattr(cls, "GetEnumeratedDataTypeValues", GetEnumeratedDataTypeValues)
   469     setattr(cls, "GetEnumeratedDataTypeValues", GetEnumeratedDataTypeValues)
   594 
       
   595     # Function that returns the block definition associated to the block type given
       
   596     def GetCustomBlockType(self, typename, inputs = None):
       
   597         customblocktype = self.CustomBlockTypes.get(typename,None)
       
   598         if customblocktype is not None:
       
   599             if inputs is not None and inputs != "undefined":
       
   600                 customblock_inputs = tuple([var_type for name, var_type, modifier in customblocktype["inputs"]])
       
   601                 if inputs == customblock_inputs:
       
   602                     return customblocktype
       
   603             else:
       
   604                 return customblocktype
       
   605         return None
       
   606     setattr(cls, "GetCustomBlockType", GetCustomBlockType)
       
   607 
       
   608     # Return Block types checking for recursion
       
   609     def GetCustomBlockTypes(self, exclude = None, onlyfunctions = False):
       
   610         if exclude is not None:
       
   611             return [customblocktype for name,customblocktype in self.CustomBlockTypes.iteritems()
       
   612                 if (customblocktype["type"] != "program"
       
   613                     and name != exclude
       
   614                     and not self.ElementIsUsedBy(exclude, name)
       
   615                     and not (onlyfunctions and customblocktype["type"] != "function"))]
       
   616         return [customblocktype for customblocktype in self.CustomBlockTypes.itervalues()
       
   617             if (customblocktype["type"] != "program"
       
   618                 and not (onlyfunctions and customblocktype["type"] != "function"))]
       
   619     setattr(cls, "GetCustomBlockTypes", GetCustomBlockTypes)
       
   620 
       
   621     # Return Function Block types checking for recursion
       
   622     def GetCustomFunctionBlockTypes(self, exclude = None):
       
   623         if exclude is not None:
       
   624             return [name for name,customblocktype in self.CustomBlockTypes.iteritems()
       
   625                 if (customblocktype["type"] == "functionBlock" 
       
   626                     and name != exclude 
       
   627                     and not self.ElementIsUsedBy(exclude, name))]
       
   628         return [name for customblocktype in self.CustomBlockTypes.itervalues()
       
   629             if customblocktype["type"] == "functionBlock"]
       
   630     setattr(cls, "GetCustomFunctionBlockTypes", GetCustomFunctionBlockTypes)
       
   631 
       
   632     # Return Block types checking for recursion
       
   633     def GetCustomBlockResource(self):
       
   634         return [customblocktype["name"] for customblocktype in self.CustomBlockTypes.itervalues()
       
   635             if customblocktype["type"] == "program"]
       
   636     setattr(cls, "GetCustomBlockResource", GetCustomBlockResource)
       
   637 
       
   638     # Return Data Types checking for recursion
       
   639     def GetCustomDataTypes(self, exclude = "", only_locatable = False):
       
   640         customdatatypes = []
       
   641         for customdatatype in self.getdataTypes():
       
   642             if not only_locatable or self.IsLocatableType(customdatatype):
       
   643                 customdatatype_name = customdatatype.getname()
       
   644                 if customdatatype_name != exclude and not self.ElementIsUsedBy(exclude, customdatatype_name):
       
   645                     customdatatypes.append({"name": customdatatype_name, "infos": customdatatype})
       
   646         return customdatatypes
       
   647     setattr(cls, "GetCustomDataTypes", GetCustomDataTypes)
       
   648 
   470 
   649     def Search(self, criteria, parent_infos=[]):
   471     def Search(self, criteria, parent_infos=[]):
   650         result = self.types.Search(criteria, parent_infos)
   472         result = self.types.Search(criteria, parent_infos)
   651         for configuration in self.instances.configurations.getconfiguration():
   473         for configuration in self.instances.configurations.getconfiguration():
   652             result.extend(configuration.Search(criteria, parent_infos))
   474             result.extend(configuration.Search(criteria, parent_infos))
  1166             for result in TestTextElement(value.getname(), criteria):
   988             for result in TestTextElement(value.getname(), criteria):
  1167                 search_result.append((tuple(parent_infos + ["value", i]),) + result)
   989                 search_result.append((tuple(parent_infos + ["value", i]),) + result)
  1168         return search_result
   990         return search_result
  1169     setattr(cls, "Search", Search)
   991     setattr(cls, "Search", Search)
  1170 
   992 
       
   993 def _getvariableTypeinfos(variable_type):
       
   994     type_content = variable_type.getcontent()
       
   995     type_content_type = type_content.getLocalTag()
       
   996     if type_content_type == "derived":
       
   997         return type_content.getname()
       
   998     return type_content_type.upper()
       
   999     
  1171 cls = PLCOpenParser.GetElementClass("pou", "pous")
  1000 cls = PLCOpenParser.GetElementClass("pou", "pous")
  1172 if cls:
  1001 if cls:
       
  1002     
       
  1003     def getblockInfos(self): 
       
  1004         block_infos = {
       
  1005             "name" : self.getname(), 
       
  1006             "type" : self.getpouType(), 
       
  1007             "extensible" : False,
       
  1008             "inputs" : [], 
       
  1009             "outputs" : [], 
       
  1010             "comment" : self.getdescription(),
       
  1011             "generate" : generate_block, 
       
  1012             "initialise" : initialise_block}
       
  1013         if self.interface is not None:
       
  1014             return_type = self.interface.getreturnType()
       
  1015             if return_type is not None:
       
  1016                 block_infos["outputs"].append(
       
  1017                     ("OUT", _getvariableTypeinfos(return_type), "none"))
       
  1018             for var in self.xpath(
       
  1019                 "ppx:interface/*[self::ppx:inputVars or self::ppx:inOutVars]/ppx:variable",
       
  1020                 namespaces=PLCOpenParser.NSMAP):
       
  1021                 block_infos["inputs"].append(
       
  1022                     (var.getname(), _getvariableTypeinfos(var.type), "none"))
       
  1023             for var in self.xpath(
       
  1024                 "ppx:interface/*[self::ppx:outputVars or self::ppx:inOutVars]/ppx:variable",
       
  1025                 namespaces=PLCOpenParser.NSMAP):
       
  1026                 block_infos["outputs"].append(
       
  1027                     (var.getname(), _getvariableTypeinfos(var.type), "none"))
       
  1028             
       
  1029         block_infos["usage"] = ("\n (%s) => (%s)" % 
       
  1030             (", ".join(["%s:%s" % (input[1], input[0]) 
       
  1031                         for input in block_infos["inputs"]]),
       
  1032              ", ".join(["%s:%s" % (output[1], output[0]) 
       
  1033                         for output in block_infos["outputs"]])))
       
  1034         return block_infos
       
  1035     setattr(cls, "getblockInfos", getblockInfos)
  1173     
  1036     
  1174     def setdescription(self, description):
  1037     def setdescription(self, description):
  1175         doc = self.getdocumentation()
  1038         doc = self.getdocumentation()
  1176         if doc is None:
  1039         if doc is None:
  1177             doc = PLCOpenParser.CreateElement("documentation", "pou")
  1040             doc = PLCOpenParser.CreateElement("documentation", "pou")
  2331     setattr(cls, "getconditionConnection", getconditionConnection)
  2194     setattr(cls, "getconditionConnection", getconditionConnection)
  2332 
  2195 
  2333     def getBoundingBox(self):
  2196     def getBoundingBox(self):
  2334         bbox = _getBoundingBoxSingle(self)
  2197         bbox = _getBoundingBoxSingle(self)
  2335         condition_connection = self.getconditionConnection()
  2198         condition_connection = self.getconditionConnection()
  2336         if condition_connection:
  2199         if condition_connection is not None:
  2337             bbox.union(_getConnectionsBoundingBox(condition_connection))
  2200             bbox.union(_getConnectionsBoundingBox(condition_connection))
  2338         return bbox
  2201         return bbox
  2339     setattr(cls, "getBoundingBox", getBoundingBox)
  2202     setattr(cls, "getBoundingBox", getBoundingBox)
  2340     
  2203     
  2341     def translate(self, dx, dy):
  2204     def translate(self, dx, dy):