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: |