--- a/PLCControler.py Mon Sep 02 23:46:38 2013 +0200
+++ b/PLCControler.py Tue Sep 03 23:32:53 2013 +0200
@@ -568,7 +568,7 @@
instances.append(var_path)
pou = project.getpou(var_type)
- if pou is not None and project.ElementIsUsedBy(pou_type, var_type):
+ if pou is not None:# and project.ElementIsUsedBy(pou_type, var_type): self.RecursiveSearchPouInstances(
project, pou_type, var_path,
@@ -603,7 +603,7 @@
instances.append(pou_path)
pou = project.getpou(pou_type)
- if pou is not None and project.ElementIsUsedBy(words[1], pou_type):
+ if pou is not None:# and project.ElementIsUsedBy(words[1], pou_type): self.RecursiveSearchPouInstances(
project, words[1], pou_path,
@@ -733,23 +733,23 @@
# Return if data type given by name is used by another data type or pou
def DataTypeIsUsed(self, name, debug = False):
- project = self.GetProject(debug)
- if project is not None:
- return project.ElementIsUsed(name)
+ #project = self.GetProject(debug) + #if project is not None: + # return project.ElementIsUsed(name) # Return if pou given by name is used by another pou
def PouIsUsed(self, name, debug = False):
- project = self.GetProject(debug)
- if project is not None:
- return project.ElementIsUsed(name)
+ #project = self.GetProject(debug) + #if project is not None: + # return project.ElementIsUsed(name) # Return if pou given by name is directly or undirectly used by the reference pou
def PouIsUsedBy(self, name, reference, debug = False):
- project = self.GetProject(debug)
- if project is not None:
- return project.ElementIsUsedBy(name, reference)
+ #project = self.GetProject(debug) + #if project is not None: + # return project.ElementIsUsedBy(name, reference) def GenerateProgram(self, filepath=None):
@@ -837,7 +837,6 @@
pou = self.Project.getpou(name)
- self.Project.RefreshCustomBlockTypes()
def GetPouXml(self, pou_name):
@@ -980,7 +979,6 @@
datatype.setname(new_name)
self.Project.updateElementName(old_name, new_name)
- self.Project.RefreshElementUsingTree()
# Change the name of a pou
@@ -991,8 +989,6 @@
self.Project.updateElementName(old_name, new_name)
- self.Project.RefreshElementUsingTree()
- self.Project.RefreshCustomBlockTypes()
# Change the name of a pou transition
@@ -1029,7 +1025,6 @@
for var in varlist.getvariable():
if var.getname() == old_name:
- self.Project.RefreshCustomBlockTypes()
# Change the name of a configuration
@@ -1068,7 +1063,6 @@
pou = project.getpou(name)
pou.setdescription(description)
- project.RefreshCustomBlockTypes()
# Return the type of the pou given by its name
@@ -1402,9 +1396,7 @@
tree.insert(0, ("EN", "BOOL", ([], [])))
- datatype = project.getdataType(typename)
- datatype = self.GetConfNodeDataType(typename)
+ datatype = self.GetDataType(typename) basetype_content = datatype.baseType.getcontent()
@@ -1463,9 +1455,7 @@
pou.interface = PLCOpenParser.CreateElement("interface", "pou")
pou.setvars([varlist for varlist_type, varlist in self.ExtractVarLists(vars)])
- self.Project.RefreshElementUsingTree()
- self.Project.RefreshCustomBlockTypes()
# Replace the return type of the pou given by its name (only for functions)
def SetPouInterfaceReturnType(self, name, return_type):
if self.Project is not None:
@@ -1488,9 +1478,7 @@
derived_type = PLCOpenParser.CreateElement("derived", "dataType")
derived_type.setname(return_type)
return_type.setcontent(derived_type)
- self.Project.RefreshElementUsingTree()
- self.Project.RefreshCustomBlockTypes()
def UpdateProjectUsedPous(self, old_name, new_name):
if self.Project is not None:
self.Project.updateElementName(old_name, new_name)
@@ -1529,7 +1517,8 @@
def AddConfNodeTypesList(self, typeslist):
self.ConfNodeTypes.extend(typeslist)
addedcat = [{"name": _("%s POUs") % confnodetypes["name"],
- "list": confnodetypes["types"].GetCustomBlockTypes()}
+ "list": [pou.getblockInfos() + for pou in confnodetypes["types"].getpous()]} for confnodetypes in typeslist]
self.TotalTypes.extend(addedcat)
@@ -1543,23 +1532,14 @@
self.TotalTypesDict = StdBlckDct.copy()
self.TotalTypes = StdBlckLst[:]
- def GetConfNodeBlockTypes(self):
- return [{"name": _("%s POUs") % confnodetypes["name"],
- "list": confnodetypes["types"].GetCustomBlockTypes()}
- for confnodetypes in self.ConfNodeTypes]
def GetConfNodeDataTypes(self, exclude = None, only_locatables = False):
return [{"name": _("%s Data Types") % confnodetypes["name"],
- "list": [datatype["name"] for datatype in confnodetypes["types"].GetCustomDataTypes(exclude, only_locatables)]}
+ for datatype in confnodetypes["types"].getdataTypes() + if not only_locatables or self.IsLocatableDataType(datatype, debug)]} for confnodetypes in self.ConfNodeTypes]
- def GetConfNodeDataType(self, typename):
- for confnodetype in self.ConfNodeTypes:
- datatype = confnodetype["types"].getdataType(typename)
- if datatype is not None:
def GetVariableLocationTree(self):
@@ -1613,7 +1593,16 @@
project = self.GetProject(debug)
- return project.GetCustomBlockType(typename, inputs)
+ blocktype = project.getpou(typename) + if blocktype is not None: + blocktype_infos = blocktype.getblockInfos() + if inputs in [None, "undefined"]: + if inputs == tuple([var_type + for name, var_type, modifier in blocktype_infos["inputs"]]): # Return Block types checking for recursion
@@ -1625,22 +1614,19 @@
if words[0] in ["P","T","A"]:
pou_type = self.GetPouType(name, debug)
- if pou_type == "function":
- for category in self.TotalTypes:
- cat = {"name" : category["name"], "list" : []}
- for block in category["list"]:
- if block["type"] == "function":
- cat["list"].append(block)
- if len(cat["list"]) > 0:
- blocktypes = [category for category in self.TotalTypes]
+ if pou_type == "function" or words[0] == "T" + else ["functionBlock", "function"]) + {"name": category["name"], + "list": [block for block in category["list"] + if block["type"] in filter]} + for category in self.TotalTypes] blocktypes.append({"name" : USER_DEFINED_POUS,
- "list": project.GetCustomBlockTypes(name,
- pou_type == "function" or words[0] == "T")})
+ "list": [pou.getblockInfos() + for pou in project.getpous(name, filter)]}) @@ -1653,11 +1639,11 @@
blocktypes.append(block["name"])
project = self.GetProject(debug)
words = tagname.split("::")
- if words[0] in ["P","T","A"]:
- blocktypes.extend(project.GetCustomFunctionBlockTypes(name))
+ blocktypes.extend([pou.getname() + for pou in project.getpous( + words[1] if words[0] in ["P","T","A"] else None, # Return Block types checking for recursion
@@ -1669,7 +1655,9 @@
blocktypes.append(blocktype["name"])
project = self.GetProject(debug)
- blocktypes.extend(project.GetCustomBlockResource())
+ for pou in project.getpous(filter=["program"])]) # Return Data Types checking for recursion
@@ -1684,7 +1672,10 @@
words = tagname.split("::")
- datatypes.extend([datatype["name"] for datatype in project.GetCustomDataTypes(name, only_locatables)])
+ for datatype in project.getdataTypes(name) + if not only_locatables or self.IsLocatableDataType(datatype, debug)]) for category in self.GetConfNodeDataTypes(name, only_locatables):
datatypes.extend(category["list"])
@@ -1759,23 +1750,26 @@
return not typename.startswith("ANY")
+ def IsLocatableDataType(self, datatype, debug = False): + basetype_content = datatype.baseType.getcontent() + basetype_content_type = basetype_content.getLocalTag() + if basetype_content_type in ["enum", "struct"]: + elif basetype_content_type == "derived": + return self.IsLocatableType(basetype_content.getname()) + elif basetype_content_name == "array": + array_base_type = basetype_content.baseType.getcontent() + if array_base_type.getLocalTag() == "derived": + return self.IsLocatableType(array_base_type.getname(), debug) def IsLocatableType(self, typename, debug = False):
- if isinstance(typename, TupleType) or self.GetBlockType(type) is not None:
+ if isinstance(typename, TupleType) or self.GetBlockType(typename) is not None: datatype = self.GetDataType(typename, debug)
- basetype_content = datatype.baseType.getcontent()
- basetype_content_type = basetype_content.getLocalTag()
- if basetype_content_type in ["enum", "struct"]:
- elif basetype_content_type == "derived":
- return self.IsLocatableType(basetype_content.getname())
- elif basetype_content_name == "array":
- array_base_type = basetype_content.baseType.getcontent()
- if array_base_type.getLocalTag() == "derived":
- return self.IsLocatableType(array_base_type.getname(), debug)
+ return self.IsLocatableDataType(datatype) def IsEnumeratedType(self, typename, debug = False):
@@ -2088,7 +2082,6 @@
datatype.initialValue.setvalue(infos["initial"])
datatype.initialValue = None
- self.Project.RefreshElementUsingTree()
#-------------------------------------------------------------------------------
@@ -2174,7 +2167,6 @@
element = self.GetEditedElement(tagname)
- self.Project.RefreshElementUsingTree()
# Return the edited element text
def GetEditedElementText(self, tagname, debug = False):
@@ -2496,7 +2488,6 @@
block.setinstanceName(blockname)
self.AddEditedElementPouVar(tagname, blocktype, blockname)
element.addinstance(block)
- self.Project.RefreshElementUsingTree()
def SetEditedElementBlockInfos(self, tagname, id, infos):
element = self.GetEditedElement(tagname)
@@ -2563,7 +2554,6 @@
variable.addconnectionPointOut()
variable.connectionPointOut.setrelPositionXY(position.x, position.y)
- self.Project.RefreshElementUsingTree()
def AddEditedElementVariable(self, tagname, id, var_type):
element = self.GetEditedElement(tagname)
@@ -3042,7 +3032,6 @@
if isinstance(instance, PLCOpenParser.GetElementClass("block", "fbdObjects")):
self.RemoveEditedElementPouVar(tagname, instance.gettypeName(), instance.getinstanceName())
element.removeinstance(id)
- self.Project.RefreshElementUsingTree()
def GetEditedResourceVariables(self, tagname, debug = False):
@@ -3155,8 +3144,6 @@
return _("Project file syntax error:\n\n") + str(e)
self.SetFilePath(filepath)
- self.Project.RefreshElementUsingTree()
- self.Project.RefreshCustomBlockTypes()
## To remove when project buffering ready
self.ProjectBufferEnabled = False
--- a/plcopen/plcopen.py Mon Sep 02 23:46:38 2013 +0200
+++ b/plcopen/plcopen.py Tue Sep 03 23:32:53 2013 +0200
@@ -241,8 +241,6 @@
cls = PLCOpenParser.GetElementClass("project")
- cls.ElementUsingTree = {}
- cls.CustomBlockTypes = OrderedDict()
self.contentHeader.setname(name)
@@ -305,10 +303,10 @@
setattr(contentheader_obj, attr, value)
setattr(cls, "setcontentHeader", setcontentHeader)
- def gettypeElement(self, element_type, name=None):
- filter = "[@name='%s']" % name if name is not None else ""
- elements = self.xpath("ppx:types/ppx:%(element_type)ss/ppx:%(element_type)s%(filter)s" % locals(),
- namespaces=PLCOpenParser.NSMAP)
+ def gettypeElement(self, element_type, name): + "ppx:types/ppx:%(element_type)ss/ppx:%(element_type)s[@name='%(name)s']" % locals(), + namespaces=PLCOpenParser.NSMAP) @@ -316,11 +314,14 @@
setattr(cls, "gettypeElement", gettypeElement)
- def getdataTypes(self):
- return self.getdataType()
+ def getdataTypes(self, exclude=None): + "ppx:types/ppx:dataTypes/ppx:dataType%s" % + ("[@name!='%s']" % exclude if exclude is not None else ""), + namespaces=PLCOpenParser.NSMAP) setattr(cls, "getdataTypes", getdataTypes)
- def getdataType(self, name=None):
+ def getdataType(self, name): return self.gettypeElement("dataType", name)
setattr(cls, "getdataType", getdataType)
@@ -336,31 +337,32 @@
def removedataType(self, name):
self.types.removedataTypeElement(name)
- self.RefreshElementUsingTree()
setattr(cls, "removedataType", removedataType)
+ def getpous(self, exclude=None, filter=None): + "ppx:types/ppx:pous/ppx:pou%s%s" % + (("[@name!='%s']" % exclude) if exclude is not None else '', + map(lambda x: "@pouType='%s'" % x, filter))) + if filter is not None else ""), + namespaces=PLCOpenParser.NSMAP) setattr(cls, "getpous", getpous)
- def getpou(self, name=None):
+ def getpou(self, name): return self.gettypeElement("pou", name)
setattr(cls, "getpou", getpou)
def appendpou(self, name, pou_type, body_type):
self.types.appendpouElement(name, pou_type, body_type)
- self.AddCustomBlockType(self.getpou(name))
setattr(cls, "appendpou", appendpou)
def insertpou(self, index, pou):
self.types.insertpouElement(index, pou)
- self.AddCustomBlockType(pou)
setattr(cls, "insertpou", insertpou)
def removepou(self, name):
self.types.removepouElement(name)
- self.RefreshCustomBlockTypes()
- self.RefreshElementUsingTree()
setattr(cls, "removepou", removepou)
def getconfigurations(self):
@@ -458,132 +460,6 @@
configuration.removeVariableByFilter(address_model)
setattr(cls, "removeVariableByFilter", removeVariableByFilter)
- # Update Block types with user-defined pou added
- def RefreshCustomBlockTypes(self):
- # Reset the tree of user-defined pou cross-use
- self.CustomBlockTypes = OrderedDict()
- for pou in self.getpous():
- self.AddCustomBlockType(pou)
- setattr(cls, "RefreshCustomBlockTypes", RefreshCustomBlockTypes)
- def AddCustomBlockType(self, pou):
- pou_name = pou.getname()
- pou_type = pou.getpouType()
- block_infos = {"name" : pou_name, "type" : pou_type, "extensible" : False,
- "inputs" : [], "outputs" : [], "comment" : pou.getdescription(),
- "generate" : generate_block, "initialise" : initialise_block}
- if pou.interface is not None:
- return_type = pou.interface.getreturnType()
- if return_type is not None:
- var_type = return_type.getcontent()
- var_type_name = var_type.getLocalTag()
- if var_type_name == "derived":
- block_infos["outputs"].append(("OUT", var_type.getname(), "none"))
- elif var_type_name in ["string", "wstring"]:
- block_infos["outputs"].append(("OUT", var_type_name.upper(), "none"))
- block_infos["outputs"].append(("OUT", var_type_name, "none"))
- for type, varlist in pou.getvars():
- for var in varlist.getvariable():
- var_type = var.type.getcontent()
- var_type_name = var_type.getLocalTag()
- if var_type_name == "derived":
- block_infos["inputs"].append((var.getname(), var_type.getname(), "none"))
- block_infos["outputs"].append((var.getname(), var_type.getname(), "none"))
- elif var_type_name in ["string", "wstring"]:
- block_infos["inputs"].append((var.getname(), var_type_name.upper(), "none"))
- block_infos["outputs"].append((var.getname(), var_type_name.upper(), "none"))
- block_infos["inputs"].append((var.getname(), var_type_name, "none"))
- block_infos["outputs"].append((var.getname(), var_type_name, "none"))
- for var in varlist.getvariable():
- var_type = var.type.getcontent()
- var_type_name = var_type.getLocalTag()
- if var_type_name == "derived":
- block_infos["inputs"].append((var.getname(), var_type.getname(), "none"))
- elif var_type_name in ["string", "wstring"]:
- block_infos["inputs"].append((var.getname(), var_type_name.upper(), "none"))
- block_infos["inputs"].append((var.getname(), var_type_name, "none"))
- for var in varlist.getvariable():
- var_type = var.type.getcontent()
- var_type_name = var_type.getLocalTag()
- if var_type_name == "derived":
- block_infos["outputs"].append((var.getname(), var_type.getname(), "none"))
- elif var_type_name in ["string", "wstring"]:
- block_infos["outputs"].append((var.getname(), var_type_name.upper(), "none"))
- block_infos["outputs"].append((var.getname(), var_type_name, "none"))
- block_infos["usage"] = "\n (%s) => (%s)" % (", ".join(["%s:%s" % (input[1], input[0]) for input in block_infos["inputs"]]),
- ", ".join(["%s:%s" % (output[1], output[0]) for output in block_infos["outputs"]]))
- self.CustomBlockTypes[pou_name]=block_infos
- setattr(cls, "AddCustomBlockType", AddCustomBlockType)
- def AddElementUsingTreeInstance(self, name, type_infos):
- typename = type_infos.getname()
- elements = self.ElementUsingTree.setdefault(typename, set())
- setattr(cls, "AddElementUsingTreeInstance", AddElementUsingTreeInstance)
- def RefreshElementUsingTree(self):
- # Reset the tree of user-defined element cross-use
- self.ElementUsingTree = {}
- # Analyze each datatype
- for datatype in self.getdataTypes():
- name = datatype.getname()
- basetype_content = datatype.baseType.getcontent()
- basetype_content_name = basetype_content.getLocalTag()
- if basetype_content_name == "derived":
- self.AddElementUsingTreeInstance(name, basetype_content)
- elif basetype_content_name in ["subrangeSigned", "subrangeUnsigned", "array"]:
- base_type = basetype_content.baseType.getcontent()
- if base_type.getLocalTag() == "derived":
- self.AddElementUsingTreeInstance(name, base_type)
- elif basetype_content_name == "struct":
- for element in basetype_content.getvariable():
- type_content = element.type.getcontent()
- if type_content.getLocalTag() == "derived":
- self.AddElementUsingTreeInstance(name, type_content)
- for pou in self.getpous():
- if pou.interface is not None:
- # Extract variables from every varLists
- for varlist_type, varlist in pou.getvars():
- for var in varlist.getvariable():
- vartype_content = var.gettype().getcontent()
- if vartype_content.getLocalTag() == "derived":
- self.AddElementUsingTreeInstance(name, vartype_content)
- setattr(cls, "RefreshElementUsingTree", RefreshElementUsingTree)
- # Return if pou given by name is used by another pou
- def ElementIsUsed(self, name):
- elements = self.ElementUsingTree.get(name, None)
- return elements is not None
- setattr(cls, "ElementIsUsed", ElementIsUsed)
- # Return if pou given by name is directly or undirectly used by the reference pou
- def ElementIsUsedBy(self, name, reference):
- elements = self.ElementUsingTree.get(name, set())
- # Test if pou is directly used by reference
- if reference in elements:
- # Test if pou is undirectly used by reference, by testing if pous
- # that directly use pou is directly or undirectly used by reference
- selffn = self.ElementIsUsedBy
- for element in elements:
- if selffn(element, reference):
- setattr(cls, "ElementIsUsedBy", ElementIsUsedBy)
def GetEnumeratedDataTypeValues(self):
@@ -592,60 +468,6 @@
namespaces=PLCOpenParser.NSMAP)]
setattr(cls, "GetEnumeratedDataTypeValues", GetEnumeratedDataTypeValues)
- # Function that returns the block definition associated to the block type given
- def GetCustomBlockType(self, typename, inputs = None):
- customblocktype = self.CustomBlockTypes.get(typename,None)
- if customblocktype is not None:
- if inputs is not None and inputs != "undefined":
- customblock_inputs = tuple([var_type for name, var_type, modifier in customblocktype["inputs"]])
- if inputs == customblock_inputs:
- setattr(cls, "GetCustomBlockType", GetCustomBlockType)
- # Return Block types checking for recursion
- def GetCustomBlockTypes(self, exclude = None, onlyfunctions = False):
- if exclude is not None:
- return [customblocktype for name,customblocktype in self.CustomBlockTypes.iteritems()
- if (customblocktype["type"] != "program"
- and not self.ElementIsUsedBy(exclude, name)
- and not (onlyfunctions and customblocktype["type"] != "function"))]
- return [customblocktype for customblocktype in self.CustomBlockTypes.itervalues()
- if (customblocktype["type"] != "program"
- and not (onlyfunctions and customblocktype["type"] != "function"))]
- setattr(cls, "GetCustomBlockTypes", GetCustomBlockTypes)
- # Return Function Block types checking for recursion
- def GetCustomFunctionBlockTypes(self, exclude = None):
- if exclude is not None:
- return [name for name,customblocktype in self.CustomBlockTypes.iteritems()
- if (customblocktype["type"] == "functionBlock"
- and not self.ElementIsUsedBy(exclude, name))]
- return [name for customblocktype in self.CustomBlockTypes.itervalues()
- if customblocktype["type"] == "functionBlock"]
- setattr(cls, "GetCustomFunctionBlockTypes", GetCustomFunctionBlockTypes)
- # Return Block types checking for recursion
- def GetCustomBlockResource(self):
- return [customblocktype["name"] for customblocktype in self.CustomBlockTypes.itervalues()
- if customblocktype["type"] == "program"]
- setattr(cls, "GetCustomBlockResource", GetCustomBlockResource)
- # Return Data Types checking for recursion
- def GetCustomDataTypes(self, exclude = "", only_locatable = False):
- for customdatatype in self.getdataTypes():
- if not only_locatable or self.IsLocatableType(customdatatype):
- customdatatype_name = customdatatype.getname()
- if customdatatype_name != exclude and not self.ElementIsUsedBy(exclude, customdatatype_name):
- customdatatypes.append({"name": customdatatype_name, "infos": customdatatype})
- setattr(cls, "GetCustomDataTypes", GetCustomDataTypes)
def Search(self, criteria, parent_infos=[]):
result = self.types.Search(criteria, parent_infos)
for configuration in self.instances.configurations.getconfiguration():
@@ -1168,9 +990,50 @@
setattr(cls, "Search", Search)
+def _getvariableTypeinfos(variable_type): + type_content = variable_type.getcontent() + type_content_type = type_content.getLocalTag() + if type_content_type == "derived": + return type_content.getname() + return type_content_type.upper() cls = PLCOpenParser.GetElementClass("pou", "pous")
+ def getblockInfos(self): + "name" : self.getname(), + "type" : self.getpouType(), + "comment" : self.getdescription(), + "generate" : generate_block, + "initialise" : initialise_block} + if self.interface is not None: + return_type = self.interface.getreturnType() + if return_type is not None: + block_infos["outputs"].append( + ("OUT", _getvariableTypeinfos(return_type), "none")) + "ppx:interface/*[self::ppx:inputVars or self::ppx:inOutVars]/ppx:variable", + namespaces=PLCOpenParser.NSMAP): + block_infos["inputs"].append( + (var.getname(), _getvariableTypeinfos(var.type), "none")) + "ppx:interface/*[self::ppx:outputVars or self::ppx:inOutVars]/ppx:variable", + namespaces=PLCOpenParser.NSMAP): + block_infos["outputs"].append( + (var.getname(), _getvariableTypeinfos(var.type), "none")) + block_infos["usage"] = ("\n (%s) => (%s)" % + (", ".join(["%s:%s" % (input[1], input[0]) + for input in block_infos["inputs"]]), + ", ".join(["%s:%s" % (output[1], output[0]) + for output in block_infos["outputs"]]))) + setattr(cls, "getblockInfos", getblockInfos) def setdescription(self, description):
doc = self.getdocumentation()
@@ -2333,7 +2196,7 @@
def getBoundingBox(self):
bbox = _getBoundingBoxSingle(self)
condition_connection = self.getconditionConnection()
- if condition_connection:
+ if condition_connection is not None: bbox.union(_getConnectionsBoundingBox(condition_connection))
setattr(cls, "getBoundingBox", getBoundingBox)