plcopen/structures.py
changeset 78 049f2e7090a2
parent 58 39cd981ff242
child 92 76d5001393df
--- a/plcopen/structures.py	Thu Aug 23 09:26:02 2007 +0200
+++ b/plcopen/structures.py	Thu Aug 23 09:39:18 2007 +0200
@@ -27,6 +27,40 @@
 
 LANGUAGES = ["IL","ST","FBD","LD","SFC"]
 
+def generate_block(generator, block, body, link):
+    name = block.getInstanceName()
+    type = block.getTypeName()
+    block_infos = GetBlockType(type)
+    if block_infos["type"] == "function" and link:
+        generator.GeneratePouProgram(type)
+        vars = []
+        for variable in block.inputVariables.getVariable():
+            connections = variable.connectionPointIn.getConnections()
+            if connections and len(connections) == 1:
+                value = generator.ComputeFBDExpression(body, connections[0])
+                vars.append(generator.ExtractModifier(variable, value))
+        variable = block.outputVariables.getVariable()[0]
+        return generator.ExtractModifier(variable, "%s(%s)"%(type, ", ".join(vars)))
+    elif block_infos["type"] == "functionBlock":
+        if not generator.ComputedBlocks.get(name, False):
+            vars = []
+            for variable in block.inputVariables.getVariable():
+                connections = variable.connectionPointIn.getConnections()
+                if connections and len(connections) == 1:
+                    parameter = variable.getFormalParameter()
+                    value = generator.ComputeFBDExpression(body, connections[0])
+                    vars.append("%s := %s"%(parameter, generator.ExtractModifier(variable, value)))
+            generator.Program += "  %s(%s);\n"%(name, ", ".join(vars))
+            generator.ComputedBlocks[name] = True
+        if link:
+            connectionPoint = link.getPosition()[-1]
+        else:
+            connectionPoint = None
+        for variable in block.outputVariables.getVariable():
+            blockPointx, blockPointy = variable.connectionPointOut.getRelPosition()
+            if not connectionPoint or block.getX() + blockPointx == connectionPoint.getX() and block.getY() + blockPointy == connectionPoint.getY():
+                return generator.ExtractModifier(variable, "%s.%s"%(name, variable.getFormalParameter()))
+        raise ValueError, "No output variable found"
 
 #-------------------------------------------------------------------------------
 #                        Function Block Types definitions
@@ -42,6 +76,7 @@
     - "inputs" : List of the block inputs
     - "outputs" : List of the block outputs
     - "comment" : Comment that will be displayed in the block popup
+    - "generate" : Method that generator will call for generating ST block code
 Inputs and outputs are a tuple of characteristics that are in order:
     - The name
     - The data type
@@ -52,110 +87,104 @@
                [{"name" : "SR", "type" : "functionBlock", "extensible" : False, 
                     "inputs" : [("S1","BOOL","none"),("R","BOOL","none")], 
                     "outputs" : [("Q1","BOOL","none")],
-                    "comment" : "SR bistable\nThe SR bistable is a latch where the Set dominates."},
+                    "comment" : "SR bistable\nThe SR bistable is a latch where the Set dominates.",
+                    "generate" : generate_block},
                 {"name" : "RS", "type" : "functionBlock", "extensible" : False, 
                     "inputs" : [("S","BOOL","none"),("R1","BOOL","none")], 
                     "outputs" : [("Q1","BOOL","none")],
-                    "comment" : "RS bistable\nThe RS bistable is a latch where the Reset dominates."},
+                    "comment" : "RS bistable\nThe RS bistable is a latch where the Reset dominates.",
+                    "generate" : generate_block},
                 {"name" : "SEMA", "type" : "functionBlock", "extensible" : False, 
                     "inputs" : [("CLAIM","BOOL","none"),("RELEASE","BOOL","none")], 
                     "outputs" : [("BUSY","BOOL","none")],
-                    "comment" : "Semaphore\nThe semaphore provides a mechanism to allow software elements mutually exclusive access to certain ressources."},
+                    "comment" : "Semaphore\nThe semaphore provides a mechanism to allow software elements mutually exclusive access to certain ressources.",
+                    "generate" : generate_block},
                 {"name" : "R_TRIG", "type" : "functionBlock", "extensible" : False, 
                     "inputs" : [("CLK","BOOL","none")], 
                     "outputs" : [("Q","BOOL","none")],
-                    "comment" : "Rising edge detector\nThe output produces a single pulse when a rising edge is detected."},
+                    "comment" : "Rising edge detector\nThe output produces a single pulse when a rising edge is detected.",
+                    "generate" : generate_block},
                 {"name" : "F_TRIG", "type" : "functionBlock", "extensible" : False, 
                     "inputs" : [("CLK","BOOL","none")], 
                     "outputs" : [("Q","BOOL","none")],
-                    "comment" : "Falling edge detector\nThe output produces a single pulse when a falling edge is detected."},
+                    "comment" : "Falling edge detector\nThe output produces a single pulse when a falling edge is detected.",
+                    "generate" : generate_block},
                 {"name" : "CTU", "type" : "functionBlock", "extensible" : False, 
                     "inputs" : [("CU","BOOL","rising"),("R","BOOL","none"),("PV","INT","none")], 
                     "outputs" : [("Q","BOOL","none"),("CV","INT","none")],
-                    "comment" : "Up-counter\nThe up-counter can be used to signal when a count has reached a maximum value."},
+                    "comment" : "Up-counter\nThe up-counter can be used to signal when a count has reached a maximum value.",
+                    "generate" : generate_block},
                 {"name" : "CTD", "type" : "functionBlock", "extensible" : False, 
                     "inputs" : [("CD","BOOL","rising"),("LD","BOOL","none"),("PV","INT","none")], 
                     "outputs" : [("Q","BOOL","none"),("CV","INT","none")],
-                    "comment" : "Down-counter\nThe down-counter can be used to signal when a count has reached zero, on counting down from a preset value."},
+                    "comment" : "Down-counter\nThe down-counter can be used to signal when a count has reached zero, on counting down from a preset value.",
+                    "generate" : generate_block},
                 {"name" : "CTUD", "type" : "functionBlock", "extensible" : False, 
                     "inputs" : [("CU","BOOL","rising"),("CD","BOOL","rising"),("R","BOOL","none"),("LD","BOOL","none"),("PV","INT","none")], 
                     "outputs" : [("QU","BOOL","none"),("QD","BOOL","none"),("CV","INT","none")],
-                    "comment" : "Up-down counter\nThe up-down counter has two inputs CU and CD. It can be used to both count up on one input ans down on the other."},
+                    "comment" : "Up-down counter\nThe up-down counter has two inputs CU and CD. It can be used to both count up on one input ans down on the other.",
+                    "generate" : generate_block},
                 {"name" : "TP", "type" : "functionBlock", "extensible" : False, 
                     "inputs" : [("IN","BOOL","none"),("PT","TIME","none")], 
                     "outputs" : [("Q","BOOL","none"),("ET","TIME","none")],
-                    "comment" : "Pulse timer\nThe pulse timer can be used to generate output pulses of a given time duration."},
+                    "comment" : "Pulse timer\nThe pulse timer can be used to generate output pulses of a given time duration.",
+                    "generate" : generate_block},
                 {"name" : "TOF", "type" : "functionBlock", "extensible" : False, 
                     "inputs" : [("IN","BOOL","none"),("PT","TIME","none")], 
                     "outputs" : [("Q","BOOL","none"),("ET","TIME","none")],
-                    "comment" : "On-delay timer\nThe on-delay timer can be used to delay setting an output true, for fixed period after an input becomes true."},
+                    "comment" : "On-delay timer\nThe on-delay timer can be used to delay setting an output true, for fixed period after an input becomes true.",
+                    "generate" : generate_block},
                 {"name" : "TON", "type" : "functionBlock", "extensible" : False, 
                     "inputs" : [("IN","BOOL","none"),("PT","TIME","none")], 
                     "outputs" : [("Q","BOOL","none"),("ET","TIME","none")],
-                    "comment" : "Off-delay timer\nThe off-delay timer can be used to delay setting an output false, for fixed period after input goes false."},
+                    "comment" : "Off-delay timer\nThe off-delay timer can be used to delay setting an output false, for fixed period after input goes false.",
+                    "generate" : generate_block},
                 {"name" : "RTC", "type" : "functionBlock", "extensible" : False, 
                     "inputs" : [("EN","BOOL","none"),("PDT","DATE_AND_TIME","none")], 
                     "outputs" : [("Q","BOOL","none"),("CDT","DATE_AND_TIME","none")],
-                    "comment" : "Real time clock\nThe real time clock has many uses including time stamping, setting dates and times of day in batch reports, in alarm messages and so on."},
+                    "comment" : "Real time clock\nThe real time clock has many uses including time stamping, setting dates and times of day in batch reports, in alarm messages and so on.",
+                    "generate" : generate_block},
                 {"name" : "INTEGRAL", "type" : "functionBlock", "extensible" : False, 
                     "inputs" : [("RUN","BOOL","none"),("R1","BOOL","none"),("XIN","REAL","none"),("X0","REAL","none"),("CYCLE","TIME","none")], 
                     "outputs" : [("Q","BOOL","none"),("XOUT","REAL","none")],
-                    "comment" : "Integral\nThe integral function block integrates the value of input XIN over time."},
+                    "comment" : "Integral\nThe integral function block integrates the value of input XIN over time.",
+                    "generate" : generate_block},
                 {"name" : "DERIVATIVE", "type" : "functionBlock", "extensible" : False, 
                     "inputs" : [("RUN","BOOL","none"),("XIN","REAL","none"),("CYCLE","TIME","none")], 
                     "outputs" : [("XOUT","REAL","none")],
-                    "comment" : "Derivative\nThe derivative function block produces an output XOUT proportional to the rate of change of the input XIN."},
+                    "comment" : "Derivative\nThe derivative function block produces an output XOUT proportional to the rate of change of the input XIN.",
+                    "generate" : generate_block},
                 {"name" : "PID", "type" : "functionBlock", "extensible" : False, 
                     "inputs" : [("AUTO","BOOL","none"),("PV","REAL","none"),("SP","REAL","none"),("X0","REAL","none"),("KP","REAL","none"),("TR","REAL","none"),("TD","REAL","none"),("CYCLE","TIME","none")], 
                     "outputs" : [("XOUT","REAL","none")],
-                    "comment" : "PID\nThe PID (proportional, Integral, Derivative) function block provides the classical three term controller for closed loop control."},
+                    "comment" : "PID\nThe PID (proportional, Integral, Derivative) function block provides the classical three term controller for closed loop control.",
+                    "generate" : generate_block},
                 {"name" : "RAMP", "type" : "functionBlock", "extensible" : False, 
                     "inputs" : [("RUN","BOOL","none"),("X0","REAL","none"),("X1","REAL","none"),("TR","TIME","none"),("CYCLE","TIME","none"),("HOLDBACK","BOOL","none"),("ERROR","REAL","none"),("PV","REAL","none")], 
                     "outputs" : [("RAMP","BOOL","none"),("XOUT","REAL","none")],
-                    "comment" : "Ramp\nThe RAMP function block is modelled on example given in the standard but with the addition of a 'Holdback' feature."},
+                    "comment" : "Ramp\nThe RAMP function block is modelled on example given in the standard but with the addition of a 'Holdback' feature.",
+                    "generate" : generate_block},
                 {"name" : "HYSTERESIS", "type" : "functionBlock", "extensible" : False, 
                     "inputs" : [("XIN1","REAL","none"),("XIN2","REAL","none"),("EPS","REAL","none")], 
                     "outputs" : [("Q","BOOL","none")],
-                    "comment" : "Hysteresis\nThe hysteresis function block provides a hysteresis boolean output driven by the difference of two floating point (REAL) inputs XIN1 and XIN2."},
+                    "comment" : "Hysteresis\nThe hysteresis function block provides a hysteresis boolean output driven by the difference of two floating point (REAL) inputs XIN1 and XIN2.",
+                    "generate" : generate_block},
                 {"name" : "RATIO_MONITOR", "type" : "functionBlock", "extensible" : False, 
                     "inputs" : [("PV1","REAL","none"),("PV2","REAL","none"),("RATIO","REAL","none"),("TIMON","TIME","none"),("TIMOFF","TIME","none"),("TOLERANCE","BOOL","none"),("RESET","BOOL","none"),("CYCLE","TIME","none")], 
                     "outputs" : [("ALARM","BOOL","none"),("TOTAL_ERR","BOOL","none")],
-                    "comment" : "Ratio monitor\nThe ratio_monitor function block checks that one process value PV1 is always a given ratio (defined by input RATIO) of a second process value PV2."}
+                    "comment" : "Ratio monitor\nThe ratio_monitor function block checks that one process value PV1 is always a given ratio (defined by input RATIO) of a second process value PV2.",
+                    "generate" : generate_block}
                 ]},
-            {"name" : "SVGUI function blocks", "list":
-                [{"name" : "Container", "type" : "functionBlock", "extensible" : False, 
-                    "inputs" : [("X","FLOAT","none"),("SetX","BOOL","none"),("Y","FLOAT","none"),("SetY","BOOL","none"),("Angle","FLOAT","none"),("SetAngle","BOOL","none")], 
-                    "outputs" : [("X","FLOAT","none"),("X Changed","BOOL","none"),("Y","FLOAT","none"),("Y Changed","BOOL","none"),("Angle","FLOAT","none"),("Angle Changed","BOOL","none")],
-                    "comment" : "SVGUI Container"},
-                {"name" : "Button", "type" : "functionBlock", "extensible" : False, 
-                    "inputs" : [("Show","BOOL","none"),("Toggle","BOOL","none")], 
-                    "outputs" : [("Visible","BOOL","none"),("State","BOOL","none")],
-                    "comment" : "SVGUI Button"},
-                {"name" : "TextCtrl", "type" : "functionBlock", "extensible" : False, 
-                    "inputs" : [("Text","STRING","none"),("Set Text","BOOL","none")], 
-                    "outputs" : [("Text","STRING","none"),("Text Changed","BOOL","none")],
-                    "comment" : "SVGUI Text Control"},
-                {"name" : "ScrollBar", "type" : "functionBlock", "extensible" : False, 
-                    "inputs" : [("Position","UINT","none"),("Set Position","BOOL","none")], 
-                    "outputs" : [("Position","UINT","none"),("Position Changed","BOOL","none")],
-                    "comment" : "SVGUI ScrollBar"},
-                {"name" : "NoteBook", "type" : "functionBlock", "extensible" : False, 
-                    "inputs" : [("Selected","UINT","none"),("Set Selected","BOOL","none")], 
-                    "outputs" : [("Selected","UINT","none"),("Selected Changed","BOOL","none")],
-                    "comment" : "SVGUI Notebook"},
-                {"name" : "RotatingCtrl", "type" : "functionBlock", "extensible" : False, 
-                    "inputs" : [("Angle","FLOAT","none"),("Set Angle","BOOL","none")], 
-                    "outputs" : [("Angle","FLOAT","none"),("Angle changed","BOOL","none")],
-                    "comment" : "SVGUI Rotating Control"},
-               ]}
              ]
+             
+PluginTypes = []
 
 """
 Function that returns the block definition associated to the block type given
 """
 
 def GetBlockType(type, inputs = None):
-    for category in BlockTypes:
+    for category in BlockTypes + PluginTypes:
         for blocktype in category["list"]:
             if inputs:
                 block_inputs = tuple([var_type for name, var_type, modifier in blocktype["inputs"]])
@@ -166,6 +195,12 @@
                 return blocktype
     return None
 
+"""
+Function that add a new plugin to the plugin list
+"""
+
+def AddPlugin(blocklist):
+    PluginTypes.append(blocklist)
 
 #-------------------------------------------------------------------------------
 #                           Data Types definitions
@@ -455,6 +490,7 @@
                 Function_decl_list = []
             if Current_section:
                 Function_decl = dict([(champ, val) for champ, val in zip(fonctions, fields[1:]) if champ])
+                Function_decl["generate"] = generate_block
                 baseinputnumber = int(Function_decl.get("baseinputnumber",1))
                 Function_decl["baseinputnumber"] = baseinputnumber
                 for param, value in Function_decl.iteritems():