plcopen/structures.py
branch1.1 Korean release
changeset 1384 02fe382c4511
parent 1330 96b242e4c59d
child 1390 0f4d32a033e0
equal deleted inserted replaced
1280:72a826dfcfbb 1384:02fe382c4511
    21 #You should have received a copy of the GNU General Public
    21 #You should have received a copy of the GNU General Public
    22 #License along with this library; if not, write to the Free Software
    22 #License along with this library; if not, write to the Free Software
    23 #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    23 #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    24 
    24 
    25 import string, os, sys, re
    25 import string, os, sys, re
       
    26 from plcopen import LoadProject
       
    27 from collections import OrderedDict
    26 
    28 
    27 LANGUAGES = ["IL","ST","FBD","LD","SFC"]
    29 LANGUAGES = ["IL","ST","FBD","LD","SFC"]
    28 
    30 
    29 LOCATIONDATATYPES = {"X" : ["BOOL"],
    31 LOCATIONDATATYPES = {"X" : ["BOOL"],
    30                      "B" : ["SINT", "USINT", "BYTE", "STRING"],
    32                      "B" : ["SINT", "USINT", "BYTE", "STRING"],
    32                      "D" : ["DINT", "UDINT", "REAL", "DWORD"],
    34                      "D" : ["DINT", "UDINT", "REAL", "DWORD"],
    33                      "L" : ["LINT", "ULINT", "LREAL", "LWORD"]} 
    35                      "L" : ["LINT", "ULINT", "LREAL", "LWORD"]} 
    34 
    36 
    35 _ = lambda x:x
    37 _ = lambda x:x
    36 
    38 
    37 # Helper for emulate join on element list
       
    38 def JoinList(separator, mylist):
       
    39     if len(mylist) > 0 :
       
    40         return reduce(lambda x, y: x + separator + y, mylist)
       
    41     else :
       
    42         return mylist
       
    43 
       
    44 def generate_block(generator, block, block_infos, body, link, order=False, to_inout=False):
       
    45     body_type = body.getcontent()["name"]
       
    46     name = block.getinstanceName()
       
    47     type = block.gettypeName()
       
    48     executionOrderId = block.getexecutionOrderId()
       
    49     input_variables = block.inputVariables.getvariable()
       
    50     output_variables = block.outputVariables.getvariable()
       
    51     inout_variables = {}
       
    52     for input_variable in input_variables:
       
    53         for output_variable in output_variables:
       
    54             if input_variable.getformalParameter() == output_variable.getformalParameter():
       
    55                 inout_variables[input_variable.getformalParameter()] = ""
       
    56     input_names = [input[0] for input in block_infos["inputs"]]
       
    57     output_names = [output[0] for output in block_infos["outputs"]]
       
    58     if block_infos["type"] == "function":
       
    59         if not generator.ComputedBlocks.get(block, False) and not order:
       
    60             generator.ComputedBlocks[block] = True
       
    61             connected_vars = []
       
    62             if not block_infos["extensible"]:
       
    63                 input_connected = dict([("EN", None)] + 
       
    64                                        [(input_name, None) for input_name in input_names])
       
    65                 for variable in input_variables:
       
    66                     parameter = variable.getformalParameter()
       
    67                     if input_connected.has_key(parameter):
       
    68                         input_connected[parameter] = variable
       
    69                 if input_connected["EN"] is None:
       
    70                     input_connected.pop("EN")
       
    71                     input_parameters = input_names
       
    72                 else:
       
    73                     input_parameters = ["EN"] + input_names
       
    74             else:
       
    75                 input_connected = dict([(variable.getformalParameter(), variable)
       
    76                                         for variable in input_variables])
       
    77                 input_parameters = [variable.getformalParameter()
       
    78                                     for variable in input_variables]
       
    79             one_input_connected = False
       
    80             all_input_connected = True
       
    81             for i, parameter in enumerate(input_parameters):
       
    82                 variable = input_connected.get(parameter)
       
    83                 if variable is not None:
       
    84                     input_info = (generator.TagName, "block", block.getlocalId(), "input", i)
       
    85                     connections = variable.connectionPointIn.getconnections()
       
    86                     if connections is not None:
       
    87                         if parameter != "EN":
       
    88                             one_input_connected = True
       
    89                         if inout_variables.has_key(parameter):
       
    90                             expression = generator.ComputeExpression(body, connections, executionOrderId > 0, True)
       
    91                             if expression is not None:
       
    92                                 inout_variables[parameter] = value
       
    93                         else:
       
    94                             expression = generator.ComputeExpression(body, connections, executionOrderId > 0)
       
    95                         if expression is not None:
       
    96                             connected_vars.append(([(parameter, input_info), (" := ", ())],
       
    97                                                    generator.ExtractModifier(variable, expression, input_info)))
       
    98                     else:
       
    99                         all_input_connected = False
       
   100                 else:
       
   101                     all_input_connected = False
       
   102             if len(output_variables) > 1 or not all_input_connected:
       
   103                 vars = [name + value for name, value in connected_vars]
       
   104             else:
       
   105                 vars = [value for name, value in connected_vars]
       
   106             if one_input_connected:
       
   107                 for i, variable in enumerate(output_variables):
       
   108                     parameter = variable.getformalParameter()
       
   109                     if not inout_variables.has_key(parameter) and parameter in output_names + ["", "ENO"]:
       
   110                         if variable.getformalParameter() == "":
       
   111                             variable_name = "%s%d"%(type, block.getlocalId())
       
   112                         else:
       
   113                             variable_name = "%s%d_%s"%(type, block.getlocalId(), parameter)
       
   114                         if generator.Interface[-1][0] != "VAR" or generator.Interface[-1][1] is not None or generator.Interface[-1][2]:
       
   115                             generator.Interface.append(("VAR", None, False, []))
       
   116                         if variable.connectionPointOut in generator.ConnectionTypes:
       
   117                             generator.Interface[-1][3].append((generator.ConnectionTypes[variable.connectionPointOut], variable_name, None, None))
       
   118                         else:
       
   119                             generator.Interface[-1][3].append(("ANY", variable_name, None, None))
       
   120                         if len(output_variables) > 1 and parameter not in ["", "OUT"]:
       
   121                             vars.append([(parameter, (generator.TagName, "block", block.getlocalId(), "output", i)), 
       
   122                                          (" => %s"%variable_name, ())])
       
   123                         else:
       
   124                             output_info = (generator.TagName, "block", block.getlocalId(), "output", i)
       
   125                             output_name = variable_name
       
   126                 generator.Program += [(generator.CurrentIndent, ()),
       
   127                                       (output_name, output_info),
       
   128                                       (" := ", ()),
       
   129                                       (type, (generator.TagName, "block", block.getlocalId(), "type")),
       
   130                                       ("(", ())]
       
   131                 generator.Program += JoinList([(", ", ())], vars)
       
   132                 generator.Program += [(");\n", ())]
       
   133             else:
       
   134                 generator.Warnings.append(_("\"%s\" function cancelled in \"%s\" POU: No input connected")%(type, generator.TagName.split("::")[-1]))
       
   135     elif block_infos["type"] == "functionBlock":
       
   136         if not generator.ComputedBlocks.get(block, False) and not order:
       
   137             generator.ComputedBlocks[block] = True
       
   138             vars = []
       
   139             offset_idx = 0
       
   140             for variable in input_variables:
       
   141                 parameter = variable.getformalParameter()
       
   142                 if parameter in input_names or parameter == "EN":
       
   143                     if parameter == "EN":
       
   144                         input_idx = 0
       
   145                         offset_idx = 1
       
   146                     else:
       
   147                         input_idx = offset_idx + input_names.index(parameter)
       
   148                     input_info = (generator.TagName, "block", block.getlocalId(), "input", input_idx)
       
   149                     connections = variable.connectionPointIn.getconnections()
       
   150                     if connections is not None:
       
   151                         expression = generator.ComputeExpression(body, connections, executionOrderId > 0, inout_variables.has_key(parameter))
       
   152                         if expression is not None:
       
   153                             vars.append([(parameter, input_info),
       
   154                                          (" := ", ())] + generator.ExtractModifier(variable, expression, input_info))
       
   155             generator.Program += [(generator.CurrentIndent, ()), 
       
   156                                   (name, (generator.TagName, "block", block.getlocalId(), "name")),
       
   157                                   ("(", ())]
       
   158             generator.Program += JoinList([(", ", ())], vars)
       
   159             generator.Program += [(");\n", ())]
       
   160     
       
   161     if link:
       
   162         connectionPoint = link.getposition()[-1]
       
   163         output_parameter = link.getformalParameter()
       
   164     else:
       
   165         connectionPoint = None
       
   166         output_parameter = None
       
   167     
       
   168     output_variable = None
       
   169     output_idx = 0
       
   170     if output_parameter is not None:
       
   171         if output_parameter in output_names or output_parameter == "ENO":
       
   172             for variable in output_variables:
       
   173                 if variable.getformalParameter() == output_parameter:
       
   174                     output_variable = variable
       
   175                     if output_parameter != "ENO":
       
   176                         output_idx = output_names.index(output_parameter)
       
   177     else:
       
   178         for i, variable in enumerate(output_variables):
       
   179             blockPointx, blockPointy = variable.connectionPointOut.getrelPositionXY()
       
   180             if (not connectionPoint or 
       
   181                 block.getx() + blockPointx == connectionPoint.getx() and 
       
   182                 block.gety() + blockPointy == connectionPoint.gety()):
       
   183                 output_variable = variable
       
   184                 output_parameter = variable.getformalParameter()
       
   185                 output_idx = i
       
   186     
       
   187     if output_variable is not None:
       
   188         if block_infos["type"] == "function":
       
   189             output_info = (generator.TagName, "block", block.getlocalId(), "output", output_idx)
       
   190             if inout_variables.has_key(output_parameter):
       
   191                 output_value = inout_variables[output_parameter]
       
   192             else:
       
   193                 if output_parameter == "":
       
   194                     output_name = "%s%d"%(type, block.getlocalId())
       
   195                 else:
       
   196                     output_name = "%s%d_%s"%(type, block.getlocalId(), output_parameter)
       
   197                 output_value = [(output_name, output_info)]
       
   198             return generator.ExtractModifier(output_variable, output_value, output_info)
       
   199         
       
   200         if block_infos["type"] == "functionBlock":
       
   201             output_info = (generator.TagName, "block", block.getlocalId(), "output", output_idx)
       
   202             output_name = generator.ExtractModifier(output_variable, [("%s.%s"%(name, output_parameter), output_info)], output_info)
       
   203             if to_inout:
       
   204                 variable_name = "%s_%s"%(name, output_parameter)
       
   205                 if not generator.IsAlreadyDefined(variable_name):
       
   206                     if generator.Interface[-1][0] != "VAR" or generator.Interface[-1][1] is not None or generator.Interface[-1][2]:
       
   207                         generator.Interface.append(("VAR", None, False, []))
       
   208                     if variable.connectionPointOut in generator.ConnectionTypes:
       
   209                         generator.Interface[-1][3].append(
       
   210                             (generator.ConnectionTypes[output_variable.connectionPointOut], variable_name, None, None))
       
   211                     else:
       
   212                         generator.Interface[-1][3].append(("ANY", variable_name, None, None))
       
   213                     generator.Program += [(generator.CurrentIndent, ()),
       
   214                                           ("%s := "%variable_name, ())]
       
   215                     generator.Program += output_name
       
   216                     generator.Program += [(";\n", ())]
       
   217                 return [(variable_name, ())]
       
   218             return output_name 
       
   219     if link is not None:
       
   220         if output_parameter is None:
       
   221             output_parameter = ""
       
   222         if name:
       
   223             blockname = "%s(%s)" % (name, type)
       
   224         else:
       
   225             blockname = type
       
   226         raise ValueError, _("No output %s variable found in block %s in POU %s. Connection must be broken")  % \
       
   227                           (output_parameter, blockname, generator.Name)
       
   228 
       
   229 def initialise_block(type, name, block = None):
       
   230     return [(type, name, None, None)]
       
   231 
       
   232 #-------------------------------------------------------------------------------
    39 #-------------------------------------------------------------------------------
   233 #                        Function Block Types definitions
    40 #                        Function Block Types definitions
   234 #-------------------------------------------------------------------------------
    41 #-------------------------------------------------------------------------------
   235 
    42 
       
    43 ScriptDirectory = os.path.split(os.path.realpath(__file__))[0]
       
    44 
       
    45 StdBlockLibrary, error = LoadProject(
       
    46     os.path.join(ScriptDirectory, "Standard_Function_Blocks.xml"))
       
    47 AddnlBlockLibrary, error = LoadProject(
       
    48     os.path.join(ScriptDirectory, "Additional_Function_Blocks.xml"))
       
    49 
       
    50 StdBlockComments = {
       
    51     "SR": _("SR bistable\nThe SR bistable is a latch where the Set dominates."),
       
    52     "RS": _("RS bistable\nThe RS bistable is a latch where the Reset dominates."),
       
    53     "SEMA": _("Semaphore\nThe semaphore provides a mechanism to allow software elements mutually exclusive access to certain ressources."),
       
    54     "R_TRIG": _("Rising edge detector\nThe output produces a single pulse when a rising edge is detected."),
       
    55     "F_TRIG": _("Falling edge detector\nThe output produces a single pulse when a falling edge is detected."),
       
    56     "CTU": _("Up-counter\nThe up-counter can be used to signal when a count has reached a maximum value."),
       
    57     "CTD": _("Down-counter\nThe down-counter can be used to signal when a count has reached zero, on counting down from a preset value."),
       
    58     "CTUD": _("Up-down counter\nThe up-down counter has two inputs CU and CD. It can be used to both count up on one input and down on the other."),
       
    59     "TP": _("Pulse timer\nThe pulse timer can be used to generate output pulses of a given time duration."),
       
    60     "TON": _("On-delay timer\nThe on-delay timer can be used to delay setting an output true, for fixed period after an input becomes true."),
       
    61     "TOF": _("Off-delay timer\nThe off-delay timer can be used to delay setting an output false, for fixed period after input goes false."),
       
    62     "RTC": _("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."),
       
    63     "INTEGRAL": _("Integral\nThe integral function block integrates the value of input XIN over time."),
       
    64     "DERIVATIVE": _("Derivative\nThe derivative function block produces an output XOUT proportional to the rate of change of the input XIN."),
       
    65     "PID": _("PID\nThe PID (proportional, Integral, Derivative) function block provides the classical three term controller for closed loop control."),
       
    66     "RAMP": _("Ramp\nThe RAMP function block is modelled on example given in the standard."),
       
    67     "HYSTERESIS": _("Hysteresis\nThe hysteresis function block provides a hysteresis boolean output driven by the difference of two floating point (REAL) inputs XIN1 and XIN2."),
       
    68 }
       
    69 
       
    70 for block_type in ["CTU", "CTD", "CTUD"]:
       
    71     for return_type in ["DINT", "LINT", "UDINT", "ULINT"]:
       
    72         StdBlockComments["%s_%s" % (block_type, return_type)] = StdBlockComments[block_type]
       
    73 
       
    74 def GetBlockInfos(pou):
       
    75     infos = pou.getblockInfos()
       
    76     infos["comment"] = StdBlockComments[infos["name"]]
       
    77     infos["inputs"] = [
       
    78         (var_name, var_type, "rising")
       
    79         if var_name in ["CU", "CD"]
       
    80         else (var_name, var_type, var_modifier)
       
    81         for var_name, var_type, var_modifier in infos["inputs"]]
       
    82     return infos
   236 
    83 
   237 """
    84 """
   238 Ordored list of common Function Blocks defined in the IEC 61131-3
    85 Ordored list of common Function Blocks defined in the IEC 61131-3
   239 Each block have this attributes:
    86 Each block have this attributes:
   240     - "name" : The block name
    87     - "name" : The block name
   248     - The name
    95     - The name
   249     - The data type
    96     - The data type
   250     - The default modifier which can be "none", "negated", "rising" or "falling"
    97     - The default modifier which can be "none", "negated", "rising" or "falling"
   251 """
    98 """
   252 
    99 
   253 BlockTypes = [{"name" : _("Standard function blocks"), "list":
   100 StdBlckLst = [{"name" : _("Standard function blocks"), "list":
   254                [{"name" : "SR", "type" : "functionBlock", "extensible" : False, 
   101                [GetBlockInfos(pou) for pou in StdBlockLibrary.getpous()]},
   255                     "inputs" : [("S1","BOOL","none"),("R","BOOL","none")], 
       
   256                     "outputs" : [("Q1","BOOL","none")],
       
   257                     "comment" : _("SR bistable\nThe SR bistable is a latch where the Set dominates."),
       
   258                     "generate" : generate_block, "initialise" : initialise_block},
       
   259                 {"name" : "RS", "type" : "functionBlock", "extensible" : False, 
       
   260                     "inputs" : [("S","BOOL","none"),("R1","BOOL","none")], 
       
   261                     "outputs" : [("Q1","BOOL","none")],
       
   262                     "comment" : _("RS bistable\nThe RS bistable is a latch where the Reset dominates."),
       
   263                     "generate" : generate_block, "initialise" : initialise_block},
       
   264                 {"name" : "SEMA", "type" : "functionBlock", "extensible" : False, 
       
   265                     "inputs" : [("CLAIM","BOOL","none"),("RELEASE","BOOL","none")], 
       
   266                     "outputs" : [("BUSY","BOOL","none")],
       
   267                     "comment" : _("Semaphore\nThe semaphore provides a mechanism to allow software elements mutually exclusive access to certain ressources."),
       
   268                     "generate" : generate_block, "initialise" : initialise_block},
       
   269                 {"name" : "R_TRIG", "type" : "functionBlock", "extensible" : False, 
       
   270                     "inputs" : [("CLK","BOOL","none")], 
       
   271                     "outputs" : [("Q","BOOL","none")],
       
   272                     "comment" : _("Rising edge detector\nThe output produces a single pulse when a rising edge is detected."),
       
   273                     "generate" : generate_block, "initialise" : initialise_block},
       
   274                 {"name" : "F_TRIG", "type" : "functionBlock", "extensible" : False, 
       
   275                     "inputs" : [("CLK","BOOL","none")], 
       
   276                     "outputs" : [("Q","BOOL","none")],
       
   277                     "comment" : _("Falling edge detector\nThe output produces a single pulse when a falling edge is detected."),
       
   278                     "generate" : generate_block, "initialise" : initialise_block},
       
   279                 {"name" : "CTU", "type" : "functionBlock", "extensible" : False, 
       
   280                     "inputs" : [("CU","BOOL","rising"),("R","BOOL","none"),("PV","INT","none")], 
       
   281                     "outputs" : [("Q","BOOL","none"),("CV","INT","none")],
       
   282                     "comment" : _("Up-counter\nThe up-counter can be used to signal when a count has reached a maximum value."),
       
   283                     "generate" : generate_block, "initialise" : initialise_block},
       
   284                 {"name" : "CTD", "type" : "functionBlock", "extensible" : False, 
       
   285                     "inputs" : [("CD","BOOL","rising"),("LD","BOOL","none"),("PV","INT","none")], 
       
   286                     "outputs" : [("Q","BOOL","none"),("CV","INT","none")],
       
   287                     "comment" : _("Down-counter\nThe down-counter can be used to signal when a count has reached zero, on counting down from a preset value."),
       
   288                     "generate" : generate_block, "initialise" : initialise_block},
       
   289                 {"name" : "CTUD", "type" : "functionBlock", "extensible" : False, 
       
   290                     "inputs" : [("CU","BOOL","rising"),("CD","BOOL","rising"),("R","BOOL","none"),("LD","BOOL","none"),("PV","INT","none")], 
       
   291                     "outputs" : [("QU","BOOL","none"),("QD","BOOL","none"),("CV","INT","none")],
       
   292                     "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 and down on the other."),
       
   293                     "generate" : generate_block, "initialise" : initialise_block},
       
   294                 {"name" : "TP", "type" : "functionBlock", "extensible" : False, 
       
   295                     "inputs" : [("IN","BOOL","none"),("PT","TIME","none")], 
       
   296                     "outputs" : [("Q","BOOL","none"),("ET","TIME","none")],
       
   297                     "comment" : _("Pulse timer\nThe pulse timer can be used to generate output pulses of a given time duration."),
       
   298                     "generate" : generate_block, "initialise" : initialise_block},
       
   299                 {"name" : "TON", "type" : "functionBlock", "extensible" : False, 
       
   300                     "inputs" : [("IN","BOOL","none"),("PT","TIME","none")], 
       
   301                     "outputs" : [("Q","BOOL","none"),("ET","TIME","none")],
       
   302                     "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."),
       
   303                     "generate" : generate_block, "initialise" : initialise_block},
       
   304                 {"name" : "TOF", "type" : "functionBlock", "extensible" : False, 
       
   305                     "inputs" : [("IN","BOOL","none"),("PT","TIME","none")], 
       
   306                     "outputs" : [("Q","BOOL","none"),("ET","TIME","none")],
       
   307                     "comment" : _("Off-delay timer\nThe off-delay timer can be used to delay setting an output false, for fixed period after input goes false."),
       
   308                     "generate" : generate_block, "initialise" : initialise_block},
       
   309                 ]},
       
   310               {"name" : _("Additional function blocks"), "list":
   102               {"name" : _("Additional function blocks"), "list":
   311                [{"name" : "RTC", "type" : "functionBlock", "extensible" : False, 
   103                [GetBlockInfos(pou) for pou in AddnlBlockLibrary.getpous()]},
   312                     "inputs" : [("IN","BOOL","none"),("PDT","DATE_AND_TIME","none")], 
       
   313                     "outputs" : [("Q","BOOL","none"),("CDT","DATE_AND_TIME","none")],
       
   314                     "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."),
       
   315                     "generate" : generate_block, "initialise" : initialise_block},
       
   316                 {"name" : "INTEGRAL", "type" : "functionBlock", "extensible" : False, 
       
   317                     "inputs" : [("RUN","BOOL","none"),("R1","BOOL","none"),("XIN","REAL","none"),("X0","REAL","none"),("CYCLE","TIME","none")], 
       
   318                     "outputs" : [("Q","BOOL","none"),("XOUT","REAL","none")],
       
   319                     "comment" : _("Integral\nThe integral function block integrates the value of input XIN over time."),
       
   320                     "generate" : generate_block, "initialise" : initialise_block},
       
   321                 {"name" : "DERIVATIVE", "type" : "functionBlock", "extensible" : False, 
       
   322                     "inputs" : [("RUN","BOOL","none"),("XIN","REAL","none"),("CYCLE","TIME","none")], 
       
   323                     "outputs" : [("XOUT","REAL","none")],
       
   324                     "comment" : _("Derivative\nThe derivative function block produces an output XOUT proportional to the rate of change of the input XIN."),
       
   325                     "generate" : generate_block, "initialise" : initialise_block},
       
   326                 {"name" : "PID", "type" : "functionBlock", "extensible" : False, 
       
   327                     "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")], 
       
   328                     "outputs" : [("XOUT","REAL","none")],
       
   329                     "comment" : _("PID\nThe PID (proportional, Integral, Derivative) function block provides the classical three term controller for closed loop control."),
       
   330                     "generate" : generate_block, "initialise" : initialise_block},
       
   331                 {"name" : "RAMP", "type" : "functionBlock", "extensible" : False, 
       
   332                     "inputs" : [("RUN","BOOL","none"),("X0","REAL","none"),("X1","REAL","none"),("TR","TIME","none"),("CYCLE","TIME","none")], 
       
   333                     "outputs" : [("BUSY","BOOL","none"),("XOUT","REAL","none")],
       
   334                     "comment" : _("Ramp\nThe RAMP function block is modelled on example given in the standard."),
       
   335                     "generate" : generate_block, "initialise" : initialise_block},
       
   336                 {"name" : "HYSTERESIS", "type" : "functionBlock", "extensible" : False, 
       
   337                     "inputs" : [("XIN1","REAL","none"),("XIN2","REAL","none"),("EPS","REAL","none")], 
       
   338                     "outputs" : [("Q","BOOL","none")],
       
   339                     "comment" : _("Hysteresis\nThe hysteresis function block provides a hysteresis boolean output driven by the difference of two floating point (REAL) inputs XIN1 and XIN2."),
       
   340                     "generate" : generate_block, "initialise" : initialise_block},
       
   341 ##                {"name" : "RATIO_MONITOR", "type" : "functionBlock", "extensible" : False, 
       
   342 ##                    "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")], 
       
   343 ##                    "outputs" : [("ALARM","BOOL","none"),("TOTAL_ERR","BOOL","none")],
       
   344 ##                    "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."),
       
   345 ##                    "generate" : generate_block, "initialise" : initialise_block}
       
   346                 ]},
       
   347              ]
   104              ]
   348 
   105 
   349 
   106 
   350 #-------------------------------------------------------------------------------
   107 #-------------------------------------------------------------------------------
   351 #                           Data Types definitions
   108 #                           Data Types definitions
   599                 Current_section = {"name" : section_name, "list" : []}
   356                 Current_section = {"name" : section_name, "list" : []}
   600                 Standard_Functions_Decl.append(Current_section)
   357                 Standard_Functions_Decl.append(Current_section)
   601                 Function_decl_list = []
   358                 Function_decl_list = []
   602             if Current_section:
   359             if Current_section:
   603                 Function_decl = dict([(champ, val) for champ, val in zip(fonctions, fields[1:]) if champ])
   360                 Function_decl = dict([(champ, val) for champ, val in zip(fonctions, fields[1:]) if champ])
   604                 Function_decl["generate"] = generate_block
       
   605                 Function_decl["initialise"] = lambda x,y:[]
       
   606                 baseinputnumber = int(Function_decl.get("baseinputnumber",1))
   361                 baseinputnumber = int(Function_decl.get("baseinputnumber",1))
   607                 Function_decl["baseinputnumber"] = baseinputnumber
   362                 Function_decl["baseinputnumber"] = baseinputnumber
   608                 for param, value in Function_decl.iteritems():
   363                 for param, value in Function_decl.iteritems():
   609                     if param in translate:
   364                     if param in translate:
   610                         Function_decl[param] = translate[param](value)
   365                         Function_decl[param] = translate[param](value)
   659             else:
   414             else:
   660                 raise "First function must be in a category"
   415                 raise "First function must be in a category"
   661     
   416     
   662     return Standard_Functions_Decl
   417     return Standard_Functions_Decl
   663 
   418 
   664 std_decl = get_standard_funtions(csv_file_to_table(open(os.path.join(os.path.split(__file__)[0],"iec_std.csv"))))#, True)
   419 std_decl = get_standard_funtions(csv_file_to_table(open(os.path.join(ScriptDirectory,"iec_std.csv"))))#, True)
   665 
   420 
   666 BlockTypes.extend(std_decl)
   421 StdBlckLst.extend(std_decl)
   667 
   422 
   668 for section in BlockTypes: 
   423 # Dictionary to speedup block type fetching by name
       
   424 StdBlckDct = OrderedDict()
       
   425 
       
   426 for section in StdBlckLst:
   669     for desc in section["list"]:
   427     for desc in section["list"]:
   670         words = desc["comment"].split('"')
   428         words = desc["comment"].split('"')
   671         if len(words) > 1:
   429         if len(words) > 1:
   672             desc["comment"] = words[1]
   430             desc["comment"] = words[1]
   673         desc["usage"] = (
   431         desc["usage"] = ("\n (%s) => (%s)" % 
   674             "\n (" +
   432             (", ".join(["%s:%s" % (input[1], input[0]) 
   675             str([ " " + fctdecl[1]+":"+fctdecl[0] for fctdecl in desc["inputs"]]).strip("[]").replace("'",'') +
   433                         for input in desc["inputs"]]),
   676             " ) => (" +
   434              ", ".join(["%s:%s" % (output[1], output[0]) 
   677             str([ " " + fctdecl[1]+":"+fctdecl[0] for fctdecl in desc["outputs"]]).strip("[]").replace("'",'') +
   435                         for output in desc["outputs"]])))
   678             " )")
   436         BlkLst = StdBlckDct.setdefault(desc["name"],[])
   679 
   437         BlkLst.append((section["name"], desc))
   680 
   438 
   681 #-------------------------------------------------------------------------------
   439 #-------------------------------------------------------------------------------
   682 #                            Languages Keywords
   440 #                            Languages Keywords
   683 #-------------------------------------------------------------------------------
   441 #-------------------------------------------------------------------------------
   684 
   442 
   685 
   443 
   686 # Keywords for Pou Declaration
   444 # Keywords for Pou Declaration
   687 POU_BLOCK_START_KEYWORDS = ["FUNCTION", "FUNCTION_BLOCK", "PROGRAM"]
   445 POU_BLOCK_START_KEYWORDS = ["FUNCTION", "FUNCTION_BLOCK", "PROGRAM"]
   688 POU_BLOCK_END_KEYWORDS = ["END_FUNCTION", "END_FUNCTION_BLOCK", "END_PROGRAM"]
   446 POU_BLOCK_END_KEYWORDS = ["END_FUNCTION", "END_FUNCTION_BLOCK", "END_PROGRAM"]
   689 POU_KEYWORDS = ["EN", "ENO", "F_EDGE", "R_EDGE"] + POU_BLOCK_START_KEYWORDS + POU_BLOCK_END_KEYWORDS
   447 POU_KEYWORDS = ["EN", "ENO", "F_EDGE", "R_EDGE"] + POU_BLOCK_START_KEYWORDS + POU_BLOCK_END_KEYWORDS
   690 for category in BlockTypes:
   448 for category in StdBlckLst:
   691     for block in category["list"]:
   449     for block in category["list"]:
   692         if block["name"] not in POU_KEYWORDS:
   450         if block["name"] not in POU_KEYWORDS:
   693             POU_KEYWORDS.append(block["name"])
   451             POU_KEYWORDS.append(block["name"])
   694 
   452 
   695 
   453