plcopen/structures.py
changeset 1390 0f4d32a033e0
parent 1330 96b242e4c59d
child 1571 486f94a8032c
equal deleted inserted replaced
1389:fb19c6226ff5 1390:0f4d32a033e0
    20 #
    20 #
    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, re
    26 from plcopen import LoadProject
    26 from plcopen import LoadProject
    27 from collections import OrderedDict
    27 from collections import OrderedDict
    28 
    28 from definitions import *
    29 LANGUAGES = ["IL","ST","FBD","LD","SFC"]
    29 
    30 
    30 TypeHierarchy = dict(TypeHierarchy_list)
    31 LOCATIONDATATYPES = {"X" : ["BOOL"],
    31 
    32                      "B" : ["SINT", "USINT", "BYTE", "STRING"],
    32 """
    33                      "W" : ["INT", "UINT", "WORD", "WSTRING"],
    33 returns true if the given data type is the same that "reference" meta-type or one of its types.
    34                      "D" : ["DINT", "UDINT", "REAL", "DWORD"],
    34 """
    35                      "L" : ["LINT", "ULINT", "LREAL", "LWORD"]} 
    35 def IsOfType(type, reference):
    36 
    36     if reference is None:
    37 _ = lambda x:x
    37         return True
    38 
    38     elif type == reference:
    39 #-------------------------------------------------------------------------------
    39         return True
    40 #                        Function Block Types definitions
    40     else:
    41 #-------------------------------------------------------------------------------
    41         parent_type = TypeHierarchy[type]
    42 
    42         if parent_type is not None:
    43 ScriptDirectory = os.path.split(os.path.realpath(__file__))[0]
    43             return IsOfType(parent_type, reference)
    44 
    44     return False
    45 StdBlockLibrary, error = LoadProject(
    45 
    46     os.path.join(ScriptDirectory, "Standard_Function_Blocks.xml"))
    46 """
    47 AddnlBlockLibrary, error = LoadProject(
    47 returns list of all types that correspont to the ANY* meta type
    48     os.path.join(ScriptDirectory, "Additional_Function_Blocks.xml"))
    48 """
    49 
    49 def GetSubTypes(type):
    50 StdBlockComments = {
    50     return [typename for typename, parenttype in TypeHierarchy.items() if not typename.startswith("ANY") and IsOfType(typename, type)]
    51     "SR": _("SR bistable\nThe SR bistable is a latch where the Set dominates."),
    51 
    52     "RS": _("RS bistable\nThe RS bistable is a latch where the Reset dominates."),
    52 DataTypeRange = dict(DataTypeRange_list)
    53     "SEMA": _("Semaphore\nThe semaphore provides a mechanism to allow software elements mutually exclusive access to certain ressources."),
    53 
    54     "R_TRIG": _("Rising edge detector\nThe output produces a single pulse when a rising edge is detected."),
    54 """
    55     "F_TRIG": _("Falling edge detector\nThe output produces a single pulse when a falling edge is detected."),
    55 Ordered list of common Function Blocks defined in the IEC 61131-3
    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
       
    83 
       
    84 """
       
    85 Ordored list of common Function Blocks defined in the IEC 61131-3
       
    86 Each block have this attributes:
    56 Each block have this attributes:
    87     - "name" : The block name
    57     - "name" : The block name
    88     - "type" : The block type. It can be "function", "functionBlock" or "program"
    58     - "type" : The block type. It can be "function", "functionBlock" or "program"
    89     - "extensible" : Boolean that define if the block is extensible
    59     - "extensible" : Boolean that define if the block is extensible
    90     - "inputs" : List of the block inputs
    60     - "inputs" : List of the block inputs
    95     - The name
    65     - The name
    96     - The data type
    66     - The data type
    97     - The default modifier which can be "none", "negated", "rising" or "falling"
    67     - The default modifier which can be "none", "negated", "rising" or "falling"
    98 """
    68 """
    99 
    69 
   100 StdBlckLst = [{"name" : _("Standard function blocks"), "list":
    70 StdBlckLibs = {libname : LoadProject(tc6fname)[0]
   101                [GetBlockInfos(pou) for pou in StdBlockLibrary.getpous()]},
    71              for libname, tc6fname in StdTC6Libs}
   102               {"name" : _("Additional function blocks"), "list":
    72 StdBlckLst = [{"name" : libname, "list":
   103                [GetBlockInfos(pou) for pou in AddnlBlockLibrary.getpous()]},
    73                [GetBlockInfos(pous) for pous in lib.getpous()]}
   104              ]
    74              for libname, lib in StdBlckLibs.iteritems()]
   105 
       
   106 
       
   107 #-------------------------------------------------------------------------------
       
   108 #                           Data Types definitions
       
   109 #-------------------------------------------------------------------------------
       
   110 
       
   111 """
       
   112 Ordored list of common data types defined in the IEC 61131-3
       
   113 Each type is associated to his direct parent type. It defines then a hierarchy
       
   114 between type that permits to make a comparison of two types
       
   115 """
       
   116 TypeHierarchy_list = [
       
   117     ("ANY", None),
       
   118     ("ANY_DERIVED", "ANY"),
       
   119     ("ANY_ELEMENTARY", "ANY"),
       
   120     ("ANY_MAGNITUDE", "ANY_ELEMENTARY"),
       
   121     ("ANY_BIT", "ANY_ELEMENTARY"),
       
   122     ("ANY_NBIT", "ANY_BIT"),
       
   123     ("ANY_STRING", "ANY_ELEMENTARY"),
       
   124     ("ANY_DATE", "ANY_ELEMENTARY"),
       
   125     ("ANY_NUM", "ANY_MAGNITUDE"),
       
   126     ("ANY_REAL", "ANY_NUM"),
       
   127     ("ANY_INT", "ANY_NUM"),
       
   128     ("ANY_SINT", "ANY_INT"),
       
   129     ("ANY_UINT", "ANY_INT"),
       
   130     ("BOOL", "ANY_BIT"),
       
   131     ("SINT", "ANY_SINT"),
       
   132     ("INT", "ANY_SINT"),
       
   133     ("DINT", "ANY_SINT"),
       
   134     ("LINT", "ANY_SINT"),
       
   135     ("USINT", "ANY_UINT"),
       
   136     ("UINT", "ANY_UINT"),
       
   137     ("UDINT", "ANY_UINT"),
       
   138     ("ULINT", "ANY_UINT"),
       
   139     ("REAL", "ANY_REAL"),
       
   140     ("LREAL", "ANY_REAL"),
       
   141     ("TIME", "ANY_MAGNITUDE"),
       
   142     ("DATE", "ANY_DATE"),
       
   143     ("TOD", "ANY_DATE"),
       
   144     ("DT", "ANY_DATE"),
       
   145     ("STRING", "ANY_STRING"),
       
   146     ("BYTE", "ANY_NBIT"),
       
   147     ("WORD", "ANY_NBIT"),
       
   148     ("DWORD", "ANY_NBIT"),
       
   149     ("LWORD", "ANY_NBIT")
       
   150     #("WSTRING", "ANY_STRING") # TODO
       
   151 ]
       
   152 
       
   153 TypeHierarchy = dict(TypeHierarchy_list)
       
   154 
       
   155 """
       
   156 returns true if the given data type is the same that "reference" meta-type or one of its types.
       
   157 """
       
   158 def IsOfType(type, reference):
       
   159     if reference is None:
       
   160         return True
       
   161     elif type == reference:
       
   162         return True
       
   163     else:
       
   164         parent_type = TypeHierarchy[type]
       
   165         if parent_type is not None:
       
   166             return IsOfType(parent_type, reference)
       
   167     return False
       
   168 
       
   169 """
       
   170 returns list of all types that correspont to the ANY* meta type
       
   171 """
       
   172 def GetSubTypes(type):
       
   173     return [typename for typename, parenttype in TypeHierarchy.items() if not typename.startswith("ANY") and IsOfType(typename, type)]
       
   174 
       
   175 
       
   176 DataTypeRange_list = [
       
   177     ("SINT", (-2**7, 2**7 - 1)),
       
   178     ("INT", (-2**15, 2**15 - 1)),
       
   179     ("DINT", (-2**31, 2**31 - 1)),
       
   180     ("LINT", (-2**31, 2**31 - 1)),
       
   181     ("USINT", (0, 2**8 - 1)),
       
   182     ("UINT", (0, 2**16 - 1)),
       
   183     ("UDINT", (0, 2**31 - 1)),
       
   184     ("ULINT", (0, 2**31 - 1))
       
   185 ]
       
   186 
       
   187 DataTypeRange = dict(DataTypeRange_list)
       
   188 
       
   189 
       
   190 
    75 
   191 #-------------------------------------------------------------------------------
    76 #-------------------------------------------------------------------------------
   192 #                             Test identifier
    77 #                             Test identifier
   193 #-------------------------------------------------------------------------------
    78 #-------------------------------------------------------------------------------
   194 
    79 
   255             base += 1
   140             base += 1
   256         else:
   141         else:
   257             param_name = "IN"
   142             param_name = "IN"
   258         params.append((param_name, param_type, "none"))
   143         params.append((param_name, param_type, "none"))
   259     return params
   144     return params
   260 
       
   261 
       
   262 ANY_TO_ANY_LIST=[
       
   263         # simple type conv are let as C cast
       
   264         (("ANY_INT","ANY_BIT"),("ANY_NUM","ANY_BIT"), ("return_type", "__move_", "IN_type")),
       
   265         (("ANY_REAL",),("ANY_REAL",), ("return_type", "__move_", "IN_type")),
       
   266         # REAL_TO_INT
       
   267         (("ANY_REAL",),("ANY_SINT",), ("return_type", "__real_to_sint", None)),
       
   268         (("ANY_REAL",),("ANY_UINT",), ("return_type", "__real_to_uint", None)),
       
   269         (("ANY_REAL",),("ANY_BIT",), ("return_type", "__real_to_bit", None)),
       
   270         # TO_TIME
       
   271         (("ANY_INT","ANY_BIT"),("ANY_DATE","TIME"), ("return_type", "__int_to_time", None)),
       
   272         (("ANY_REAL",),("ANY_DATE","TIME"), ("return_type", "__real_to_time", None)),
       
   273         (("ANY_STRING",), ("ANY_DATE","TIME"), ("return_type", "__string_to_time", None)),
       
   274         # FROM_TIME
       
   275         (("ANY_DATE","TIME"), ("ANY_REAL",), ("return_type", "__time_to_real", None)),
       
   276         (("ANY_DATE","TIME"), ("ANY_INT","ANY_NBIT"), ("return_type", "__time_to_int", None)),
       
   277         (("TIME",), ("ANY_STRING",), ("return_type", "__time_to_string", None)),
       
   278         (("DATE",), ("ANY_STRING",), ("return_type", "__date_to_string", None)),
       
   279         (("TOD",), ("ANY_STRING",), ("return_type", "__tod_to_string", None)),
       
   280         (("DT",), ("ANY_STRING",), ("return_type", "__dt_to_string", None)),
       
   281         # TO_STRING
       
   282         (("BOOL",), ("ANY_STRING",), ("return_type", "__bool_to_string", None)),
       
   283         (("ANY_BIT",), ("ANY_STRING",), ("return_type", "__bit_to_string", None)),
       
   284         (("ANY_REAL",), ("ANY_STRING",), ("return_type", "__real_to_string", None)),
       
   285         (("ANY_SINT",), ("ANY_STRING",), ("return_type", "__sint_to_string", None)),
       
   286         (("ANY_UINT",), ("ANY_STRING",), ("return_type", "__uint_to_string", None)),
       
   287         # FROM_STRING
       
   288         (("ANY_STRING",), ("BOOL",), ("return_type", "__string_to_bool", None)),
       
   289         (("ANY_STRING",), ("ANY_BIT",), ("return_type", "__string_to_bit", None)),
       
   290         (("ANY_STRING",), ("ANY_SINT",), ("return_type", "__string_to_sint", None)),
       
   291         (("ANY_STRING",), ("ANY_UINT",), ("return_type", "__string_to_uint", None)),
       
   292         (("ANY_STRING",), ("ANY_REAL",), ("return_type", "__string_to_real", None))]
       
   293 
       
   294 
       
   295 BCD_TO_ANY_LIST=[
       
   296         (("BYTE",),("USINT",), ("return_type", "__bcd_to_uint", None)),
       
   297         (("WORD",),("UINT",), ("return_type", "__bcd_to_uint", None)),
       
   298         (("DWORD",),("UDINT",), ("return_type", "__bcd_to_uint", None)),
       
   299         (("LWORD",),("ULINT",), ("return_type", "__bcd_to_uint", None))]
       
   300 
       
   301 
       
   302 ANY_TO_BCD_LIST=[
       
   303         (("USINT",),("BYTE",), ("return_type", "__uint_to_bcd", None)),
       
   304         (("UINT",),("WORD",), ("return_type", "__uint_to_bcd", None)),
       
   305         (("UDINT",),("DWORD",), ("return_type", "__uint_to_bcd", None)),
       
   306         (("ULINT",),("LWORD",), ("return_type", "__uint_to_bcd", None))]
       
   307 
       
   308 
       
   309 def ANY_TO_ANY_FORMAT_GEN(any_to_any_list, fdecl):
       
   310 
       
   311     for (InTypes, OutTypes, Format) in any_to_any_list:
       
   312         outs = reduce(lambda a,b: a or b, map(lambda testtype : IsOfType(fdecl["outputs"][0][1],testtype), OutTypes))
       
   313         inps = reduce(lambda a,b: a or b, map(lambda testtype : IsOfType(fdecl["inputs"][0][1],testtype), InTypes))
       
   314         if inps and outs and fdecl["outputs"][0][1] != fdecl["inputs"][0][1]:
       
   315              return Format
       
   316     
       
   317     return None
       
   318 
   145 
   319 
   146 
   320 """
   147 """
   321 Returns this kind of declaration for all standard functions
   148 Returns this kind of declaration for all standard functions
   322 
   149 
   401                                 funcdeclout =  funcdeclin
   228                                 funcdeclout =  funcdeclin
   402                         else:
   229                         else:
   403                             funcdeclout =  funcdeclin
   230                             funcdeclout =  funcdeclin
   404                         Function_decl["name"] = funcdeclout
   231                         Function_decl["name"] = funcdeclout
   405 
   232 
   406 
   233                         # apply filter given in "filter" column
   407                         fdecl = Function_decl
   234                         filter_name = Function_decl["filter"]
   408                         res = eval(Function_decl["python_eval_c_code_format"])
   235                         store = True
   409 
   236                         for (InTypes, OutTypes) in ANY_TO_ANY_FILTERS.get(filter_name,[]):
   410                         if res != None :
   237                             outs = reduce(lambda a,b: a or b, 
       
   238                                        map(lambda testtype : IsOfType(
       
   239                                            Function_decl["outputs"][0][1],
       
   240                                            testtype), OutTypes))
       
   241                             inps = reduce(lambda a,b: a or b,
       
   242                                        map(lambda testtype : IsOfType(
       
   243                                            Function_decl["inputs"][0][1],
       
   244                                            testtype), InTypes))
       
   245                             if inps and outs and Function_decl["outputs"][0][1] != Function_decl["inputs"][0][1]:
       
   246                                 store = True
       
   247                                 break
       
   248                             else:
       
   249                                 store = False
       
   250                         if store :
   411                             # create the copy of decl dict to be appended to section
   251                             # create the copy of decl dict to be appended to section
   412                             Function_decl_copy = Function_decl.copy()
   252                             Function_decl_copy = Function_decl.copy()
   413                             Current_section["list"].append(Function_decl_copy)
   253                             Current_section["list"].append(Function_decl_copy)
   414             else:
   254             else:
   415                 raise "First function must be in a category"
   255                 raise "First function must be in a category"
   416     
   256     
   417     return Standard_Functions_Decl
   257     return Standard_Functions_Decl
   418 
   258 
   419 std_decl = get_standard_funtions(csv_file_to_table(open(os.path.join(ScriptDirectory,"iec_std.csv"))))#, True)
   259 StdBlckLst.extend(get_standard_funtions(csv_file_to_table(open(StdFuncsCSV))))
   420 
       
   421 StdBlckLst.extend(std_decl)
       
   422 
   260 
   423 # Dictionary to speedup block type fetching by name
   261 # Dictionary to speedup block type fetching by name
   424 StdBlckDct = OrderedDict()
   262 StdBlckDct = OrderedDict()
   425 
   263 
   426 for section in StdBlckLst:
   264 for section in StdBlckLst:
   437         BlkLst.append((section["name"], desc))
   275         BlkLst.append((section["name"], desc))
   438 
   276 
   439 #-------------------------------------------------------------------------------
   277 #-------------------------------------------------------------------------------
   440 #                            Languages Keywords
   278 #                            Languages Keywords
   441 #-------------------------------------------------------------------------------
   279 #-------------------------------------------------------------------------------
   442 
       
   443 
   280 
   444 # Keywords for Pou Declaration
   281 # Keywords for Pou Declaration
   445 POU_BLOCK_START_KEYWORDS = ["FUNCTION", "FUNCTION_BLOCK", "PROGRAM"]
   282 POU_BLOCK_START_KEYWORDS = ["FUNCTION", "FUNCTION_BLOCK", "PROGRAM"]
   446 POU_BLOCK_END_KEYWORDS = ["END_FUNCTION", "END_FUNCTION_BLOCK", "END_PROGRAM"]
   283 POU_BLOCK_END_KEYWORDS = ["END_FUNCTION", "END_FUNCTION_BLOCK", "END_PROGRAM"]
   447 POU_KEYWORDS = ["EN", "ENO", "F_EDGE", "R_EDGE"] + POU_BLOCK_START_KEYWORDS + POU_BLOCK_END_KEYWORDS
   284 POU_KEYWORDS = ["EN", "ENO", "F_EDGE", "R_EDGE"] + POU_BLOCK_START_KEYWORDS + POU_BLOCK_END_KEYWORDS
   500                                     (IEC_KEYWORDS, [POU_KEYWORDS, TYPE_KEYWORDS, VAR_KEYWORDS, CONFIG_KEYWORDS,
   337                                     (IEC_KEYWORDS, [POU_KEYWORDS, TYPE_KEYWORDS, VAR_KEYWORDS, CONFIG_KEYWORDS,
   501                                                     SFC_KEYWORDS, IL_KEYWORDS, ST_KEYWORDS])]:
   338                                                     SFC_KEYWORDS, IL_KEYWORDS, ST_KEYWORDS])]:
   502     for keywords in keywords_list:
   339     for keywords in keywords_list:
   503         all_keywords.extend([keyword for keyword in keywords if keyword not in all_keywords])
   340         all_keywords.extend([keyword for keyword in keywords if keyword not in all_keywords])
   504 
   341 
       
   342