--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/PLCGenerator.py Wed Jan 31 16:31:39 2007 +0100
@@ -0,0 +1,422 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+#This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor
+#based on the plcopen standard.
+#
+#Copyright (C): Edouard TISSERANT and Laurent BESSARD
+#
+#See COPYING file for copyrights details.
+#
+#This library is free software; you can redistribute it and/or
+#modify it under the terms of the GNU Lesser General Public
+#License as published by the Free Software Foundation; either
+#version 2.1 of the License, or (at your option) any later version.
+#
+#This library is distributed in the hope that it will be useful,
+#but WITHOUT ANY WARRANTY; without even the implied warranty of
+#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+#Lesser General Public License for more details.
+#
+#You should have received a copy of the GNU Lesser General Public
+#License along with this library; if not, write to the Free Software
+#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+from plcopen import plcopen
+from plcopen.structures import *
+from types import *
+
+varTypeNames = {"localVars" : "VAR", "tempVars" : "VAR_TEMP", "inputVars" : "VAR_INPUT",
+ "outputVars" : "VAR_OUTPUT", "inOutVars" : "VAR_IN_OUT", "externalVars" : "VAR_EXTERNAL",
+ "globalVars" : "VAR_GLOBAL", "accessVars" : "VAR_ACCESS"}
+"""
+Module implementing methods for generating PLC programs in ST or IL
+"""
+
+class PouProgram:
+
+ def __init__(self, name, type):
+ self.Name = name
+ self.Type = type
+ self.Interface = {}
+ self.Steps = {}
+ self.Transitions = {}
+ self.Order = []
+ self.Program = ""
+
+ def GenerateInterface(self, interface):
+ if self.Type == "FUNCTION":
+ self.Interface["returnType"] = interface.getReturnType().getValue()
+ for varlist in interface.getContent():
+ variables = {}
+ for var in varlist["value"].getVariable():
+ type = var.getType().getValue()
+ if type not in variables:
+ variables[type] = []
+ variables[type].append(var.getName())
+ self.Interface[(varTypeNames[varlist["name"]], varlist["value"].getRetain(),
+ varlist["value"].getConstant())] = variables
+
+ def GenerateProgram(self, pou):
+ body = pou.getBody()
+ body_content = body.getContent()
+ body_type = body_content["name"]
+ if body_type in ["IL","ST"]:
+ self.Program = "%s\n"%body_content["value"].getText()
+ elif body_type == "FBD":
+ for instance in body.getContentInstances():
+ if isinstance(instance, plcopen.outVariable):
+ var = instance.getExpression()
+ connections = instance.connectionPointIn.getConnections()
+ if connections and len(connections) == 1:
+ expression = self.ComputeFBDExpression(body, connections[0])
+ self.Program += " %s := %s;\n"%(var, expression)
+ elif body_type == "LD":
+ for instance in body.getContentInstances():
+ if isinstance(instance, plcopen.coil):
+ paths = self.GenerateLDPaths(instance, body)
+ variable = self.ExtractModifier(instance, instance.getVariable())
+ expression = self.ComputeLDExpression(paths, True)
+ self.Program += " %s := %s;\n"%(variable, expression)
+ elif body_type == "SFC":
+ for instance in body.getContentInstances():
+ if isinstance(instance, plcopen.step):
+ self.GenerateSFCSteps(instance, pou)
+ elif isinstance(instance, plcopen.actionBlock):
+ self.GenerateSFCActions(instance, pou)
+ elif isinstance(instance, plcopen.transition):
+ self.GenerateSFCTransitions(instance, pou)
+ elif isinstance(instance, plcopen.jumpStep):
+ self.GenerateSFCJump(instance, pou)
+ for name, values in self.Steps.items():
+ if values['initial']:
+ self.GenerateSFCStepOrder(name, [])
+ steps_type = "ARRAY [1..%d] OF BOOL"%len(self.Order)
+ if ("VAR", False, False) not in self.Interface:
+ self.Interface[("VAR", False, False)] = {}
+ if steps_type not in self.Interface[("VAR", False, False)]:
+ self.Interface[("VAR", False, False)][steps_type] = ["Steps"]
+ else:
+ self.Interface[("VAR", False, False)][steps_type].append("Steps")
+ for index, name in enumerate(self.Order):
+ values = self.Steps[name]
+ self.Program += " IF Steps[%d] THEN\n"%index
+ for action in values["actions"]:
+ if action["qualifier"] == "N":
+ for line in action["content"].splitlines():
+ self.Program += " %s\n"%line
+ elif action["qualifier"] == "S":
+ if "R_TRIG" not in self.Interface[("VAR", False, False)]:
+ self.Interface[("VAR", False, False)]["R_TRIG"] = []
+ i = 1
+ name = "R_TRIG%d"%i
+ while name in self.Interface[("VAR", False, False)]["R_TRIG"]:
+ i += 1
+ name = "R_TRIG%d"%i
+ self.Interface[("VAR", False, False)]["R_TRIG"].append(name)
+ self.Program += " IF %s(CLK := Steps[%d]) THEN\n"%(name, index)
+ self.Program += " %s := TRUE;\n"%action["content"]
+ for transition in values["transitions"]:
+ if transition["compute"] != '':
+ self.Program += " %s %s"%(transition["condition"], transition["compute"])
+ self.Program += " IF %s THEN\n"%transition["condition"]
+ for target in transition["targets"]:
+ self.Program += " Steps[%d] := TRUE;\n"%self.Order.index(target)
+ self.Program += " Steps[%d] := FALSE;\n"%index
+
+ def ComputeFBDExpression(self, body, link):
+ localid = link.getRefLocalId()
+ instance = body.getContentInstance(localid)
+ if isinstance(instance, plcopen.inVariable):
+ return instance.getExpression()
+ elif isinstance(instance, plcopen.block):
+ name = instance.getInstanceName()
+ type = instance.getTypeName()
+ block_infos = GetBlockType(type)
+ if block_infos["type"] == "function":
+ vars = []
+ for variable in instance.inputVariables.getVariable():
+ connections = variable.connectionPointIn.getConnections()
+ if connections and len(connections) == 1:
+ value = self.ComputeFBDExpression(body, connections[0])
+ vars.append(self.ExtractModifier(variable, value))
+ variable = instance.outputVariables.getVariable()[0]
+ return self.ExtractModifier(variable, "%s(%s)"%(type, ", ".join(vars)))
+ elif block_infos["type"] == "functionBlock":
+ if ("VAR", False, False) not in self.Interface:
+ self.Interface[("VAR", False, False)] = {}
+ if type not in self.Interface[("VAR", False, False)]:
+ self.Interface[("VAR", False, False)][type] = []
+ if name not in self.Interface[("VAR", False, False)][type]:
+ self.Interface[("VAR", False, False)][type].append(name)
+ vars = []
+ for variable in instance.inputVariables.getVariable():
+ connections = variable.connectionPointIn.getConnections()
+ if connections and len(connections) == 1:
+ parameter = variable.getFormalParameter()
+ value = self.ComputeFBDExpression(body, connections[0])
+ vars.append(self.ExtractModifier(variable, "%s := %s"%(parameter, value)))
+ self.Program += " %s(%s);\n"%(name, ", ".join(vars))
+ connectionPoint = link.getPosition()[-1]
+ for variable in instance.outputVariables.getVariable():
+ blockPointx, blockPointy = variable.connectionPointOut.getRelPosition()
+ if instance.getX() + blockPointx == connectionPoint.getX() and instance.getY() + blockPointy == connectionPoint.getY():
+ return self.ExtractModifier(variable, "%s.%s"%(name, variable.getFormalParameter()))
+ raise ValueError, "No output variable found"
+
+ def GenerateLDPaths(self, instance, body):
+ paths = []
+ variable = self.ExtractModifier(instance, instance.getVariable())
+ connections = instance.connectionPointIn.getConnections()
+ for connection in connections:
+ localId = connection.getRefLocalId()
+ next = body.getContentInstance(localId)
+ if isinstance(next, plcopen.leftPowerRail):
+ paths.append(None)
+ else:
+ paths.append(self.GenerateLDPaths(next, body))
+ if isinstance(instance, plcopen.coil):
+ if len(paths) > 1:
+ return tuple(paths)
+ else:
+ return paths
+ else:
+ if len(paths) > 1:
+ return [variable, tuple(paths)]
+ elif type(paths[0]) == ListType:
+ return [variable] + paths[0]
+ elif paths[0]:
+ return [variable, paths[0]]
+ else:
+ return variable
+
+ def GenerateSFCSteps(self, step, pou):
+ step_name = step.getName()
+ if step_name not in self.Steps:
+ step_infos = {"initial" : step.getInitialStep(), "transitions" : [], "actions" : []}
+ self.Steps[step_name] = step_infos
+ if step.connectionPointIn:
+ instances = []
+ connections = step.connectionPointIn.getConnections()
+ if len(connections) == 1:
+ instanceLocalId = connections[0].getRefLocalId()
+ instance = pou.body.getContentInstance(instanceLocalId)
+ if isinstance(instance, plcopen.transition):
+ self.GenerateSFCTransitions(instance, pou)
+ instances.append(instance)
+ elif isinstance(instance, plcopen.selectionConvergence):
+ for connectionPointIn in instance.getConnectionPointIn():
+ divergence_connections = connectionPointIn.getConnections()
+ if len(divergence_connections) == 1:
+ transitionLocalId = connections[0].getRefLocalId()
+ transition = pou.body.getContentInstance(transitionLocalId)
+ self.GenerateSFCTransitions(transition, pou)
+ instances.append(transition)
+ for instance in instances:
+ self.Transitions[instance]["targets"].append(step_name)
+
+ def GenerateSFCJump(self, jump, pou):
+ jump_target = jump.getTargetName()
+ if jump.connectionPointIn:
+ instances = []
+ connections = jump.connectionPointIn.getConnections()
+ if len(connections) == 1:
+ instanceLocalId = connections[0].getRefLocalId()
+ instance = pou.body.getContentInstance(instanceLocalId)
+ if isinstance(instance, plcopen.transition):
+ self.GenerateSFCTransitions(instance, pou)
+ instances.append(instance)
+ elif isinstance(instance, plcopen.selectionConvergence):
+ for connectionPointIn in instance.getConnectionPointIn():
+ divergence_connections = connectionPointIn.getConnections()
+ if len(divergence_connections) == 1:
+ transitionLocalId = divergence_connections[0].getRefLocalId()
+ transition = pou.body.getContentInstance(transitionLocalId)
+ self.GenerateSFCTransitions(transition, pou)
+ instances.append(transition)
+ for instance in instances:
+ self.Transitions[instance]["targets"].append(jump_target)
+
+ def GenerateSFCActions(self, actionBlock, pou):
+ connections = actionBlock.connectionPointIn.getConnections()
+ if len(connections) == 1:
+ stepLocalId = connections[0].getRefLocalId()
+ step = pou.body.getContentInstance(stepLocalId)
+ step_name = step.getName()
+ if step_name not in self.Steps:
+ self.GenerateSFCSteps(step, pou)
+ if step_name in self.Steps:
+ actions = actionBlock.getActions()
+ for action in actions:
+ action_infos = {"qualifier" : action["qualifier"], "content" : ""}
+ if action["type"] == "inline":
+ action_infos["content"] = action["value"]
+ elif action["type"] == "reference":
+ actionContent = pou.getAction(action["value"])
+ if actionContent:
+ actionType = actionContent.getBodyType()
+ actionBody = actionContent.getBody()
+ if actionType in ["ST", "IL"]:
+ action_infos["content"] = actionContent.getText()
+ elif actionType == "FBD":
+ for instance in actionBody.getContentInstances():
+ if isinstance(instance, plcopen.outVariable):
+ var = instance.getExpression()
+ connections = instance.connectionPointIn.getConnections()
+ if connections and len(connections) == 1:
+ expression = self.ComputeFBDExpression(actionBody, connections[0])
+ action_infos["content"] = self.Program + " %s := %s;"%(var, expression)
+ self.Program = ""
+ elif actionType == "LD":
+ for instance in actionbody.getContentInstances():
+ if isinstance(instance, plcopen.coil):
+ paths = self.GenerateLDPaths(instance, actionBody)
+ variable = self.ExtractModifier(instance, instance.getVariable())
+ expression = self.ComputeLDExpression(paths, True)
+ action_infos["content"] = self.Program + " %s := %s;"%(variable, expression)
+ self.Program = ""
+ else:
+ action_infos["content"] = action["value"]
+ self.Steps[step_name]["actions"].append(action_infos)
+
+ def GenerateSFCTransitions(self, transition, pou):
+ if transition not in self.Transitions:
+ connections = transition.connectionPointIn.getConnections()
+ if len(connections) == 1:
+ instanceLocalId = connections[0].getRefLocalId()
+ instance = pou.body.getContentInstance(instanceLocalId)
+ if isinstance(instance, plcopen.step):
+ step_name = instance.getName()
+ if step_name not in self.Steps:
+ self.GenerateSFCSteps(instance, pou)
+ elif isinstance(instance, plcopen.selectionDivergence):
+ divergence_connections = instance.connectionPointIn.getConnections()
+ if len(divergence_connections) == 1:
+ stepLocalId = divergence_connections[0].getRefLocalId()
+ divergence_instance = pou.body.getContentInstance(stepLocalId)
+ if isinstance(divergence_instance, plcopen.step):
+ step_name = divergence_instance.getName()
+ if step_name not in self.Steps:
+ self.GenerateSFCSteps(divergence_instance, pou)
+ if step_name in self.Steps:
+ transition_infos = {"targets" : []}
+ transitionValues = transition.getConditionContent()
+ transition_infos["condition"] = transitionValues["value"]
+ if transitionValues["type"] == "inline":
+ transition_infos["compute"] = ""
+ else:
+ transitionContent = pou.getTransition(transitionValues["value"])
+ transitionType = transitionContent.getBodyType()
+ transitionBody = transitionContent.getBody()
+ if transitionType in ["ST", "IL"]:
+ transition_infos["compute"] = "%s\n"%transitionContent.getText()
+ elif conditionType == "FBD":
+ for instance in conditionBody.getContentInstances():
+ if isinstance(instance, plcopen.outVariable):
+ var = instance.getExpression()
+ connections = instance.connectionPointIn.getConnections()
+ if connections and len(connections) == 1:
+ expression = self.ComputeFBDExpression(actionBody, connections[0])
+ transition_infos["compute"] = self.Program + ":= %s;\n"%(var, expression)
+ self.Program = ""
+ elif actionType == "LD":
+ for instance in conditionbody.getContentInstances():
+ if isinstance(instance, plcopen.coil):
+ paths = self.GenerateLDPaths(instance, conditionBody)
+ variable = self.ExtractModifier(instance, instance.getVariable())
+ expression = self.ComputeLDExpression(paths, True)
+ transition_infos["compute"] = self.Program + ":= %s;\n"%(variable, expression)
+ self.Program = ""
+ self.Steps[step_name]["transitions"].append(transition_infos)
+ self.Transitions[transition] = transition_infos
+
+ def GenerateSFCStepOrder(self, name, path):
+ self.Order.append(name)
+ for transition in self.Steps[name]["transitions"]:
+ for target in transition["targets"]:
+ if target not in self.Order or target not in path:
+ if target in self.Order:
+ self.Order.remove(target)
+ self.GenerateSFCStepOrder(target, path + [name])
+
+ def ComputeLDExpression(self, paths, first = False):
+ if type(paths) == TupleType:
+ if None in paths:
+ return "TRUE"
+ else:
+ var = [self.ComputeLDExpression(path) for path in paths]
+ if first:
+ return " OR ".join(var)
+ else:
+ return "(%s)"%" OR ".join(var)
+ elif type(paths) == ListType:
+ var = [self.ComputeLDExpression(path) for path in paths]
+ return " AND ".join(var)
+ else:
+ return paths
+
+ def ExtractModifier(self, variable, text):
+ if variable.getNegated():
+ return "NOT(%s)"%text
+ else:
+ edge = variable.getEdge()
+ if edge:
+ if edge.getValue() == "rising":
+ return self.AddTrigger("R_TRIG", text)
+ elif edge.getValue() == "falling":
+ return self.AddTrigger("F_TRIG", text)
+ return text
+
+ def AddTrigger(self, edge, text):
+ if ("VAR", False, False) not in self.Interface:
+ self.Interface[("VAR", False, False)] = {}
+ if type not in self.Interface[("VAR", False, False)]:
+ self.Interface[("VAR", False, False)][edge] = []
+ i = 1
+ name = "%s%d"%(edge, i)
+ while name in self.Interface[("VAR", False, False)][edge]:
+ i += 1
+ name = "%s%d"%(edge, i)
+ self.Interface[("VAR", False, False)][edge].append(name)
+ self.Program += " %s(CLK := %s);\n"%(name, text)
+ return "%s.Q"%name
+
+ def GenerateSTProgram(self):
+ program = ""
+ if "returnType" in self.Interface:
+ program += "%s %s : %s\n"%(self.Type, self.Name, self.Interface["returnType"])
+ else:
+ program += "%s %s\n"%(self.Type, self.Name)
+ for values, variables in self.Interface.items():
+ if values != "returnType":
+ program += " %s"%values[0]
+ if values[1]:
+ program += " RETAIN"
+ if values[2]:
+ program += " CONSTANT"
+ program += "\n"
+ for vartype, list in variables.items():
+ program += " %s : %s;\n"%(", ".join(list), vartype)
+ program += " END_%s\n"%values[0]
+ program += "\n"
+ program += self.Program
+ program += "END_%s\n\n"%self.Type
+ return program
+
+def GenerateCurrentProgram(project):
+ program = ""
+ for pou in project.getPous():
+ pou_type = pou.getPouType().getValue()
+ if pou_type == "function":
+ pou_program = PouProgram(pou.getName(), "FUNCTION")
+ elif pou_type == "functionBlock":
+ pou_program = PouProgram(pou.getName(), "FUNCTION_BLOCK")
+ elif pou_type == "program":
+ pou_program = PouProgram(pou.getName(), "PROGRAM")
+ else:
+ raise ValueError, "Undefined pou type"
+ pou_program.GenerateInterface(pou.getInterface())
+ pou_program.GenerateProgram(pou)
+ program += pou_program.GenerateSTProgram()
+ return program
+