runtime/PLCObject.py
changeset 291 701c0601db02
parent 290 3bd617ae7a05
child 299 d7f8ffe18017
equal deleted inserted replaced
290:3bd617ae7a05 291:701c0601db02
    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 Pyro.core as pyro
    25 import Pyro.core as pyro
    26 from threading import Timer, Thread
    26 from threading import Timer, Thread
    27 import ctypes, os, commands
    27 import ctypes, os, commands
       
    28 import sys
    28 
    29 
    29 if os.name in ("nt", "ce"):
    30 if os.name in ("nt", "ce"):
    30     from _ctypes import LoadLibrary as dlopen
    31     from _ctypes import LoadLibrary as dlopen
    31     from _ctypes import FreeLibrary as dlclose
    32     from _ctypes import FreeLibrary as dlclose
    32 elif os.name == "posix":
    33 elif os.name == "posix":
    36 
    37 
    37 lib_ext ={
    38 lib_ext ={
    38      "linux2":".so",
    39      "linux2":".so",
    39      "win32":".dll",
    40      "win32":".dll",
    40      }.get(sys.platform, "")
    41      }.get(sys.platform, "")
       
    42 
       
    43 def PLCprint(message):
       
    44     sys.stdout.write("PLCobject : "+message+"\n")
       
    45     sys.stdout.flush()
    41 
    46 
    42 class PLCObject(pyro.ObjBase):
    47 class PLCObject(pyro.ObjBase):
    43     _Idxs = []
    48     _Idxs = []
    44     def __init__(self, workingdir, daemon, argv, statuschange=None):
    49     def __init__(self, workingdir, daemon, argv, statuschange=None):
    45         pyro.ObjBase.__init__(self)
    50         pyro.ObjBase.__init__(self)
    76     def _LoadNewPLC(self):
    81     def _LoadNewPLC(self):
    77         """
    82         """
    78         Load PLC library
    83         Load PLC library
    79         Declare all functions, arguments and return values
    84         Declare all functions, arguments and return values
    80         """
    85         """
    81         print "Load PLC"
    86         PLCprint("Load PLC")
    82         try:
    87         try:
    83             self._PLClibraryHandle = dlopen(self._GetLibFileName())
    88             self._PLClibraryHandle = dlopen(self._GetLibFileName())
    84             self.PLClibraryHandle = ctypes.CDLL(self.CurrentPLCFilename, handle=self._PLClibraryHandle)
    89             self.PLClibraryHandle = ctypes.CDLL(self.CurrentPLCFilename, handle=self._PLClibraryHandle)
    85     
    90     
    86             self._startPLC = self.PLClibraryHandle.startPLC
    91             self._startPLC = self.PLClibraryHandle.startPLC
   117             self._PythonIterator.restype = ctypes.c_char_p
   122             self._PythonIterator.restype = ctypes.c_char_p
   118             self._PythonIterator.argtypes = [ctypes.c_char_p]
   123             self._PythonIterator.argtypes = [ctypes.c_char_p]
   119             
   124             
   120             return True
   125             return True
   121         except:
   126         except:
   122             print traceback.format_exc()
   127             PLCprint(traceback.format_exc())
   123             return False
   128             return False
   124 
   129 
   125     def _FreePLC(self):
   130     def _FreePLC(self):
   126         """
   131         """
   127         Unload PLC library.
   132         Unload PLC library.
   139         self._resumeDebug = lambda:None
   144         self._resumeDebug = lambda:None
   140         self._PythonIterator = lambda:""
   145         self._PythonIterator = lambda:""
   141         self.PLClibraryHandle = None
   146         self.PLClibraryHandle = None
   142         # Unload library explicitely
   147         # Unload library explicitely
   143         if getattr(self,"_PLClibraryHandle",None) is not None:
   148         if getattr(self,"_PLClibraryHandle",None) is not None:
   144             print "Unload PLC"
   149             PLCprint("Unload PLC")
   145             dlclose(self._PLClibraryHandle)
   150             dlclose(self._PLClibraryHandle)
   146             res = self._DetectDirtyLibs()
   151             res = self._DetectDirtyLibs()
   147         else:
   152         else:
   148             res = False
   153             res = False
   149 
   154 
   166                                   "libatk",
   171                                   "libatk",
   167                                   "libpan",
   172                                   "libpan",
   168                                   "libX11",
   173                                   "libX11",
   169                                   ]:
   174                                   ]:
   170                     #badhandle = dlopen(badlib, dl.RTLD_NOLOAD)
   175                     #badhandle = dlopen(badlib, dl.RTLD_NOLOAD)
   171                     print "Dirty lib detected :" + badlib
   176                     PLCprint("Dirty lib detected :" + badlib)
   172                     #dlclose(badhandle)
   177                     #dlclose(badhandle)
   173                     return True
   178                     return True
   174         return False
   179         return False
   175 
   180 
   176     def PythonThreadProc(self):
   181     def ExecRuntimePy(self):
   177         print "PythonThreadProc started"
       
   178         self.python_threads_vars = globals().copy()
   182         self.python_threads_vars = globals().copy()
   179         pyfile = os.path.join(self.workingdir, "runtime.py")
   183         pyfile = os.path.join(self.workingdir, "runtime.py")
   180         if os.path.exists(pyfile):
   184         if os.path.exists(pyfile):
   181             # TODO handle exceptions in runtime.py
   185             # TODO handle exceptions in runtime.py
   182             # pyfile may redefine _runtime_cleanup
   186             # pyfile may redefine _runtime_cleanup
   183             # or even call _PythonThreadProc itself.
   187             # or even call _PythonThreadProc itself.
   184             execfile(pyfile, self.python_threads_vars)
   188             execfile(pyfile, self.python_threads_vars)
       
   189 
       
   190     def FinishRuntimePy(self):
       
   191         if self.python_threads_vars.get("_runtime_cleanup",None) is not None:
       
   192             self.python_threads_vars["_runtime_cleanup"]()
       
   193         self.python_threads_vars = None
       
   194 
       
   195     def PythonThreadProc(self):
       
   196         PLCprint("PythonThreadProc started")
   185         res,cmd = "None","None"
   197         res,cmd = "None","None"
   186         while self.PLCStatus == "Started":
   198         while self.PLCStatus == "Started":
   187             #print "_PythonIterator(", res, ")",
   199             #print "_PythonIterator(", res, ")",
   188             cmd = self._PythonIterator(res)
   200             cmd = self._PythonIterator(res)
   189             #print " -> ", cmd
   201             #print " -> ", cmd
   191                 break
   203                 break
   192             try :
   204             try :
   193                 res = str(eval(cmd,self.python_threads_vars))
   205                 res = str(eval(cmd,self.python_threads_vars))
   194             except Exception,e:
   206             except Exception,e:
   195                 res = "#EXCEPTION : "+str(e)
   207                 res = "#EXCEPTION : "+str(e)
   196                 print res
   208                 PLCprint(res)
   197         print "PythonThreadProc interrupted"
   209         PLCprint("PythonThreadProc interrupted")
   198         if self.python_threads_vars.get("_runtime_cleanup",None) is not None:
       
   199             self.python_threads_vars["_runtime_cleanup"]()
       
   200         self.python_threads_vars = None
       
   201         print "PythonThreadProc cleaned up"
       
   202     
   210     
   203     def StartPLC(self, debug=False):
   211     def StartPLC(self, debug=False):
   204         print "StartPLC"
   212         PLCprint("StartPLC")
   205         if self.CurrentPLCFilename is not None and self.PLCStatus == "Stopped":
   213         if self.CurrentPLCFilename is not None and self.PLCStatus == "Stopped":
   206             c_argv = ctypes.c_char_p * len(self.argv)
   214             c_argv = ctypes.c_char_p * len(self.argv)
   207             if self._LoadNewPLC() and self._startPLC(len(self.argv),c_argv(*self.argv)) == 0:
   215             if self._LoadNewPLC() and self._startPLC(len(self.argv),c_argv(*self.argv)) == 0:
   208                 if debug:
   216                 if debug:
   209                     self._resumeDebug()
   217                     self._resumeDebug()
   210                 self.PLCStatus = "Started"
   218                 self.PLCStatus = "Started"
   211                 self.StatusChange()
   219                 self.StatusChange()
       
   220                 self.ExecRuntimePy()
   212                 self.PythonThread = Thread(target=self.PythonThreadProc)
   221                 self.PythonThread = Thread(target=self.PythonThreadProc)
   213                 self.PythonThread.start()
   222                 self.PythonThread.start()
   214                 return True
   223                 return True
   215             else:
   224             else:
   216                 print "_StartPLC did not return 0 !"
   225                 PLCprint("Problem starting PLC")
   217                 self._DoStopPLC()
   226                 self._DoStopPLC()
   218         return False
   227         return False
   219 
   228 
   220     def _DoStopPLC(self):
   229     def _DoStopPLC(self):
   221         self._stopPLC()
   230         self._stopPLC()
   222         self.PLCStatus = "Stopped"
   231         self.PLCStatus = "Stopped"
   223         self.PythonThread.join(timeout=1)
   232         self.PythonThread.join(timeout=1)
   224         if self.PythonThread.isAlive():
   233         if self.PythonThread.isAlive():
   225             print "Python thread couldn't be killed"
   234             PLCprint("Python thread couldn't be killed")
       
   235         self.FinishRuntimePy()
   226         if self._FreePLC():
   236         if self._FreePLC():
   227             self.PLCStatus = "Dirty"
   237             self.PLCStatus = "Dirty"
   228         self.StatusChange()
   238         self.StatusChange()
   229         return True
   239         return True
   230 
   240 
   248 
   258 
   249     def GetPLCstatus(self):
   259     def GetPLCstatus(self):
   250         return self.PLCStatus
   260         return self.PLCStatus
   251     
   261     
   252     def NewPLC(self, md5sum, data, extrafiles):
   262     def NewPLC(self, md5sum, data, extrafiles):
   253         print "NewPLC (%s)"%md5sum
   263         PLCprint("NewPLC (%s)"%md5sum)
   254         if self.PLCStatus in ["Stopped", "Empty", "Dirty"]:
   264         if self.PLCStatus in ["Stopped", "Empty", "Dirty"]:
   255             NewFileName = md5sum + lib_ext
   265             NewFileName = md5sum + lib_ext
   256             extra_files_log = os.path.join(self.workingdir,"extra_files.txt")
   266             extra_files_log = os.path.join(self.workingdir,"extra_files.txt")
   257             try:
   267             try:
   258                 os.remove(os.path.join(self.workingdir,
   268                 os.remove(os.path.join(self.workingdir,
   281                     log.write(fname+'\n')
   291                     log.write(fname+'\n')
   282 
   292 
   283                 # Store new PLC filename
   293                 # Store new PLC filename
   284                 self.CurrentPLCFilename = NewFileName
   294                 self.CurrentPLCFilename = NewFileName
   285             except:
   295             except:
   286                 print traceback.format_exc()
   296                 PLCprint(traceback.format_exc())
   287                 return False
   297                 return False
   288             if self.PLCStatus == "Empty":
   298             if self.PLCStatus == "Empty":
   289                 self.PLCStatus = "Stopped"
   299                 self.PLCStatus = "Stopped"
   290             return True
   300             return True
   291         return False
   301         return False
   357                     c_type,unpack_func = self.TypeTranslator.get(typename.value, (None,None))
   367                     c_type,unpack_func = self.TypeTranslator.get(typename.value, (None,None))
   358                     if c_type is not None and given_idx == idx.value:
   368                     if c_type is not None and given_idx == idx.value:
   359                         res.append(unpack_func(ctypes.cast(buffer,
   369                         res.append(unpack_func(ctypes.cast(buffer,
   360                                                            ctypes.POINTER(c_type)).contents))
   370                                                            ctypes.POINTER(c_type)).contents))
   361                     else:
   371                     else:
   362                         print "Debug error idx : %d, expected_idx %d, type : %s"%(idx.value, given_idx,typename.value)
   372                         PLCprint("Debug error idx : %d, expected_idx %d, type : %s"%(idx.value, given_idx,typename.value))
   363                         res.append(None)
   373                         res.append(None)
   364             self._FreeDebugData()
   374             self._FreeDebugData()
   365             return tick, res
   375             return tick, res
   366         return -1, None
   376         return -1, None
   367         
   377