plcopen/structures.py
changeset 391 07447ee3538e
parent 373 db5f282946b0
child 404 d5a5eaea7844
equal deleted inserted replaced
390:020420ad8914 391:07447ee3538e
    30 LOCATIONDATATYPES = {"X" : ["BOOL"],
    30 LOCATIONDATATYPES = {"X" : ["BOOL"],
    31                      "B" : ["SINT", "USINT", "BYTE", "STRING"],
    31                      "B" : ["SINT", "USINT", "BYTE", "STRING"],
    32                      "W" : ["INT", "UINT", "WORD", "WSTRING"],
    32                      "W" : ["INT", "UINT", "WORD", "WSTRING"],
    33                      "D" : ["DINT", "UDINT", "REAL", "DWORD"],
    33                      "D" : ["DINT", "UDINT", "REAL", "DWORD"],
    34                      "L" : ["LINT", "ULINT", "LREAL", "LWORD"]} 
    34                      "L" : ["LINT", "ULINT", "LREAL", "LWORD"]} 
       
    35 
       
    36 _ = lambda x:x
    35 
    37 
    36 # Helper for emulate join on element list
    38 # Helper for emulate join on element list
    37 def JoinList(separator, mylist):
    39 def JoinList(separator, mylist):
    38     if len(mylist) > 0 :
    40     if len(mylist) > 0 :
    39         return reduce(lambda x, y: x + separator + y, mylist)
    41         return reduce(lambda x, y: x + separator + y, mylist)
    90                                       (type, (generator.TagName, "block", block.getlocalId(), "type")),
    92                                       (type, (generator.TagName, "block", block.getlocalId(), "type")),
    91                                       ("(", ())]
    93                                       ("(", ())]
    92                 generator.Program += JoinList([(", ", ())], vars)
    94                 generator.Program += JoinList([(", ", ())], vars)
    93                 generator.Program += [(");\n", ())]
    95                 generator.Program += [(");\n", ())]
    94             else:
    96             else:
    95                 generator.Warnings.append("\"%s\" function cancelled in \"%s\" POU: No input connected"%(type, generator.TagName.split("::")[-1]))
    97                 generator.Warnings.append(_("\"%s\" function cancelled in \"%s\" POU: No input connected")%(type, generator.TagName.split("::")[-1]))
    96         if link:
    98         if link:
    97             connectionPoint = link.getposition()[-1]
    99             connectionPoint = link.getposition()[-1]
    98         else:
   100         else:
    99             connectionPoint = None
   101             connectionPoint = None
   100         for i, variable in enumerate(output_variables):
   102         for i, variable in enumerate(output_variables):
   132             blockPointx, blockPointy = variable.connectionPointOut.getrelPositionXY()
   134             blockPointx, blockPointy = variable.connectionPointOut.getrelPositionXY()
   133             if not connectionPoint or block.getx() + blockPointx == connectionPoint.getx() and block.gety() + blockPointy == connectionPoint.gety():
   135             if not connectionPoint or block.getx() + blockPointx == connectionPoint.getx() and block.gety() + blockPointy == connectionPoint.gety():
   134                 output_info = (generator.TagName, "block", block.getlocalId(), "output", i)
   136                 output_info = (generator.TagName, "block", block.getlocalId(), "output", i)
   135                 return generator.ExtractModifier(variable, [("%s.%s"%(name, variable.getformalParameter()), output_info)], output_info)
   137                 return generator.ExtractModifier(variable, [("%s.%s"%(name, variable.getformalParameter()), output_info)], output_info)
   136     if link is not None:
   138     if link is not None:
   137         raise ValueError, "No output variable found"
   139         raise ValueError, _("No output variable found")
   138 
   140 
   139 def initialise_block(type, name, block = None):
   141 def initialise_block(type, name, block = None):
   140     return [(type, name, None, None)]
   142     return [(type, name, None, None)]
   141 
   143 
   142 #-------------------------------------------------------------------------------
   144 #-------------------------------------------------------------------------------
   158     - The name
   160     - The name
   159     - The data type
   161     - The data type
   160     - The default modifier which can be "none", "negated", "rising" or "falling"
   162     - The default modifier which can be "none", "negated", "rising" or "falling"
   161 """
   163 """
   162 
   164 
   163 BlockTypes = [{"name" : "Standard function blocks", "list":
   165 BlockTypes = [{"name" : _("Standard function blocks"), "list":
   164                [{"name" : "SR", "type" : "functionBlock", "extensible" : False, 
   166                [{"name" : "SR", "type" : "functionBlock", "extensible" : False, 
   165                     "inputs" : [("S1","BOOL","none"),("R","BOOL","none")], 
   167                     "inputs" : [("S1","BOOL","none"),("R","BOOL","none")], 
   166                     "outputs" : [("Q1","BOOL","none")],
   168                     "outputs" : [("Q1","BOOL","none")],
   167                     "comment" : "SR bistable\nThe SR bistable is a latch where the Set dominates.",
   169                     "comment" : _("SR bistable\nThe SR bistable is a latch where the Set dominates."),
   168                     "generate" : generate_block, "initialise" : initialise_block},
   170                     "generate" : generate_block, "initialise" : initialise_block},
   169                 {"name" : "RS", "type" : "functionBlock", "extensible" : False, 
   171                 {"name" : "RS", "type" : "functionBlock", "extensible" : False, 
   170                     "inputs" : [("S","BOOL","none"),("R1","BOOL","none")], 
   172                     "inputs" : [("S","BOOL","none"),("R1","BOOL","none")], 
   171                     "outputs" : [("Q1","BOOL","none")],
   173                     "outputs" : [("Q1","BOOL","none")],
   172                     "comment" : "RS bistable\nThe RS bistable is a latch where the Reset dominates.",
   174                     "comment" : _("RS bistable\nThe RS bistable is a latch where the Reset dominates."),
   173                     "generate" : generate_block, "initialise" : initialise_block},
   175                     "generate" : generate_block, "initialise" : initialise_block},
   174                 {"name" : "SEMA", "type" : "functionBlock", "extensible" : False, 
   176                 {"name" : "SEMA", "type" : "functionBlock", "extensible" : False, 
   175                     "inputs" : [("CLAIM","BOOL","none"),("RELEASE","BOOL","none")], 
   177                     "inputs" : [("CLAIM","BOOL","none"),("RELEASE","BOOL","none")], 
   176                     "outputs" : [("BUSY","BOOL","none")],
   178                     "outputs" : [("BUSY","BOOL","none")],
   177                     "comment" : "Semaphore\nThe semaphore provides a mechanism to allow software elements mutually exclusive access to certain ressources.",
   179                     "comment" : _("Semaphore\nThe semaphore provides a mechanism to allow software elements mutually exclusive access to certain ressources."),
   178                     "generate" : generate_block, "initialise" : initialise_block},
   180                     "generate" : generate_block, "initialise" : initialise_block},
   179                 {"name" : "R_TRIG", "type" : "functionBlock", "extensible" : False, 
   181                 {"name" : "R_TRIG", "type" : "functionBlock", "extensible" : False, 
   180                     "inputs" : [("CLK","BOOL","none")], 
   182                     "inputs" : [("CLK","BOOL","none")], 
   181                     "outputs" : [("Q","BOOL","none")],
   183                     "outputs" : [("Q","BOOL","none")],
   182                     "comment" : "Rising edge detector\nThe output produces a single pulse when a rising edge is detected.",
   184                     "comment" : _("Rising edge detector\nThe output produces a single pulse when a rising edge is detected."),
   183                     "generate" : generate_block, "initialise" : initialise_block},
   185                     "generate" : generate_block, "initialise" : initialise_block},
   184                 {"name" : "F_TRIG", "type" : "functionBlock", "extensible" : False, 
   186                 {"name" : "F_TRIG", "type" : "functionBlock", "extensible" : False, 
   185                     "inputs" : [("CLK","BOOL","none")], 
   187                     "inputs" : [("CLK","BOOL","none")], 
   186                     "outputs" : [("Q","BOOL","none")],
   188                     "outputs" : [("Q","BOOL","none")],
   187                     "comment" : "Falling edge detector\nThe output produces a single pulse when a falling edge is detected.",
   189                     "comment" : _("Falling edge detector\nThe output produces a single pulse when a falling edge is detected."),
   188                     "generate" : generate_block, "initialise" : initialise_block},
   190                     "generate" : generate_block, "initialise" : initialise_block},
   189                 {"name" : "CTU", "type" : "functionBlock", "extensible" : False, 
   191                 {"name" : "CTU", "type" : "functionBlock", "extensible" : False, 
   190                     "inputs" : [("CU","BOOL","rising"),("R","BOOL","none"),("PV","INT","none")], 
   192                     "inputs" : [("CU","BOOL","rising"),("R","BOOL","none"),("PV","INT","none")], 
   191                     "outputs" : [("Q","BOOL","none"),("CV","INT","none")],
   193                     "outputs" : [("Q","BOOL","none"),("CV","INT","none")],
   192                     "comment" : "Up-counter\nThe up-counter can be used to signal when a count has reached a maximum value.",
   194                     "comment" : _("Up-counter\nThe up-counter can be used to signal when a count has reached a maximum value."),
   193                     "generate" : generate_block, "initialise" : initialise_block},
   195                     "generate" : generate_block, "initialise" : initialise_block},
   194                 {"name" : "CTD", "type" : "functionBlock", "extensible" : False, 
   196                 {"name" : "CTD", "type" : "functionBlock", "extensible" : False, 
   195                     "inputs" : [("CD","BOOL","rising"),("LD","BOOL","none"),("PV","INT","none")], 
   197                     "inputs" : [("CD","BOOL","rising"),("LD","BOOL","none"),("PV","INT","none")], 
   196                     "outputs" : [("Q","BOOL","none"),("CV","INT","none")],
   198                     "outputs" : [("Q","BOOL","none"),("CV","INT","none")],
   197                     "comment" : "Down-counter\nThe down-counter can be used to signal when a count has reached zero, on counting down from a preset value.",
   199                     "comment" : _("Down-counter\nThe down-counter can be used to signal when a count has reached zero, on counting down from a preset value."),
   198                     "generate" : generate_block, "initialise" : initialise_block},
   200                     "generate" : generate_block, "initialise" : initialise_block},
   199                 {"name" : "CTUD", "type" : "functionBlock", "extensible" : False, 
   201                 {"name" : "CTUD", "type" : "functionBlock", "extensible" : False, 
   200                     "inputs" : [("CU","BOOL","rising"),("CD","BOOL","rising"),("R","BOOL","none"),("LD","BOOL","none"),("PV","INT","none")], 
   202                     "inputs" : [("CU","BOOL","rising"),("CD","BOOL","rising"),("R","BOOL","none"),("LD","BOOL","none"),("PV","INT","none")], 
   201                     "outputs" : [("QU","BOOL","none"),("QD","BOOL","none"),("CV","INT","none")],
   203                     "outputs" : [("QU","BOOL","none"),("QD","BOOL","none"),("CV","INT","none")],
   202                     "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.",
   204                     "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."),
   203                     "generate" : generate_block, "initialise" : initialise_block},
   205                     "generate" : generate_block, "initialise" : initialise_block},
   204                 {"name" : "TP", "type" : "functionBlock", "extensible" : False, 
   206                 {"name" : "TP", "type" : "functionBlock", "extensible" : False, 
   205                     "inputs" : [("IN","BOOL","none"),("PT","TIME","none")], 
   207                     "inputs" : [("IN","BOOL","none"),("PT","TIME","none")], 
   206                     "outputs" : [("Q","BOOL","none"),("ET","TIME","none")],
   208                     "outputs" : [("Q","BOOL","none"),("ET","TIME","none")],
   207                     "comment" : "Pulse timer\nThe pulse timer can be used to generate output pulses of a given time duration.",
   209                     "comment" : _("Pulse timer\nThe pulse timer can be used to generate output pulses of a given time duration."),
   208                     "generate" : generate_block, "initialise" : initialise_block},
   210                     "generate" : generate_block, "initialise" : initialise_block},
   209                 {"name" : "TON", "type" : "functionBlock", "extensible" : False, 
   211                 {"name" : "TON", "type" : "functionBlock", "extensible" : False, 
   210                     "inputs" : [("IN","BOOL","none"),("PT","TIME","none")], 
   212                     "inputs" : [("IN","BOOL","none"),("PT","TIME","none")], 
   211                     "outputs" : [("Q","BOOL","none"),("ET","TIME","none")],
   213                     "outputs" : [("Q","BOOL","none"),("ET","TIME","none")],
   212                     "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.",
   214                     "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."),
   213                     "generate" : generate_block, "initialise" : initialise_block},
   215                     "generate" : generate_block, "initialise" : initialise_block},
   214                 {"name" : "TOF", "type" : "functionBlock", "extensible" : False, 
   216                 {"name" : "TOF", "type" : "functionBlock", "extensible" : False, 
   215                     "inputs" : [("IN","BOOL","none"),("PT","TIME","none")], 
   217                     "inputs" : [("IN","BOOL","none"),("PT","TIME","none")], 
   216                     "outputs" : [("Q","BOOL","none"),("ET","TIME","none")],
   218                     "outputs" : [("Q","BOOL","none"),("ET","TIME","none")],
   217                     "comment" : "Off-delay timer\nThe off-delay timer can be used to delay setting an output false, for fixed period after input goes false.",
   219                     "comment" : _("Off-delay timer\nThe off-delay timer can be used to delay setting an output false, for fixed period after input goes false."),
   218                     "generate" : generate_block, "initialise" : initialise_block},
   220                     "generate" : generate_block, "initialise" : initialise_block},
   219                 ]},
   221                 ]},
   220               {"name" : "Additionnal function blocks", "list":
   222               {"name" : _("Additionnal function blocks"), "list":
   221 ##                {"name" : "RTC", "type" : "functionBlock", "extensible" : False, 
   223 ##                {"name" : "RTC", "type" : "functionBlock", "extensible" : False, 
   222 ##                    "inputs" : [("EN","BOOL","none"),("PDT","DATE_AND_TIME","none")], 
   224 ##                    "inputs" : [("EN","BOOL","none"),("PDT","DATE_AND_TIME","none")], 
   223 ##                    "outputs" : [("Q","BOOL","none"),("CDT","DATE_AND_TIME","none")],
   225 ##                    "outputs" : [("Q","BOOL","none"),("CDT","DATE_AND_TIME","none")],
   224 ##                    "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.",
   226 ##                    "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."),
   225 ##                    "generate" : generate_block, "initialise" : initialise_block},
   227 ##                    "generate" : generate_block, "initialise" : initialise_block},
   226                [{"name" : "INTEGRAL", "type" : "functionBlock", "extensible" : False, 
   228                [{"name" : "INTEGRAL", "type" : "functionBlock", "extensible" : False, 
   227                     "inputs" : [("RUN","BOOL","none"),("R1","BOOL","none"),("XIN","REAL","none"),("X0","REAL","none"),("CYCLE","TIME","none")], 
   229                     "inputs" : [("RUN","BOOL","none"),("R1","BOOL","none"),("XIN","REAL","none"),("X0","REAL","none"),("CYCLE","TIME","none")], 
   228                     "outputs" : [("Q","BOOL","none"),("XOUT","REAL","none")],
   230                     "outputs" : [("Q","BOOL","none"),("XOUT","REAL","none")],
   229                     "comment" : "Integral\nThe integral function block integrates the value of input XIN over time.",
   231                     "comment" : _("Integral\nThe integral function block integrates the value of input XIN over time."),
   230                     "generate" : generate_block, "initialise" : initialise_block},
   232                     "generate" : generate_block, "initialise" : initialise_block},
   231                 {"name" : "DERIVATIVE", "type" : "functionBlock", "extensible" : False, 
   233                 {"name" : "DERIVATIVE", "type" : "functionBlock", "extensible" : False, 
   232                     "inputs" : [("RUN","BOOL","none"),("XIN","REAL","none"),("CYCLE","TIME","none")], 
   234                     "inputs" : [("RUN","BOOL","none"),("XIN","REAL","none"),("CYCLE","TIME","none")], 
   233                     "outputs" : [("XOUT","REAL","none")],
   235                     "outputs" : [("XOUT","REAL","none")],
   234                     "comment" : "Derivative\nThe derivative function block produces an output XOUT proportional to the rate of change of the input XIN.",
   236                     "comment" : _("Derivative\nThe derivative function block produces an output XOUT proportional to the rate of change of the input XIN."),
   235                     "generate" : generate_block, "initialise" : initialise_block},
   237                     "generate" : generate_block, "initialise" : initialise_block},
   236                 {"name" : "PID", "type" : "functionBlock", "extensible" : False, 
   238                 {"name" : "PID", "type" : "functionBlock", "extensible" : False, 
   237                     "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")], 
   239                     "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")], 
   238                     "outputs" : [("XOUT","REAL","none")],
   240                     "outputs" : [("XOUT","REAL","none")],
   239                     "comment" : "PID\nThe PID (proportional, Integral, Derivative) function block provides the classical three term controller for closed loop control.",
   241                     "comment" : _("PID\nThe PID (proportional, Integral, Derivative) function block provides the classical three term controller for closed loop control."),
   240                     "generate" : generate_block, "initialise" : initialise_block},
   242                     "generate" : generate_block, "initialise" : initialise_block},
   241                 {"name" : "RAMP", "type" : "functionBlock", "extensible" : False, 
   243                 {"name" : "RAMP", "type" : "functionBlock", "extensible" : False, 
   242                     "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")], 
   244                     "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")], 
   243                     "outputs" : [("RAMP","BOOL","none"),("XOUT","REAL","none")],
   245                     "outputs" : [("RAMP","BOOL","none"),("XOUT","REAL","none")],
   244                     "comment" : "Ramp\nThe RAMP function block is modelled on example given in the standard but with the addition of a 'Holdback' feature.",
   246                     "comment" : _("Ramp\nThe RAMP function block is modelled on example given in the standard but with the addition of a 'Holdback' feature."),
   245                     "generate" : generate_block, "initialise" : initialise_block},
   247                     "generate" : generate_block, "initialise" : initialise_block},
   246                 {"name" : "HYSTERESIS", "type" : "functionBlock", "extensible" : False, 
   248                 {"name" : "HYSTERESIS", "type" : "functionBlock", "extensible" : False, 
   247                     "inputs" : [("XIN1","REAL","none"),("XIN2","REAL","none"),("EPS","REAL","none")], 
   249                     "inputs" : [("XIN1","REAL","none"),("XIN2","REAL","none"),("EPS","REAL","none")], 
   248                     "outputs" : [("Q","BOOL","none")],
   250                     "outputs" : [("Q","BOOL","none")],
   249                     "comment" : "Hysteresis\nThe hysteresis function block provides a hysteresis boolean output driven by the difference of two floating point (REAL) inputs XIN1 and XIN2.",
   251                     "comment" : _("Hysteresis\nThe hysteresis function block provides a hysteresis boolean output driven by the difference of two floating point (REAL) inputs XIN1 and XIN2."),
   250                     "generate" : generate_block, "initialise" : initialise_block},
   252                     "generate" : generate_block, "initialise" : initialise_block},
   251 ##                {"name" : "RATIO_MONITOR", "type" : "functionBlock", "extensible" : False, 
   253 ##                {"name" : "RATIO_MONITOR", "type" : "functionBlock", "extensible" : False, 
   252 ##                    "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")], 
   254 ##                    "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")], 
   253 ##                    "outputs" : [("ALARM","BOOL","none"),("TOTAL_ERR","BOOL","none")],
   255 ##                    "outputs" : [("ALARM","BOOL","none"),("TOTAL_ERR","BOOL","none")],
   254 ##                    "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.",
   256 ##                    "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."),
   255 ##                    "generate" : generate_block, "initialise" : initialise_block}
   257 ##                    "generate" : generate_block, "initialise" : initialise_block}
   256                 ]},
   258                 ]},
   257              ]
   259              ]
   258 
   260 
   259 
   261 
   501     
   503     
   502     for fields in table:
   504     for fields in table:
   503         if fields[1]:
   505         if fields[1]:
   504             # If function section name given
   506             # If function section name given
   505             if fields[0]:
   507             if fields[0]:
   506                 Current_section = {"name" : fields[0], "list" : []}
   508                 words = fields[0].split('"')
       
   509                 if len(words) > 1:
       
   510                     section_name = words[1]
       
   511                 else:
       
   512                     section_name = fields[0]
       
   513                 Current_section = {"name" : section_name, "list" : []}
   507                 Standard_Functions_Decl.append(Current_section)
   514                 Standard_Functions_Decl.append(Current_section)
   508                 Function_decl_list = []
   515                 Function_decl_list = []
   509             if Current_section:
   516             if Current_section:
   510                 Function_decl = dict([(champ, val) for champ, val in zip(fonctions, fields[1:]) if champ])
   517                 Function_decl = dict([(champ, val) for champ, val in zip(fonctions, fields[1:]) if champ])
   511                 Function_decl["generate"] = generate_block
   518                 Function_decl["generate"] = generate_block
   561 
   568 
   562                         if res != None :
   569                         if res != None :
   563                             # create the copy of decl dict to be appended to section
   570                             # create the copy of decl dict to be appended to section
   564                             Function_decl_copy = Function_decl.copy()
   571                             Function_decl_copy = Function_decl.copy()
   565                             # Have to generate type description in comment with freshly redefined types
   572                             # Have to generate type description in comment with freshly redefined types
   566                             Function_decl_copy["comment"] += (
   573                             words = Function_decl_copy["comment"].split('"')
       
   574                             if len(words) > 1:
       
   575                                 Function_decl_copy["comment"] = words[1]
       
   576                             Function_decl_copy["usage"] = (
   567                                 "\n (" +
   577                                 "\n (" +
   568                                 str([ " " + fctdecl[1]+":"+fctdecl[0] for fctdecl in Function_decl["inputs"]]).strip("[]").replace("'",'') +
   578                                 str([ " " + fctdecl[1]+":"+fctdecl[0] for fctdecl in Function_decl["inputs"]]).strip("[]").replace("'",'') +
   569                                 " ) => (" +
   579                                 " ) => (" +
   570                                 str([ " " + fctdecl[1]+":"+fctdecl[0] for fctdecl in Function_decl["outputs"]]).strip("[]").replace("'",'') +
   580                                 str([ " " + fctdecl[1]+":"+fctdecl[0] for fctdecl in Function_decl["outputs"]]).strip("[]").replace("'",'') +
   571                                 " )")
   581                                 " )")