runtime/PLCObject.py
changeset 2429 15f18dc8b56a
parent 2324 1cf3768ebf85
parent 2419 c081dabc0f63
child 2459 21164625b393
equal deleted inserted replaced
2428:e0f16317668e 2429:15f18dc8b56a
    32 import _ctypes  # pylint: disable=wrong-import-order
    32 import _ctypes  # pylint: disable=wrong-import-order
    33 
    33 
    34 from runtime.typemapping import TypeTranslator
    34 from runtime.typemapping import TypeTranslator
    35 from runtime.loglevels import LogLevelsDefault, LogLevelsCount
    35 from runtime.loglevels import LogLevelsDefault, LogLevelsCount
    36 from runtime.Stunnel import getPSKID
    36 from runtime.Stunnel import getPSKID
       
    37 from runtime import PlcStatus
    37 from runtime import MainWorker
    38 from runtime import MainWorker
    38 
    39 
    39 if os.name in ("nt", "ce"):
    40 if os.name in ("nt", "ce"):
    40     dlopen = _ctypes.LoadLibrary
    41     dlopen = _ctypes.LoadLibrary
    41     dlclose = _ctypes.FreeLibrary
    42     dlclose = _ctypes.FreeLibrary
    73         # FIXME : is argv of any use nowadays ?
    74         # FIXME : is argv of any use nowadays ?
    74         self.argv = [WorkingDir] + argv  # force argv[0] to be "path" to exec...
    75         self.argv = [WorkingDir] + argv  # force argv[0] to be "path" to exec...
    75         self.statuschange = statuschange
    76         self.statuschange = statuschange
    76         self.evaluator = evaluator
    77         self.evaluator = evaluator
    77         self.pyruntimevars = pyruntimevars
    78         self.pyruntimevars = pyruntimevars
    78         self.PLCStatus = "Empty"
    79         self.PLCStatus = PlcStatus.Empty
    79         self.PLClibraryHandle = None
    80         self.PLClibraryHandle = None
    80         self.PLClibraryLock = Lock()
    81         self.PLClibraryLock = Lock()
    81         # Creates fake C funcs proxies
    82         # Creates fake C funcs proxies
    82         self._InitPLCStubCalls()
    83         self._InitPLCStubCalls()
    83         self._loading_error = None
    84         self._loading_error = None
   394                     self.LogMessage(1, ('PyEval@0x%x(Code="%s") Exception "%s"') % (
   395                     self.LogMessage(1, ('PyEval@0x%x(Code="%s") Exception "%s"') % (
   395                         FBID, cmd, '\n'.join(traceback.format_exception(*exp))))
   396                         FBID, cmd, '\n'.join(traceback.format_exception(*exp))))
   396                 else:
   397                 else:
   397                     res = str(result)
   398                     res = str(result)
   398                 self.python_runtime_vars["FBID"] = None
   399                 self.python_runtime_vars["FBID"] = None
   399             except Exception, e:
   400             except Exception as e:
   400                 res = "#EXCEPTION : "+str(e)
   401                 res = "#EXCEPTION : "+str(e)
   401                 self.LogMessage(1, ('PyEval@0x%x(Code="%s") Exception "%s"') % (FBID, cmd, str(e)))
   402                 self.LogMessage(1, ('PyEval@0x%x(Code="%s") Exception "%s"') % (FBID, cmd, str(e)))
   402 
   403 
   403     @RunInMain
   404     @RunInMain
   404     def StartPLC(self):
   405     def StartPLC(self):
   405         if self.CurrentPLCFilename is not None and self.PLCStatus == "Stopped":
   406         if self.CurrentPLCFilename is not None and self.PLCStatus == PlcStatus.Stopped:
   406             c_argv = ctypes.c_char_p * len(self.argv)
   407             c_argv = ctypes.c_char_p * len(self.argv)
   407             res = self._startPLC(len(self.argv), c_argv(*self.argv))
   408             res = self._startPLC(len(self.argv), c_argv(*self.argv))
   408             if res == 0:
   409             if res == 0:
   409                 self.PLCStatus = "Started"
   410                 self.PLCStatus = PlcStatus.Started
   410                 self.StatusChange()
   411                 self.StatusChange()
   411                 self.PythonRuntimeCall("start")
   412                 self.PythonRuntimeCall("start")
   412                 self.StartSem = Semaphore(0)
   413                 self.StartSem = Semaphore(0)
   413                 self.PythonThread = Thread(target=self.PythonThreadProc)
   414                 self.PythonThread = Thread(target=self.PythonThreadProc)
   414                 self.PythonThread.start()
   415                 self.PythonThread.start()
   415                 self.StartSem.acquire()
   416                 self.StartSem.acquire()
   416                 self.LogMessage("PLC started")
   417                 self.LogMessage("PLC started")
   417             else:
   418             else:
   418                 self.LogMessage(0, _("Problem starting PLC : error %d" % res))
   419                 self.LogMessage(0, _("Problem starting PLC : error %d" % res))
   419                 self.PLCStatus = "Broken"
   420                 self.PLCStatus = PlcStatus.Broken
   420                 self.StatusChange()
   421                 self.StatusChange()
   421 
   422 
   422     @RunInMain
   423     @RunInMain
   423     def StopPLC(self):
   424     def StopPLC(self):
   424         if self.PLCStatus == "Started":
   425         if self.PLCStatus == PlcStatus.Started:
   425             self.LogMessage("PLC stopped")
   426             self.LogMessage("PLC stopped")
   426             self._stopPLC()
   427             self._stopPLC()
   427             self.PythonThread.join()
   428             self.PythonThread.join()
   428             self.PLCStatus = "Stopped"
   429             self.PLCStatus = PlcStatus.Stopped
   429             self.StatusChange()
   430             self.StatusChange()
   430             self.PythonRuntimeCall("stop")
   431             self.PythonRuntimeCall("stop")
   431             if self.TraceThread is not None:
   432             if self.TraceThread is not None:
   432                 self.TraceThread.join()
   433                 self.TraceThread.join()
   433                 self.TraceThread = None
   434                 self.TraceThread = None
   442     def GetPLCID(self):
   443     def GetPLCID(self):
   443         return getPSKID()
   444         return getPSKID()
   444 
   445 
   445     @RunInMain
   446     @RunInMain
   446     def NewPLC(self, md5sum, data, extrafiles):
   447     def NewPLC(self, md5sum, data, extrafiles):
   447         if self.PLCStatus in ["Stopped", "Empty", "Broken"]:
   448         if self.PLCStatus in [PlcStatus.Stopped, PlcStatus.Empty, PlcStatus.Broken]:
   448             NewFileName = md5sum + lib_ext
   449             NewFileName = md5sum + lib_ext
   449             extra_files_log = os.path.join(self.workingdir, "extra_files.txt")
   450             extra_files_log = os.path.join(self.workingdir, "extra_files.txt")
   450 
   451 
   451             old_PLC_filename = os.path.join(self.workingdir, self.CurrentPLCFilename) \
   452             old_PLC_filename = os.path.join(self.workingdir, self.CurrentPLCFilename) \
   452                 if self.CurrentPLCFilename is not None \
   453                 if self.CurrentPLCFilename is not None \
   458 
   459 
   459             if replace_PLC_shared_object:
   460             if replace_PLC_shared_object:
   460                 self.UnLoadPLC()
   461                 self.UnLoadPLC()
   461 
   462 
   462             self.LogMessage("NewPLC (%s)" % md5sum)
   463             self.LogMessage("NewPLC (%s)" % md5sum)
   463             self.PLCStatus = "Empty"
   464             self.PLCStatus = PlcStatus.Empty
   464 
   465 
   465             try:
   466             try:
   466                 if replace_PLC_shared_object:
   467                 if replace_PLC_shared_object:
   467                     os.remove(old_PLC_filename)
   468                     os.remove(old_PLC_filename)
   468                 for filename in file(extra_files_log, "r").readlines() + [extra_files_log]:
   469                 for filename in file(extra_files_log, "r").readlines() + [extra_files_log]:
   489                     log.write(fname+'\n')
   490                     log.write(fname+'\n')
   490 
   491 
   491                 # Store new PLC filename
   492                 # Store new PLC filename
   492                 self.CurrentPLCFilename = NewFileName
   493                 self.CurrentPLCFilename = NewFileName
   493             except Exception:
   494             except Exception:
   494                 self.PLCStatus = "Broken"
   495                 self.PLCStatus = PlcStatus.Broken
   495                 self.StatusChange()
   496                 self.StatusChange()
   496                 PLCprint(traceback.format_exc())
   497                 PLCprint(traceback.format_exc())
   497                 return False
   498                 return False
   498 
   499 
   499             if not replace_PLC_shared_object:
   500             if not replace_PLC_shared_object:
   500                 self.PLCStatus = "Stopped"
   501                 self.PLCStatus = PlcStatus.Stopped
   501             elif self.LoadPLC():
   502             elif self.LoadPLC():
   502                 self.PLCStatus = "Stopped"
   503                 self.PLCStatus = PlcStatus.Stopped
   503             else:
   504             else:
   504                 self.PLCStatus = "Broken"
   505                 self.PLCStatus = PlcStatus.Broken
   505             self.StatusChange()
   506             self.StatusChange()
   506 
   507 
   507             return self.PLCStatus == "Stopped"
   508             return self.PLCStatus == PlcStatus.Stopped
   508         return False
   509         return False
   509 
   510 
   510     def MatchMD5(self, MD5):
   511     def MatchMD5(self, MD5):
   511         try:
   512         try:
   512             last_md5 = open(self._GetMD5FileName(), "r").read()
   513             last_md5 = open(self._GetMD5FileName(), "r").read()
   537         else:
   538         else:
   538             self._suspendDebug(True)
   539             self._suspendDebug(True)
   539 
   540 
   540     def _TracesSwap(self):
   541     def _TracesSwap(self):
   541         self.LastSwapTrace = time()
   542         self.LastSwapTrace = time()
   542         if self.TraceThread is None and self.PLCStatus == "Started":
   543         if self.TraceThread is None and self.PLCStatus == PlcStatus.Started:
   543             self.TraceThread = Thread(target=self.TraceThreadProc)
   544             self.TraceThread = Thread(target=self.TraceThreadProc)
   544             self.TraceThread.start()
   545             self.TraceThread.start()
   545         self.TraceLock.acquire()
   546         self.TraceLock.acquire()
   546         Traces = self.Traces
   547         Traces = self.Traces
   547         self.Traces = []
   548         self.Traces = []
   555     def TraceThreadProc(self):
   556     def TraceThreadProc(self):
   556         """
   557         """
   557         Return a list of traces, corresponding to the list of required idx
   558         Return a list of traces, corresponding to the list of required idx
   558         """
   559         """
   559         self._resumeDebug()  # Re-enable debugger
   560         self._resumeDebug()  # Re-enable debugger
   560         while self.PLCStatus == "Started":
   561         while self.PLCStatus == PlcStatus.Started:
   561             tick = ctypes.c_uint32()
   562             tick = ctypes.c_uint32()
   562             size = ctypes.c_uint32()
   563             size = ctypes.c_uint32()
   563             buff = ctypes.c_void_p()
   564             buff = ctypes.c_void_p()
   564             TraceBuffer = None
   565             TraceBuffer = None
   565 
   566 
   598 
   599 
   599         self.TraceThread = None
   600         self.TraceThread = None
   600 
   601 
   601     def RemoteExec(self, script, *kwargs):
   602     def RemoteExec(self, script, *kwargs):
   602         try:
   603         try:
   603             exec script in kwargs
   604             exec(script, kwargs)
   604         except Exception:
   605         except Exception:
   605             _e_type, e_value, e_traceback = sys.exc_info()
   606             _e_type, e_value, e_traceback = sys.exc_info()
   606             line_no = traceback.tb_lineno(get_last_traceback(e_traceback))
   607             line_no = traceback.tb_lineno(get_last_traceback(e_traceback))
   607             return (-1, "RemoteExec script failed!\n\nLine %d: %s\n\t%s" %
   608             return (-1, "RemoteExec script failed!\n\nLine %d: %s\n\t%s" %
   608                     (line_no, e_value, script.splitlines()[line_no - 1]))
   609                     (line_no, e_value, script.splitlines()[line_no - 1]))