167 "%(IECtype)s", |
167 "%(IECtype)s", |
168 %(initial)s, |
168 %(initial)s, |
169 %(desc)s, |
169 %(desc)s, |
170 %(onchange)s, |
170 %(onchange)s, |
171 %(opts)s)) |
171 %(opts)s)) |
172 """ % varinfo for varinfo in varinfos]) |
172 """ % varinfo + (""" |
|
173 _PyOnChangeCount_%(name)s = ctypes.c_uint.in_dll(PLCBinary,"__%(name)s_onchange_count") |
|
174 _PyOnChangeFirst_%(name)s = _%(name)s_ctype.in_dll(PLCBinary,"__%(name)s_onchange_firstval") |
|
175 _PyOnChangeLast_%(name)s = _%(name)s_ctype.in_dll(PLCBinary,"__%(name)s_onchange_lastval") |
|
176 """ % varinfo if varinfo["onchange"] else "") for varinfo in varinfos]) |
173 |
177 |
174 on_change_func_body = "\n".join([""" |
178 on_change_func_body = "\n".join([""" |
175 if changes.next(): |
179 if _PyOnChangeCount_%(name)s.value > 0: |
176 # %(name)s |
180 # %(name)s |
177 try:""" % varinfo + """ |
181 try:""" % varinfo + """ |
178 """ + """ |
182 """ + """ |
179 """.join(varinfo['onchangecode'])+""" |
183 """.join(varinfo['onchangecode'])+""" |
180 except Exception as e: |
184 except Exception as e: |
213 ## Code for PLC global variable access |
217 ## Code for PLC global variable access |
214 from runtime.typemapping import TypeTranslator |
218 from runtime.typemapping import TypeTranslator |
215 import ctypes |
219 import ctypes |
216 |
220 |
217 _PySafeGetChanges_%(pyextname)s = PLCBinary.PySafeGetChanges_%(location_str)s |
221 _PySafeGetChanges_%(pyextname)s = PLCBinary.PySafeGetChanges_%(location_str)s |
218 _PySafeGetChanges_%(pyextname)s.restype = ctypes.POINTER(ctypes.c_int * %(onchange_var_count)d) |
222 _PySafeGetChanges_%(pyextname)s.restype = None |
219 _PySafeGetChanges_%(pyextname)s.argtypes = None |
223 _PySafeGetChanges_%(pyextname)s.argtypes = None |
220 |
224 |
221 _%(pyextname)sGlobalsDesc = [] |
225 _%(pyextname)sGlobalsDesc = [] |
222 __ext_name__ = "%(pyextname)s" |
226 __ext_name__ = "%(pyextname)s" |
223 PLCGlobalsDesc.append(( "%(pyextname)s" , _%(pyextname)sGlobalsDesc )) |
227 PLCGlobalsDesc.append(( "%(pyextname)s" , _%(pyextname)sGlobalsDesc )) |
228 |
232 |
229 ## Beremiz python runtime calls |
233 ## Beremiz python runtime calls |
230 %(rtcalls)s |
234 %(rtcalls)s |
231 |
235 |
232 def On_%(pyextname)s_Change(): |
236 def On_%(pyextname)s_Change(): |
233 changesP = _PySafeGetChanges_%(pyextname)s() |
237 _PySafeGetChanges_%(pyextname)s() |
234 if not changesP: |
|
235 raise Exception("PySafeGetChanges returned NULL!") |
|
236 changes = iter(changesP.contents) |
|
237 errors = [] |
238 errors = [] |
238 %(on_change_func_body)s |
239 %(on_change_func_body)s |
239 if len(errors)>0 : |
240 if len(errors)>0 : |
240 raise Exception("Exception in %(pyextname)s OnChange call:\\\\n" + "\\\\n".join(errors)) |
241 raise Exception("Exception in %(pyextname)s OnChange call:\\\\n" + "\\\\n".join(errors)) |
241 |
242 |
272 } |
273 } |
273 |
274 |
274 """ |
275 """ |
275 |
276 |
276 vardeconchangefmt = """\ |
277 vardeconchangefmt = """\ |
277 int __%(name)s_rbuffer_written = 0; |
278 unsigned int __%(name)s_rbuffer_written = 0; |
|
279 IEC_%(IECtype)s __%(name)s_rbuffer_firstval; |
|
280 IEC_%(IECtype)s __%(name)s_rbuffer_lastval; |
|
281 unsigned int __%(name)s_onchange_count = 0; |
|
282 IEC_%(IECtype)s __%(name)s_onchange_firstval; |
|
283 IEC_%(IECtype)s __%(name)s_onchange_lastval; |
278 """ |
284 """ |
279 |
285 |
280 varretfmt = """\ |
286 varretfmt = """\ |
281 if(!AtomicCompareExchange(&__%(name)s_wlock, 0, 1)){ |
287 if(!AtomicCompareExchange(&__%(name)s_wlock, 0, 1)){ |
282 if(__%(name)s_wbuffer_written == 1){ |
288 if(__%(name)s_wbuffer_written == 1){ |
295 |
301 |
296 varpubonchangefmt = """\ |
302 varpubonchangefmt = """\ |
297 if(!AtomicCompareExchange(&__%(name)s_rlock, 0, 1)){ |
303 if(!AtomicCompareExchange(&__%(name)s_rlock, 0, 1)){ |
298 IEC_%(IECtype)s tmp = __GET_VAR(%(configname)s__%(uppername)s); |
304 IEC_%(IECtype)s tmp = __GET_VAR(%(configname)s__%(uppername)s); |
299 if(NE_%(IECtype)s(1, NULL, __%(name)s_rbuffer, tmp)){ |
305 if(NE_%(IECtype)s(1, NULL, __%(name)s_rbuffer, tmp)){ |
|
306 if(__%(name)s_rbuffer_written == 0); |
|
307 __%(name)s_rbuffer_firstval = __%(name)s_rbuffer; |
|
308 __%(name)s_rbuffer_lastval = tmp; |
300 __%(name)s_rbuffer = tmp; |
309 __%(name)s_rbuffer = tmp; |
301 /* mark variable as changed */ |
310 /* count one more change */ |
302 __%(name)s_rbuffer_written = 1; |
311 __%(name)s_rbuffer_written += 1; |
303 some_change = 1; |
312 some_change_found = 1; |
304 } |
313 } |
305 AtomicCompareExchange((long*)&__%(name)s_rlock, 1, 0); |
314 AtomicCompareExchange((long*)&__%(name)s_rlock, 1, 0); |
306 } |
315 } |
307 """ |
316 """ |
308 |
317 |
309 varcollectchangefmt = """\ |
318 varcollectchangefmt = """\ |
310 while(AtomicCompareExchange(&__%(name)s_wlock, 0, 1)); |
319 while(AtomicCompareExchange(&__%(name)s_rlock, 0, 1)); |
311 pysafe_changes[change_index++] = __%(name)s_rbuffer_written; |
320 __%(name)s_onchange_count = __%(name)s_rbuffer_written; |
|
321 __%(name)s_onchange_firstval = __%(name)s_rbuffer_firstval; |
|
322 __%(name)s_onchange_lastval = __%(name)s_rbuffer_lastval; |
312 /* mark variable as unchanged */ |
323 /* mark variable as unchanged */ |
313 __%(name)s_rbuffer_written = 0; |
324 __%(name)s_rbuffer_written = 0; |
314 AtomicCompareExchange((long*)&__%(name)s_wlock, 1, 0); |
325 AtomicCompareExchange((long*)&__%(name)s_rlock, 1, 0); |
315 |
326 |
316 """ |
327 """ |
317 vardec = "\n".join([(vardecfmt + vardeconchangefmt |
328 vardec = "\n".join([(vardecfmt + vardeconchangefmt |
318 if varinfo["onchange"] else vardecfmt) % varinfo |
329 if varinfo["onchange"] else vardecfmt) % varinfo |
319 for varinfo in varinfos]) |
330 for varinfo in varinfos]) |
369 |
380 |
370 void __retrieve_%(location_str)s(void){ |
381 void __retrieve_%(location_str)s(void){ |
371 %(varret)s |
382 %(varret)s |
372 } |
383 } |
373 |
384 |
|
385 static int passing_changes_to_python = 0; |
374 void __publish_%(location_str)s(void){ |
386 void __publish_%(location_str)s(void){ |
375 int some_change = 0; |
387 int some_change_found = 0; |
376 %(varpub)s |
388 %(varpub)s |
|
389 passing_changes_to_python |= some_change_found; |
377 // call python part if there was at least a change |
390 // call python part if there was at least a change |
378 if(some_change){ |
391 if(passing_changes_to_python){ |
379 PYTHON_POLL_body__(__%(location_str)s_notifier); |
392 PYTHON_POLL_body__(__%(location_str)s_notifier); |
|
393 passing_changes_to_python &= !(__GET_VAR(__%(location_str)s_notifier->ACK,)); |
380 } |
394 } |
381 } |
395 } |
382 |
396 |
383 static int pysafe_changes[%(onchange_var_count)d]; |
|
384 void* PySafeGetChanges_%(location_str)s(void){ |
397 void* PySafeGetChanges_%(location_str)s(void){ |
385 int change_index=0; |
|
386 %(varcollectchange)s |
398 %(varcollectchange)s |
387 return (void*)&pysafe_changes[0]; |
|
388 } |
399 } |
389 |
400 |
390 """ % loc_dict |
401 """ % loc_dict |
391 |
402 |
392 Gen_PyCfile_path = os.path.join(buildpath, "PyCFile_%s.c" % location_str) |
403 Gen_PyCfile_path = os.path.join(buildpath, "PyCFile_%s.c" % location_str) |