plcopen/plcopen.py
changeset 1334 b0c2c4e1c1f1
parent 1331 38c5de794e62
child 1338 c1e6c712cc35
equal deleted inserted replaced
1332:ac7d39f4e376 1334:b0c2c4e1c1f1
   156   <body>
   156   <body>
   157     <%(body_type)s>%%s</%(body_type)s>
   157     <%(body_type)s>%%s</%(body_type)s>
   158   </body>
   158   </body>
   159 </pou>""" % locals()
   159 </pou>""" % locals()
   160 
   160 
       
   161 PLCOpen_v1_file = open(os.path.join(os.path.split(__file__)[0], "TC6_XML_V10_B.xsd"))
       
   162 PLCOpen_v1_xml = PLCOpen_v1_file.read()
       
   163 PLCOpen_v1_file.close()
       
   164 PLCOpen_v1_xml = PLCOpen_v1_xml.replace(
       
   165         "http://www.plcopen.org/xml/tc6.xsd", 
       
   166         "http://www.plcopen.org/xml/tc6_0201") 
       
   167 PLCOpen_v1_xsd = etree.XMLSchema(etree.fromstring(PLCOpen_v1_xml))
       
   168 
       
   169 # XPath for file compatibility process
       
   170 ProjectResourcesXPath = PLCOpen_XPath("ppx:instances/ppx:configurations/ppx:configuration/ppx:resource")
       
   171 ResourceInstancesXpath = PLCOpen_XPath("ppx:pouInstance | ppx:task/ppx:pouInstance")
       
   172 TransitionsConditionXPath = PLCOpen_XPath("ppx:types/ppx:pous/ppx:pou/ppx:body/*/ppx:transition/ppx:condition")
       
   173 ConditionConnectionsXPath = PLCOpen_XPath("ppx:connection")
       
   174 ActionBlocksXPath = PLCOpen_XPath("ppx:types/ppx:pous/ppx:pou/ppx:body/*/ppx:actionBlock")
       
   175 ActionBlocksConnectionPointOutXPath = PLCOpen_XPath("ppx:connectionPointOut")
       
   176 
   161 def LoadProjectXML(project_xml):
   177 def LoadProjectXML(project_xml):
   162     project_xml = project_xml.replace(
   178     project_xml = project_xml.replace(
   163         "http://www.plcopen.org/xml/tc6.xsd", 
   179         "http://www.plcopen.org/xml/tc6.xsd", 
   164         "http://www.plcopen.org/xml/tc6_0201")
   180         "http://www.plcopen.org/xml/tc6_0201")
   165     for cre, repl in [
   181     for cre, repl in [
   167         (re.compile("(?:]]>)(?!</xhtml:p>)"), "]]></xhtml:p>")]:
   183         (re.compile("(?:]]>)(?!</xhtml:p>)"), "]]></xhtml:p>")]:
   168         project_xml = cre.sub(repl, project_xml)
   184         project_xml = cre.sub(repl, project_xml)
   169     
   185     
   170     try:
   186     try:
   171         tree, error = PLCOpenParser.LoadXMLString(project_xml)
   187         tree, error = PLCOpenParser.LoadXMLString(project_xml)
   172         if error is not None:
   188         if error is None:
   173             # TODO Validate file according to PLCOpen v1 and modify it for
   189             return tree, None
   174             # compatibility with PLCOpen v2
   190         
   175             return tree, error
   191         if PLCOpen_v1_xsd.validate(tree):
   176         return tree, None
   192             # Make file compatible with PLCOpen v2
       
   193             
       
   194             # Update resource interval value
       
   195             for resource in ProjectResourcesXPath(tree):
       
   196                 for task in resource.gettask():
       
   197                     interval = task.get("interval")
       
   198                     if interval is not None:
       
   199                         result = time_model.match(interval)
       
   200                         if result is not None:
       
   201                             values = result.groups()
       
   202                             time_values = [int(v) for v in values[:2]]
       
   203                             seconds = float(values[2])
       
   204                             time_values.extend([int(seconds), int((seconds % 1) * 1000000)])
       
   205                             text = "T#"
       
   206                             if time_values[0] != 0:
       
   207                                 text += "%dh"%time_values[0]
       
   208                             if time_values[1] != 0:
       
   209                                 text += "%dm"%time_values[1]
       
   210                             if time_values[2] != 0:
       
   211                                 text += "%ds"%time_values[2]
       
   212                             if time_values[3] != 0:
       
   213                                 if time_values[3] % 1000 != 0:
       
   214                                     text += "%.3fms"%(float(time_values[3]) / 1000)
       
   215                                 else:
       
   216                                     text += "%dms"%(time_values[3] / 1000)
       
   217                             task.set("interval", text)
       
   218                 
       
   219                 # Update resources pou instance attributes
       
   220                 for pouInstance in ResourceInstancesXpath(resource):
       
   221                     type_name = pouInstance.get("type")
       
   222                     if type_name is not None:
       
   223                         pouInstance.set("typeName", type_name)
       
   224             
       
   225             # Update transitions condition
       
   226             for transition_condition in TransitionsConditionXPath(tree):
       
   227                 connections = ConditionConnectionsXPath(transition_condition)
       
   228                 if len(connections) > 0:
       
   229                     connectionPointIn = PLCOpenParser.CreateElement("connectionPointIn", "condition")
       
   230                     transition_condition.setcontent(connectionPointIn)
       
   231                     connectionPointIn.setrelPositionXY(0, 0)
       
   232                     for connection in connections:
       
   233                         connectionPointIn.append(connection)
       
   234             
       
   235             # Update actionBlocks
       
   236             for actionBlock in ActionBlocksXPath(tree):
       
   237                 for connectionPointOut in ActionBlocksConnectionPointOutXPath(actionBlock):
       
   238                     actionBlock.remove(connectionPointOut)
       
   239                     
       
   240                 for action in actionBlock.getaction():
       
   241                     action.set("localId", "0")
       
   242                     relPosition = PLCOpenParser.CreateElement("relPosition", "action")
       
   243                     relPosition.set("x", "0")
       
   244                     relPosition.set("y", "0")
       
   245                     action.setrelPosition(relPosition)
       
   246             
       
   247             return tree, None
       
   248         
       
   249         return tree, error
       
   250     
   177     except Exception, e:
   251     except Exception, e:
   178         return None, e.message
   252         return None, e.message
   179 
   253 
   180 def LoadProject(filepath):
   254 def LoadProject(filepath):
   181     project_file = open(filepath)
   255     project_file = open(filepath)
   691         return search_result
   765         return search_result
   692     setattr(cls, "Search", Search)
   766     setattr(cls, "Search", Search)
   693 
   767 
   694 cls = PLCOpenParser.GetElementClass("task", "resource")
   768 cls = PLCOpenParser.GetElementClass("task", "resource")
   695 if cls:
   769 if cls:
   696     def compatibility(self, tree):
       
   697         if tree.hasAttribute("interval"):
       
   698             interval = GetAttributeValue(tree._attrs["interval"])
       
   699             result = time_model.match(interval)
       
   700             if result is not None:
       
   701                 values = result.groups()
       
   702                 time_values = [int(v) for v in values[:2]]
       
   703                 seconds = float(values[2])
       
   704                 time_values.extend([int(seconds), int((seconds % 1) * 1000000)])
       
   705                 text = "t#"
       
   706                 if time_values[0] != 0:
       
   707                     text += "%dh"%time_values[0]
       
   708                 if time_values[1] != 0:
       
   709                     text += "%dm"%time_values[1]
       
   710                 if time_values[2] != 0:
       
   711                     text += "%ds"%time_values[2]
       
   712                 if time_values[3] != 0:
       
   713                     if time_values[3] % 1000 != 0:
       
   714                         text += "%.3fms"%(float(time_values[3]) / 1000)
       
   715                     else:
       
   716                         text += "%dms"%(time_values[3] / 1000)
       
   717                 NodeSetAttr(tree, "interval", text)
       
   718     setattr(cls, "compatibility", compatibility)
       
   719     
       
   720     def updateElementName(self, old_name, new_name):
   770     def updateElementName(self, old_name, new_name):
   721         if self.single == old_name:
   771         if self.single == old_name:
   722             self.single = new_name
   772             self.single = new_name
   723         if self.interval == old_name:
   773         if self.interval == old_name:
   724             self.interval = new_name
   774             self.interval = new_name
   740                        criteria, parent_infos)
   790                        criteria, parent_infos)
   741     setattr(cls, "Search", Search)
   791     setattr(cls, "Search", Search)
   742 
   792 
   743 cls = PLCOpenParser.GetElementClass("pouInstance")
   793 cls = PLCOpenParser.GetElementClass("pouInstance")
   744 if cls:
   794 if cls:
   745     def compatibility(self, tree):
       
   746         if tree.hasAttribute("type"):
       
   747             NodeRenameAttr(tree, "type", "typeName")
       
   748     setattr(cls, "compatibility", compatibility)
       
   749     
       
   750     def updateElementName(self, old_name, new_name):
   795     def updateElementName(self, old_name, new_name):
   751         if self.typeName == old_name:
   796         if self.typeName == old_name:
   752             self.typeName = new_name
   797             self.typeName = new_name
   753     setattr(cls, "updateElementName", updateElementName)
   798     setattr(cls, "updateElementName", updateElementName)
   754 
   799 
  2100 
  2145 
  2101     def Search(self, criteria, parent_infos=[]):
  2146     def Search(self, criteria, parent_infos=[]):
  2102         return _Search([("name", self.getname())], criteria, parent_infos + ["step", self.getlocalId()])
  2147         return _Search([("name", self.getname())], criteria, parent_infos + ["step", self.getlocalId()])
  2103     setattr(cls, "Search", Search)
  2148     setattr(cls, "Search", Search)
  2104 
  2149 
  2105 cls = PLCOpenParser.GetElementClass("condition", "transition")
       
  2106 if cls:
       
  2107     def compatibility(self, tree):
       
  2108         connections = []
       
  2109         for child in tree.childNodes:
       
  2110             if child.nodeName == "connection":
       
  2111                 connections.append(child)
       
  2112         if len(connections) > 0:
       
  2113             node = CreateNode("connectionPointIn")
       
  2114             relPosition = CreateNode("relPosition")
       
  2115             NodeSetAttr(relPosition, "x", "0")
       
  2116             NodeSetAttr(relPosition, "y", "0")
       
  2117             node.childNodes.append(relPosition)
       
  2118             node.childNodes.extend(connections)
       
  2119             tree.childNodes = [node]
       
  2120     setattr(cls, "compatibility", compatibility)
       
  2121 
       
  2122 cls = _initElementClass("transition", "sfcObjects")
  2150 cls = _initElementClass("transition", "sfcObjects")
  2123 if cls:
  2151 if cls:
  2124     def getinfos(self):
  2152     def getinfos(self):
  2125         infos = _getelementinfos(self)
  2153         infos = _getelementinfos(self)
  2126         infos["type"] = "transition"
  2154         infos["type"] = "transition"
  2280         return _Search([("target", self.gettargetName())], criteria, parent_infos + ["jump", self.getlocalId()])
  2308         return _Search([("target", self.gettargetName())], criteria, parent_infos + ["jump", self.getlocalId()])
  2281     setattr(cls, "Search", Search)
  2309     setattr(cls, "Search", Search)
  2282 
  2310 
  2283 cls = PLCOpenParser.GetElementClass("action", "actionBlock")
  2311 cls = PLCOpenParser.GetElementClass("action", "actionBlock")
  2284 if cls:
  2312 if cls:
  2285     def compatibility(self, tree):
       
  2286         relPosition = reduce(lambda x, y: x | (y.nodeName == "relPosition"), tree.childNodes, False)
       
  2287         if not tree.hasAttribute("localId"):
       
  2288             NodeSetAttr(tree, "localId", "0")
       
  2289         if not relPosition:
       
  2290             node = CreateNode("relPosition")
       
  2291             NodeSetAttr(node, "x", "0")
       
  2292             NodeSetAttr(node, "y", "0")
       
  2293             tree.childNodes.insert(0, node)
       
  2294     setattr(cls, "compatibility", compatibility)
       
  2295     
       
  2296     def setreferenceName(self, name):
  2313     def setreferenceName(self, name):
  2297         if self.reference is not None:
  2314         if self.reference is not None:
  2298             self.reference.setname(name)
  2315             self.reference.setname(name)
  2299     setattr(cls, "setreferenceName", setreferenceName)
  2316     setattr(cls, "setreferenceName", setreferenceName)
  2300     
  2317     
  2342                        criteria, parent_infos)
  2359                        criteria, parent_infos)
  2343     setattr(cls, "Search", Search)
  2360     setattr(cls, "Search", Search)
  2344 
  2361 
  2345 cls = _initElementClass("actionBlock", "commonObjects", "single")
  2362 cls = _initElementClass("actionBlock", "commonObjects", "single")
  2346 if cls:
  2363 if cls:
  2347     def compatibility(self, tree):
       
  2348         for child in tree.childNodes[:]:
       
  2349             if child.nodeName == "connectionPointOut":
       
  2350                 tree.childNodes.remove(child)
       
  2351     setattr(cls, "compatibility", compatibility)
       
  2352     
       
  2353     def getinfos(self):
  2364     def getinfos(self):
  2354         infos = _getelementinfos(self)
  2365         infos = _getelementinfos(self)
  2355         infos["type"] = "actionBlock"
  2366         infos["type"] = "actionBlock"
  2356         infos["specific_values"]["actions"] = self.getactions()
  2367         infos["specific_values"]["actions"] = self.getactions()
  2357         infos["inputs"].append(_getconnectioninfos(self, self.connectionPointIn, True))
  2368         infos["inputs"].append(_getconnectioninfos(self, self.connectionPointIn, True))