--- a/plcopen/plcopen.py Fri Jul 18 15:44:37 2008 +0200
+++ b/plcopen/plcopen.py Tue Aug 12 16:28:55 2008 +0200
@@ -23,6 +23,7 @@
#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
from xmlclass import *
+from structures import *
from types import *
import os, re
@@ -63,6 +64,11 @@
cls = PLCOpenClasses.get("project", None)
if cls:
cls.singleLineAttributes = False
+ cls.EnumeratedDataTypeValues = {}
+ cls.CustomDataTypeRange = {}
+ cls.CustomTypeHierarchy = {}
+ cls.ElementUsingTree = {}
+ cls.CustomBlockTypes = []
def setname(self, name):
self.contentHeader.setname(name)
@@ -143,15 +149,21 @@
setattr(cls, "getdataType", getdataType)
def appenddataType(self, name):
+ if name in self.CustomTypeHierarchy:
+ raise ValueError, "\"%s\" Data Type already exists !!!"%name
self.types.appenddataTypeElement(name)
+ self.AddCustomDataType(self.getdataType(name))
setattr(cls, "appenddataType", appenddataType)
def insertdataType(self, index, datatype):
self.types.insertdataTypeElement(index, datatype)
+ self.AddCustomDataType(datatype)
setattr(cls, "insertdataType", insertdataType)
def removedataType(self, name):
self.types.removedataTypeElement(name)
+ self.RefreshDataTypeHierarchy()
+ self.RefreshElementUsingTree()
setattr(cls, "removedataType", removedataType)
def getpous(self):
@@ -164,14 +176,18 @@
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):
@@ -248,6 +264,275 @@
configuration.updateElementName(old_name, new_name)
setattr(cls, "updateElementName", updateElementName)
+ def RefreshDataTypeHierarchy(self):
+ self.EnumeratedDataTypeValues = {}
+ self.CustomDataTypeRange = {}
+ self.CustomTypeHierarchy = {}
+ for datatype in self.getdataTypes():
+ self.AddCustomDataType(datatype)
+ setattr(cls, "RefreshDataTypeHierarchy", RefreshDataTypeHierarchy)
+
+ def AddCustomDataType(self, datatype):
+ name = datatype.getname()
+ basetype_content = datatype.getbaseType().getcontent()
+ if basetype_content["value"] is None:
+ self.CustomTypeHierarchy[name] = basetype_content["name"]
+ elif basetype_content["name"] in ["string", "wstring"]:
+ self.CustomTypeHierarchy[name] = basetype_content["name"].upper()
+ elif basetype_content["name"] == "derived":
+ self.CustomTypeHierarchy[name] = basetype_content["value"].getname()
+ elif basetype_content["name"] in ["subrangeSigned", "subrangeUnsigned"]:
+ range = (basetype_content["value"].range.getlower(),
+ basetype_content["value"].range.getupper())
+ self.CustomDataTypeRange[name] = range
+ base_type = basetype_content["value"].baseType.getcontent()
+ if base_type["value"] is None:
+ self.CustomTypeHierarchy[name] = base_type["name"]
+ else:
+ self.CustomTypeHierarchy[name] = base_type["value"].getname()
+ else:
+ if basetype_content["name"] == "enum":
+ values = []
+ for value in basetype_content["value"].values.getvalue():
+ values.append(value.getname())
+ self.EnumeratedDataTypeValues[name] = values
+ self.CustomTypeHierarchy[name] = "ANY_DERIVED"
+ setattr(cls, "AddCustomDataType", AddCustomDataType)
+
+ # Update Block types with user-defined pou added
+ def RefreshCustomBlockTypes(self):
+ # Reset the tree of user-defined pou cross-use
+ self.CustomBlockTypes = []
+ for pou in self.getpous():
+ self.AddCustomBlockType(pou)
+ setattr(cls, "RefreshCustomBlockTypes", RefreshCustomBlockTypes)
+
+ def AddCustomBlockType(self, pou):
+ pou_name = pou.getname()
+ pou_type = pou.getpouType()
+ if pou_type != "program":
+ block_infos = {"name" : pou_name, "type" : pou_type, "extensible" : False,
+ "inputs" : [], "outputs" : [], "comment" : "",
+ "generate" : generate_block, "initialise" : initialise_block }
+ if pou.getinterface():
+ for type, varlist in pou.getvars():
+ if type == "InOut":
+ for var in varlist.getvariable():
+ var_type = var.type.getcontent()
+ if var_type["name"] == "derived":
+ block_infos["inputs"].append((var.getname(), var_type["value"].getname(), "none"))
+ block_infos["outputs"].append((var.getname(), var_type["value"].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"))
+ else:
+ block_infos["inputs"].append((var.getname(), var_type["name"], "none"))
+ block_infos["outputs"].append((var.getname(), var_type["name"], "none"))
+ elif type == "Input":
+ for var in varlist.getvariable():
+ var_type = var.type.getcontent()
+ if var_type["name"] == "derived":
+ block_infos["inputs"].append((var.getname(), var_type["value"].getname(), "none"))
+ elif var_type["name"] in ["string", "wstring"]:
+ block_infos["inputs"].append((var.getname(), var_type["name"].upper(), "none"))
+ else:
+ block_infos["inputs"].append((var.getname(), var_type["name"], "none"))
+ elif type == "Output":
+ for var in varlist.getvariable():
+ var_type = var.type.getcontent()
+ if var_type["name"] == "derived":
+ block_infos["outputs"].append((var.getname(), var_type["value"].getname(), "none"))
+ elif var_type["name"] in ["string", "wstring"]:
+ block_infos["outputs"].append((var.getname(), var_type["name"].upper(), "none"))
+ else:
+ block_infos["outputs"].append((var.getname(), var_type["name"], "none"))
+ return_type = pou.interface.getreturnType()
+ if return_type:
+ var_type = return_type.getcontent()
+ if var_type["name"] == "derived":
+ block_infos["outputs"].append(("", var_type["value"].getname(), "none"))
+ elif var_type["name"] in ["string", "wstring"]:
+ block_infos["outputs"].append(("", var_type["name"].upper(), "none"))
+ else:
+ block_infos["outputs"].append(("", var_type["name"], "none"))
+ if pou.getbodyType() in ["FBD","LD","SFC"]:
+ for instance in pou.getinstances():
+ if isinstance(instance, PLCOpenClasses.get("commonObjects_comment", None)):
+ block_infos["comment"] = instance.getcontentText()
+ self.CustomBlockTypes.append(block_infos)
+ setattr(cls, "AddCustomBlockType", AddCustomBlockType)
+
+ def RefreshElementUsingTree(self):
+ # Reset the tree of user-defined element cross-use
+ self.ElementUsingTree = {}
+ pous = self.getpous()
+ # Reference all the user-defined elementu names and initialize the tree of
+ # user-defined elemnt cross-use
+ pounames = [pou.getname() for pou in pous]
+ for name in pounames:
+ self.ElementUsingTree[name] = []
+ # Analyze each pou
+ for pou in pous:
+ name = pou.getname()
+ if pou.interface:
+ # Extract variables from every varLists
+ for type, varlist in pou.getvars():
+ for var in varlist.getvariable():
+ vartype_content = var.gettype().getcontent()
+ if vartype_content["name"] == "derived":
+ typename = vartype_content["value"].getname()
+ if typename in pounames and name not in self.ElementUsingTree[typename]:
+ self.ElementUsingTree[typename].append(name)
+ setattr(cls, "RefreshElementUsingTree", RefreshElementUsingTree)
+
+ def GetParentType(self, type):
+ if type in self.CustomTypeHierarchy:
+ return self.CustomTypeHierarchy[type]
+ elif type in TypeHierarchy:
+ return TypeHierarchy[type]
+ return None
+ setattr(cls, "GetParentType", GetParentType)
+
+ def GetBaseType(self, type):
+ parent_type = self.GetParentType(type)
+ if parent_type is not None:
+ if parent_type.startswith("ANY"):
+ return type
+ else:
+ return self.GetBaseType(parent_type)
+ return None
+ setattr(cls, "GetBaseType", GetBaseType)
+
+ def GetSubrangeBaseTypes(self, exclude):
+ derived = []
+ for type in self.CustomTypeHierarchy.keys():
+ for base_type in DataTypeRange.keys():
+ if self.IsOfType(type, base_type) and not self.IsOfType(type, exclude):
+ derived.append(type)
+ break
+ return DataTypeRange.keys() + derived
+ setattr(cls, "GetSubrangeBaseTypes", GetSubrangeBaseTypes)
+
+ """
+ returns true if the given data type is the same that "reference" meta-type or one of its types.
+ """
+ def IsOfType(self, type, reference):
+ if reference is None:
+ return True
+ elif type == reference:
+ return True
+ else:
+ parent_type = self.GetParentType(type)
+ if parent_type is not None:
+ return self.IsOfType(parent_type, reference)
+ return False
+ setattr(cls, "IsOfType", IsOfType)
+
+ # Return if pou given by name is used by another pou
+ def ElementIsUsed(self, name):
+ if name in self.ElementUsingTree:
+ return len(self.ElementUsingTree[name]) > 0
+ return False
+ setattr(cls, "ElementIsUsed", ElementIsUsed)
+
+ def DataTypeIsDerived(self, name):
+ return name in self.CustomTypeHierarchy.values()
+ setattr(cls, "DataTypeIsDerived", DataTypeIsDerived)
+
+ # Return if pou given by name is directly or undirectly used by the reference pou
+ def ElementIsUsedBy(self, name, reference):
+ if name in self.ElementUsingTree:
+ list = self.ElementUsingTree[name]
+ # Test if pou is directly used by reference
+ if reference in list:
+ return True
+ else:
+ # Test if pou is undirectly used by reference, by testing if pous
+ # that directly use pou is directly or undirectly used by reference
+ used = False
+ for element in list:
+ used |= self.ElementIsUsedBy(element, reference)
+ return used
+ return False
+ setattr(cls, "ElementIsUsedBy", ElementIsUsedBy)
+
+ def GetDataTypeRange(self, type):
+ if type in self.CustomDataTypeRange:
+ return self.CustomDataTypeRange[type]
+ elif type in DataTypeRange:
+ return DataTypeRange[type]
+ else:
+ parent_type = self.GetParentType(type)
+ if parent_type is not None:
+ return self.GetDataTypeRange(parent_type)
+ return None
+ setattr(cls, "GetDataTypeRange", GetDataTypeRange)
+
+ def GetEnumeratedDataTypeValues(self, type = None):
+ if type is None:
+ all_values = []
+ for values in self.EnumeratedDataTypeValues.values():
+ all_values.extend(values)
+ return all_values
+ elif type in self.EnumeratedDataTypeValues:
+ return self.EnumeratedDataTypeValues(type)
+ return []
+ setattr(cls, "GetEnumeratedDataTypeValues", GetEnumeratedDataTypeValues)
+
+ # Function that returns the block definition associated to the block type given
+ def GetCustomBlockType(self, type, inputs = None):
+ for customblocktype in self.CustomBlockTypes:
+ if inputs:
+ customblock_inputs = tuple([var_type for name, var_type, modifier in customblocktype["inputs"]])
+ same_inputs = inputs == customblock_inputs
+ else:
+ same_inputs = True
+ if customblocktype["name"] == type and same_inputs:
+ return customblocktype
+ return None
+ setattr(cls, "GetCustomBlockType", GetCustomBlockType)
+
+ # Return Block types checking for recursion
+ def GetCustomBlockTypes(self, exclude = ""):
+ pou = self.getpou(exclude)
+ type = pou.getpouType()
+ customblocktypes = []
+ for customblocktype in self.CustomBlockTypes:
+ if customblocktype["name"] != exclude and not self.ElementIsUsedBy(exclude, customblocktype["name"]) and not (type == "function" and customblocktype["type"] != "function"):
+ customblocktypes.append(customblocktype)
+ return customblocktypes
+ setattr(cls, "GetCustomBlockTypes", GetCustomBlockTypes)
+
+ # Return Function Block types checking for recursion
+ def GetCustomFunctionBlockTypes(self, exclude = ""):
+ pou = self.getpou(exclude)
+ type = pou.getpouType()
+ customblocktypes = []
+ for customblocktype in self.CustomBlockTypes:
+ if customblocktype["name"] != exclude and not self.ElementIsUsedBy(exclude, customblocktype["name"]) and not (type == "function" and customblocktype["type"] != "function"):
+ customblocktypes.appendcustom(customblocktype["name"])
+ return customblocktypes
+ setattr(cls, "GetCustomFunctionBlockTypes", GetCustomFunctionBlockTypes)
+
+ # Return Block types checking for recursion
+ def GetCustomBlockResource(self):
+ customblocktypes = []
+ for customblocktype in self.CustomBlockTypes:
+ if customblocktype["type"] == "program":
+ customblocktypes.append(customblocktype["name"])
+ return customblocktypes
+ setattr(cls, "GetCustomBlockResource", GetCustomBlockResource)
+
+ # Return Data Types checking for recursion
+ def GetCustomDataTypes(self, exclude = ""):
+ customdatatypes = []
+ for customdatatype in self.getdataTypes():
+ customdatatype_name = customdatatype.getname()
+ if customdatatype_name != exclude and not self.ElementIsUsedBy(exclude, customdatatype_name):
+ customdatatypes.append(customdatatype_name)
+ return customdatatypes
+ setattr(cls, "GetCustomDataTypes", GetCustomDataTypes)
+
cls = PLCOpenClasses.get("project_fileHeader", None)
if cls:
cls.singleLineAttributes = False
@@ -365,15 +650,12 @@
setattr(cls, "getdataTypeElement", getdataTypeElement)
def appenddataTypeElement(self, name):
- for element in self.dataTypes.getdataType():
- if element.getname() == name:
- raise ValueError, "\"%s\" Data Type already exists !!!"%name
new_datatype = PLCOpenClasses["dataTypes_dataType"]()
new_datatype.setname(name)
new_datatype.baseType.setcontent({"name" : "BOOL", "value" : None})
self.dataTypes.appenddataType(new_datatype)
setattr(cls, "appenddataTypeElement", appenddataTypeElement)
-
+
def insertdataTypeElement(self, index, dataType):
self.dataTypes.insertdataType(index, dataType)
setattr(cls, "insertdataTypeElement", insertdataTypeElement)