diff -r 31e63e25b4cc -r 64beb9e9c749 runtime/PLCObject.py --- a/runtime/PLCObject.py Mon Aug 21 20:17:19 2017 +0000 +++ b/runtime/PLCObject.py Mon Aug 21 23:22:58 2017 +0300 @@ -23,7 +23,12 @@ import Pyro.core as pyro from threading import Timer, Thread, Lock, Semaphore, Event -import ctypes, os, commands, types, sys +import ctypes +import os +import commands +import types +import sys +import traceback from targets.typemapping import LogLevelsDefault, LogLevelsCount, TypeTranslator, UnpackDebugBuffer from time import time @@ -34,26 +39,29 @@ elif os.name == "posix": from _ctypes import dlopen, dlclose -import traceback + def get_last_traceback(tb): while tb.tb_next: tb = tb.tb_next return tb -lib_ext ={ - "linux2":".so", - "win32":".dll", + +lib_ext = { + "linux2": ".so", + "win32": ".dll", }.get(sys.platform, "") + def PLCprint(message): sys.stdout.write("PLCobject : "+message+"\n") sys.stdout.flush() + class PLCObject(pyro.ObjBase): def __init__(self, workingdir, daemon, argv, statuschange, evaluator, pyruntimevars): pyro.ObjBase.__init__(self) self.evaluator = evaluator - self.argv = [workingdir] + argv # force argv[0] to be "path" to exec... + self.argv = [workingdir] + argv # force argv[0] to be "path" to exec... self.workingdir = workingdir self.PLCStatus = "Empty" self.PLClibraryHandle = None @@ -75,14 +83,14 @@ def AutoLoad(self): # Get the last transfered PLC if connector must be restart try: - self.CurrentPLCFilename=open( + self.CurrentPLCFilename = open( self._GetMD5FileName(), "r").read().strip() + lib_ext if self.LoadPLC(): self.PLCStatus = "Stopped" except Exception, e: self.PLCStatus = "Empty" - self.CurrentPLCFilename=None + self.CurrentPLCFilename = None def StatusChange(self): if self.statuschange is not None: @@ -102,9 +110,9 @@ self._ResetLogCount() def GetLogCount(self, level): - if self._GetLogCount is not None : + if self._GetLogCount is not None: return int(self._GetLogCount(level)) - elif self._loading_error is not None and level==0: + elif self._loading_error is not None and level == 0: return 1 def GetLogMessage(self, level, msgid): @@ -114,23 +122,22 @@ if self._GetLogMessage is not None: maxsz = len(self._log_read_buffer)-1 sz = self._GetLogMessage(level, msgid, - self._log_read_buffer, maxsz, - ctypes.byref(tick), - ctypes.byref(tv_sec), - ctypes.byref(tv_nsec)) + self._log_read_buffer, maxsz, + ctypes.byref(tick), + ctypes.byref(tv_sec), + ctypes.byref(tv_nsec)) if sz and sz <= maxsz: self._log_read_buffer[sz] = '\x00' - return self._log_read_buffer.value,tick.value,tv_sec.value,tv_nsec.value - elif self._loading_error is not None and level==0: - return self._loading_error,0,0,0 + return self._log_read_buffer.value, tick.value, tv_sec.value, tv_nsec.value + elif self._loading_error is not None and level == 0: + return self._loading_error, 0, 0, 0 return None def _GetMD5FileName(self): return os.path.join(self.workingdir, "lasttransferedPLC.md5") def _GetLibFileName(self): - return os.path.join(self.workingdir,self.CurrentPLCFilename) - + return os.path.join(self.workingdir, self.CurrentPLCFilename) def LoadPLC(self): """ @@ -143,8 +150,8 @@ self.PLClibraryHandle = ctypes.CDLL(self.CurrentPLCFilename, handle=self._PLClibraryHandle) self.PLC_ID = ctypes.c_char_p.in_dll(self.PLClibraryHandle, "PLC_ID") - if len(md5) == 32 : - self.PLC_ID.value = md5 + if len(md5) == 32: + self.PLC_ID.value = md5 self._startPLC = self.PLClibraryHandle.startPLC self._startPLC.restype = ctypes.c_int @@ -163,6 +170,7 @@ # If python confnode is not enabled, we reuse _PythonIterator # as a call that block pythonthread until StopPLC self.PlcStopping = Event() + def PythonIterator(res, blkid): self.PlcStopping.clear() self.PlcStopping.wait() @@ -174,7 +182,6 @@ self.PlcStopping.set() self._stopPLC = __StopPLC - self._ResetDebugVariables = self.PLClibraryHandle.ResetDebugVariables self._ResetDebugVariables.restype = None @@ -207,7 +214,7 @@ self._LogMessage.restype = ctypes.c_int self._LogMessage.argtypes = [ctypes.c_uint8, ctypes.c_char_p, ctypes.c_uint32] - self._log_read_buffer = ctypes.create_string_buffer(1<<14) #16K + self._log_read_buffer = ctypes.create_string_buffer(1 << 14) # 16K self._GetLogMessage = self.PLClibraryHandle.GetLogMessage self._GetLogMessage.restype = ctypes.c_uint32 self._GetLogMessage.argtypes = [ctypes.c_uint8, ctypes.c_uint32, ctypes.c_char_p, ctypes.c_uint32, ctypes.POINTER(ctypes.c_uint32), ctypes.POINTER(ctypes.c_uint32), ctypes.POINTER(ctypes.c_uint32)] @@ -217,7 +224,7 @@ self.PythonRuntimeInit() return True - except: + except Exception: self._loading_error = traceback.format_exc() PLCprint(self._loading_error) return False @@ -233,22 +240,22 @@ """ self.PLClibraryLock.acquire() # Forget all refs to library - self._startPLC = lambda x,y:None - self._stopPLC = lambda:None - self._ResetDebugVariables = lambda:None - self._RegisterDebugVariable = lambda x, y:None - self._IterDebugData = lambda x,y:None - self._FreeDebugData = lambda:None - self._GetDebugData = lambda:-1 - self._suspendDebug = lambda x:-1 - self._resumeDebug = lambda:None - self._PythonIterator = lambda:"" + self._startPLC = lambda x, y: None + self._stopPLC = lambda: None + self._ResetDebugVariables = lambda: None + self._RegisterDebugVariable = lambda x, y: None + self._IterDebugData = lambda x, y: None + self._FreeDebugData = lambda: None + self._GetDebugData = lambda: -1 + self._suspendDebug = lambda x: -1 + self._resumeDebug = lambda: None + self._PythonIterator = lambda: "" self._GetLogCount = None - self._LogMessage = lambda l,m,s:PLCprint("OFF LOG :"+m) + self._LogMessage = lambda l, m, s: PLCprint("OFF LOG :"+m) self._GetLogMessage = None self.PLClibraryHandle = None # Unload library explicitely - if getattr(self,"_PLClibraryHandle",None) is not None: + if getattr(self, "_PLClibraryHandle", None) is not None: dlclose(self._PLClibraryHandle) self._PLClibraryHandle = None @@ -260,10 +267,10 @@ Calls init, start, stop or cleanup method provided by runtime python files, loaded when new PLC uploaded """ - for method in self.python_runtime_vars.get("_runtime_%s"%methodname, []): - res,exp = self.evaluator(method) + for method in self.python_runtime_vars.get("_runtime_%s" % methodname, []): + res, exp = self.evaluator(method) if exp is not None: - self.LogMessage(0,'\n'.join(traceback.format_exception(*exp))) + self.LogMessage(0, '\n'.join(traceback.format_exception(*exp))) def PythonRuntimeInit(self): MethodNames = ["init", "start", "stop", "cleanup"] @@ -272,30 +279,31 @@ class PLCSafeGlobals: def __getattr__(_self, name): - try : + try: t = self.python_runtime_vars["_"+name+"_ctype"] except KeyError: - raise KeyError("Try to get unknown shared global variable : %s"%name) + raise KeyError("Try to get unknown shared global variable : %s" % name) v = t() r = self.python_runtime_vars["_PySafeGetPLCGlob_"+name](ctypes.byref(v)) return self.python_runtime_vars["_"+name+"_unpack"](v) + def __setattr__(_self, name, value): - try : + try: t = self.python_runtime_vars["_"+name+"_ctype"] except KeyError: - raise KeyError("Try to set unknown shared global variable : %s"%name) - v = self.python_runtime_vars["_"+name+"_pack"](t,value) + raise KeyError("Try to set unknown shared global variable : %s" % name) + v = self.python_runtime_vars["_"+name+"_pack"](t, value) self.python_runtime_vars["_PySafeSetPLCGlob_"+name](ctypes.byref(v)) self.python_runtime_vars.update({ - "PLCGlobals" : PLCSafeGlobals(), - "WorkingDir" : self.workingdir, - "PLCObject" : self, - "PLCBinary" : self.PLClibraryHandle, - "PLCGlobalsDesc" : []}) - - for methodname in MethodNames : - self.python_runtime_vars["_runtime_%s"%methodname] = [] + "PLCGlobals": PLCSafeGlobals(), + "WorkingDir": self.workingdir, + "PLCObject": self, + "PLCBinary": self.PLClibraryHandle, + "PLCGlobalsDesc": []}) + + for methodname in MethodNames: + self.python_runtime_vars["_runtime_%s" % methodname] = [] try: filenames = os.listdir(self.workingdir) @@ -307,15 +315,13 @@ for methodname in MethodNames: method = self.python_runtime_vars.get("_%s_%s" % (name, methodname), None) if method is not None: - self.python_runtime_vars["_runtime_%s"%methodname].append(method) - except: - self.LogMessage(0,traceback.format_exc()) + self.python_runtime_vars["_runtime_%s" % methodname].append(method) + except Exception: + self.LogMessage(0, traceback.format_exc()) raise self.PythonRuntimeCall("init") - - def PythonRuntimeCleanup(self): if self.python_runtime_vars is not None: self.PythonRuntimeCall("cleanup") @@ -324,49 +330,49 @@ def PythonThreadProc(self): self.StartSem.release() - res,cmd,blkid = "None","None",ctypes.c_void_p() - compile_cache={} + res, cmd, blkid = "None", "None", ctypes.c_void_p() + compile_cache = {} while True: # print "_PythonIterator(", res, ")", - cmd = self._PythonIterator(res,blkid) + cmd = self._PythonIterator(res, blkid) FBID = blkid.value # print " -> ", cmd, blkid if cmd is None: break - try : - self.python_runtime_vars["FBID"]=FBID - ccmd,AST =compile_cache.get(FBID, (None,None)) - if ccmd is None or ccmd!=cmd: + try: + self.python_runtime_vars["FBID"] = FBID + ccmd, AST = compile_cache.get(FBID, (None, None)) + if ccmd is None or ccmd != cmd: AST = compile(cmd, '', 'eval') - compile_cache[FBID]=(cmd,AST) - result,exp = self.evaluator(eval,AST,self.python_runtime_vars) + compile_cache[FBID] = (cmd, AST) + result, exp = self.evaluator(eval, AST, self.python_runtime_vars) if exp is not None: res = "#EXCEPTION : "+str(exp[1]) - self.LogMessage(1,('PyEval@0x%x(Code="%s") Exception "%s"')%(FBID,cmd, - '\n'.join(traceback.format_exception(*exp)))) + self.LogMessage(1, ('PyEval@0x%x(Code="%s") Exception "%s"') % ( + FBID, cmd, '\n'.join(traceback.format_exception(*exp)))) else: - res=str(result) - self.python_runtime_vars["FBID"]=None - except Exception,e: + res = str(result) + self.python_runtime_vars["FBID"] = None + except Exception, e: res = "#EXCEPTION : "+str(e) - self.LogMessage(1,('PyEval@0x%x(Code="%s") Exception "%s"')%(FBID,cmd,str(e))) + self.LogMessage(1, ('PyEval@0x%x(Code="%s") Exception "%s"') % (FBID, cmd, str(e))) def StartPLC(self): if self.CurrentPLCFilename is not None and self.PLCStatus == "Stopped": c_argv = ctypes.c_char_p * len(self.argv) error = None - res = self._startPLC(len(self.argv),c_argv(*self.argv)) + res = self._startPLC(len(self.argv), c_argv(*self.argv)) if res == 0: self.PLCStatus = "Started" self.StatusChange() self.PythonRuntimeCall("start") - self.StartSem=Semaphore(0) + self.StartSem = Semaphore(0) self.PythonThread = Thread(target=self.PythonThreadProc) self.PythonThread.start() self.StartSem.acquire() self.LogMessage("PLC started") else: - self.LogMessage(0,_("Problem starting PLC : error %d" % res)) + self.LogMessage(0, _("Problem starting PLC : error %d" % res)) self.PLCStatus = "Broken" self.StatusChange() @@ -378,7 +384,7 @@ self.PLCStatus = "Stopped" self.StatusChange() self.PythonRuntimeCall("stop") - if self.TraceThread is not None : + if self.TraceThread is not None: self.TraceWakeup.set() self.TraceThread.join() self.TraceThread = None @@ -388,26 +394,26 @@ def _Reload(self): self.daemon.shutdown(True) self.daemon.sock.close() - os.execv(sys.executable,[sys.executable]+sys.argv[:]) + os.execv(sys.executable, [sys.executable]+sys.argv[:]) # never reached return 0 def ForceReload(self): # respawn python interpreter - Timer(0.1,self._Reload).start() + Timer(0.1, self._Reload).start() return True def GetPLCstatus(self): - return self.PLCStatus, map(self.GetLogCount,xrange(LogLevelsCount)) + return self.PLCStatus, map(self.GetLogCount, xrange(LogLevelsCount)) def NewPLC(self, md5sum, data, extrafiles): if self.PLCStatus in ["Stopped", "Empty", "Broken"]: NewFileName = md5sum + lib_ext - extra_files_log = os.path.join(self.workingdir,"extra_files.txt") + extra_files_log = os.path.join(self.workingdir, "extra_files.txt") self.UnLoadPLC() - self.LogMessage("NewPLC (%s)"%md5sum) + self.LogMessage("NewPLC (%s)" % md5sum) self.PLCStatus = "Empty" try: @@ -416,14 +422,14 @@ for filename in file(extra_files_log, "r").readlines() + [extra_files_log]: try: os.remove(os.path.join(self.workingdir, filename.strip())) - except: + except Exception: pass - except: + except Exception: pass try: # Create new PLC file - open(os.path.join(self.workingdir,NewFileName), + open(os.path.join(self.workingdir, NewFileName), 'wb').write(data) # Store new PLC filename based on md5 key @@ -431,14 +437,14 @@ # Then write the files log = file(extra_files_log, "w") - for fname,fdata in extrafiles: - fpath = os.path.join(self.workingdir,fname) + for fname, fdata in extrafiles: + fpath = os.path.join(self.workingdir, fname) open(fpath, "wb").write(fdata) log.write(fname+'\n') # Store new PLC filename self.CurrentPLCFilename = NewFileName - except: + except Exception: self.PLCStatus = "Broken" self.StatusChange() PLCprint(traceback.format_exc()) @@ -458,7 +464,7 @@ try: last_md5 = open(self._GetMD5FileName(), "r").read() return last_md5 == MD5 - except: + except Exception: pass return False @@ -472,12 +478,12 @@ if self._suspendDebug(False) == 0: # keep a copy of requested idx self._ResetDebugVariables() - for idx,iectype,force in idxs: - if force !=None: - c_type,unpack_func, pack_func = \ + for idx, iectype, force in idxs: + if force is not None: + c_type, unpack_func, pack_func = \ TypeTranslator.get(iectype, - (None,None,None)) - force = ctypes.byref(pack_func(c_type,force)) + (None, None, None)) + force = ctypes.byref(pack_func(c_type, force)) self._RegisterDebugVariable(idx, force) self._TracesSwap() self._resumeDebug() @@ -487,7 +493,7 @@ def _TracesPush(self, trace): self.TraceLock.acquire() lT = len(self.Traces) - if lT != 0 and lT * len(self.Traces[0]) > 1024 * 1024 : + if lT != 0 and lT * len(self.Traces[0]) > 1024 * 1024: self.Traces.pop(0) self.Traces.append(trace) self.TraceLock.release() @@ -511,10 +517,10 @@ self.TraceLock.acquire() self.Traces = [] self.TraceLock.release() - self._suspendDebug(True) # Disable debugger + self._suspendDebug(True) # Disable debugger self.TraceWakeup.clear() self.TraceWakeup.wait() - self._resumeDebug() # Re-enable debugger + self._resumeDebug() # Re-enable debugger def _TracesFlush(self): self.TraceLock.acquire() @@ -528,7 +534,7 @@ """ Return a list of traces, corresponding to the list of required idx """ - while self.PLCStatus == "Started" : + while self.PLCStatus == "Started": tick = ctypes.c_uint32() size = ctypes.c_uint32() buff = ctypes.c_void_p() @@ -546,15 +552,12 @@ self._TracesAutoSuspend() self._TracesFlush() - def RemoteExec(self, script, *kwargs): try: exec script in kwargs - except: + except Exception: e_type, e_value, e_traceback = sys.exc_info() line_no = traceback.tb_lineno(get_last_traceback(e_traceback)) return (-1, "RemoteExec script failed!\n\nLine %d: %s\n\t%s" % (line_no, e_value, script.splitlines()[line_no - 1])) return (0, kwargs.get("returnVal", None)) - -