21 # License along with this library; if not, write to the Free Software |
21 # License along with this library; if not, write to the Free Software |
22 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
22 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
23 |
23 |
24 |
24 |
25 from __future__ import absolute_import |
25 from __future__ import absolute_import |
26 from threading import Thread, Lock, Semaphore, Event |
26 from threading import Thread, Lock, Event, Condition |
27 import ctypes |
27 import ctypes |
28 import os |
28 import os |
29 import sys |
29 import sys |
30 import traceback |
30 import traceback |
31 import shutil |
31 import shutil |
377 self.python_runtime_vars["_runtime_%s" % methodname].append(method) |
377 self.python_runtime_vars["_runtime_%s" % methodname].append(method) |
378 except Exception: |
378 except Exception: |
379 self.LogMessage(0, traceback.format_exc()) |
379 self.LogMessage(0, traceback.format_exc()) |
380 raise |
380 raise |
381 |
381 |
382 self.PythonRuntimeCall("init") |
382 self.PythonThreadCondLock = Lock() |
|
383 self.PythonThreadCond = Condition(self.PythonThreadCondLock) |
|
384 self.PythonThreadCmd = "Wait" |
|
385 self.PythonThread = Thread(target=self.PythonThreadProc) |
|
386 self.PythonThread.start() |
|
387 |
383 |
388 |
384 # used internaly |
389 # used internaly |
385 def PythonRuntimeCleanup(self): |
390 def PythonRuntimeCleanup(self): |
386 if self.python_runtime_vars is not None: |
391 if self.python_runtime_vars is not None: |
387 self.PythonRuntimeCall("cleanup") |
392 self.PythonThreadCommand("Finish") |
|
393 self.PythonThread.join() |
388 |
394 |
389 self.python_runtime_vars = None |
395 self.python_runtime_vars = None |
390 |
396 |
391 def PythonThreadProc(self): |
397 def PythonThreadLoop(self): |
392 self.StartSem.release() |
|
393 res, cmd, blkid = "None", "None", ctypes.c_void_p() |
398 res, cmd, blkid = "None", "None", ctypes.c_void_p() |
394 compile_cache = {} |
399 compile_cache = {} |
395 while True: |
400 while True: |
396 cmd = self._PythonIterator(res, blkid) |
401 cmd = self._PythonIterator(res, blkid) |
397 FBID = blkid.value |
402 FBID = blkid.value |
413 self.python_runtime_vars["FBID"] = None |
418 self.python_runtime_vars["FBID"] = None |
414 except Exception as e: |
419 except Exception as e: |
415 res = "#EXCEPTION : "+str(e) |
420 res = "#EXCEPTION : "+str(e) |
416 self.LogMessage(1, ('PyEval@0x%x(Code="%s") Exception "%s"') % (FBID, cmd, str(e))) |
421 self.LogMessage(1, ('PyEval@0x%x(Code="%s") Exception "%s"') % (FBID, cmd, str(e))) |
417 |
422 |
|
423 def PythonThreadProc(self): |
|
424 print('self.PythonRuntimeCall("init")') |
|
425 self.PythonRuntimeCall("init") |
|
426 |
|
427 while True: |
|
428 self.PythonThreadCondLock.acquire() |
|
429 cmd = self.PythonThreadCmd |
|
430 while cmd == "Wait": |
|
431 self.PythonThreadCond.wait() |
|
432 cmd = self.PythonThreadCmd |
|
433 self.PythonThreadCmd = "Wait" |
|
434 self.PythonThreadCondLock.release() |
|
435 |
|
436 if cmd == "Activate" : |
|
437 print('self.PythonRuntimeCall("start")') |
|
438 self.PythonRuntimeCall("start") |
|
439 |
|
440 self.PythonThreadLoop() |
|
441 |
|
442 self.PythonRuntimeCall("stop") |
|
443 else: # "Finish" |
|
444 break |
|
445 |
|
446 self.PythonRuntimeCall("cleanup") |
|
447 |
|
448 def PythonThreadCommand(self, cmd): |
|
449 self.PythonThreadCondLock.acquire() |
|
450 self.PythonThreadCmd = cmd |
|
451 self.PythonThreadCond.notify() |
|
452 self.PythonThreadCondLock.release() |
|
453 |
418 @RunInMain |
454 @RunInMain |
419 def StartPLC(self): |
455 def StartPLC(self): |
420 if self.CurrentPLCFilename is not None and self.PLCStatus == PlcStatus.Stopped: |
456 if self.CurrentPLCFilename is not None and self.PLCStatus == PlcStatus.Stopped: |
421 c_argv = ctypes.c_char_p * len(self.argv) |
457 c_argv = ctypes.c_char_p * len(self.argv) |
422 res = self._startPLC(len(self.argv), c_argv(*self.argv)) |
458 res = self._startPLC(len(self.argv), c_argv(*self.argv)) |
423 if res == 0: |
459 if res == 0: |
424 self.PLCStatus = PlcStatus.Started |
460 self.PLCStatus = PlcStatus.Started |
425 self.StatusChange() |
461 self.StatusChange() |
426 self.PythonRuntimeCall("start") |
462 self.PythonThreadCommand("Activate") |
427 self.StartSem = Semaphore(0) |
|
428 self.PythonThread = Thread(target=self.PythonThreadProc) |
|
429 self.PythonThread.start() |
|
430 self.StartSem.acquire() |
|
431 self.LogMessage("PLC started") |
463 self.LogMessage("PLC started") |
432 else: |
464 else: |
433 self.LogMessage(0, _("Problem starting PLC : error %d" % res)) |
465 self.LogMessage(0, _("Problem starting PLC : error %d" % res)) |
434 self.PLCStatus = PlcStatus.Broken |
466 self.PLCStatus = PlcStatus.Broken |
435 self.StatusChange() |
467 self.StatusChange() |
437 @RunInMain |
469 @RunInMain |
438 def StopPLC(self): |
470 def StopPLC(self): |
439 if self.PLCStatus == PlcStatus.Started: |
471 if self.PLCStatus == PlcStatus.Started: |
440 self.LogMessage("PLC stopped") |
472 self.LogMessage("PLC stopped") |
441 self._stopPLC() |
473 self._stopPLC() |
442 self.PythonThread.join() |
|
443 self.PLCStatus = PlcStatus.Stopped |
474 self.PLCStatus = PlcStatus.Stopped |
444 self.StatusChange() |
475 self.StatusChange() |
445 self.PythonRuntimeCall("stop") |
|
446 if self.TraceThread is not None: |
476 if self.TraceThread is not None: |
447 self.TraceThread.join() |
477 self.TraceThread.join() |
448 self.TraceThread = None |
478 self.TraceThread = None |
449 return True |
479 return True |
450 return False |
480 return False |