126 ctypes.byref(tick), |
126 ctypes.byref(tick), |
127 ctypes.byref(tv_sec), |
127 ctypes.byref(tv_sec), |
128 ctypes.byref(tv_nsec)) |
128 ctypes.byref(tv_nsec)) |
129 if sz and sz <= maxsz: |
129 if sz and sz <= maxsz: |
130 self._log_read_buffer[sz] = '\x00' |
130 self._log_read_buffer[sz] = '\x00' |
131 return self._log_read_buffer.value,tick.value,tv_sec.value,tv_nsec.value |
131 return self._log_read_buffer.value, tick.value, tv_sec.value, tv_nsec.value |
132 elif self._loading_error is not None and level==0: |
132 elif self._loading_error is not None and level==0: |
133 return self._loading_error,0,0,0 |
133 return self._loading_error, 0, 0, 0 |
134 return None |
134 return None |
135 |
135 |
136 def _GetMD5FileName(self): |
136 def _GetMD5FileName(self): |
137 return os.path.join(self.workingdir, "lasttransferedPLC.md5") |
137 return os.path.join(self.workingdir, "lasttransferedPLC.md5") |
138 |
138 |
139 def _GetLibFileName(self): |
139 def _GetLibFileName(self): |
140 return os.path.join(self.workingdir,self.CurrentPLCFilename) |
140 return os.path.join(self.workingdir, self.CurrentPLCFilename) |
141 |
141 |
142 |
142 |
143 def LoadPLC(self): |
143 def LoadPLC(self): |
144 """ |
144 """ |
145 Load PLC library |
145 Load PLC library |
239 Unload PLC library. |
239 Unload PLC library. |
240 This is also called by __init__ to create dummy C func proxies |
240 This is also called by __init__ to create dummy C func proxies |
241 """ |
241 """ |
242 self.PLClibraryLock.acquire() |
242 self.PLClibraryLock.acquire() |
243 # Forget all refs to library |
243 # Forget all refs to library |
244 self._startPLC = lambda x,y:None |
244 self._startPLC = lambda x, y: None |
245 self._stopPLC = lambda:None |
245 self._stopPLC = lambda: None |
246 self._ResetDebugVariables = lambda:None |
246 self._ResetDebugVariables = lambda: None |
247 self._RegisterDebugVariable = lambda x, y:None |
247 self._RegisterDebugVariable = lambda x, y: None |
248 self._IterDebugData = lambda x,y:None |
248 self._IterDebugData = lambda x, y: None |
249 self._FreeDebugData = lambda:None |
249 self._FreeDebugData = lambda: None |
250 self._GetDebugData = lambda:-1 |
250 self._GetDebugData = lambda: -1 |
251 self._suspendDebug = lambda x:-1 |
251 self._suspendDebug = lambda x: -1 |
252 self._resumeDebug = lambda:None |
252 self._resumeDebug = lambda: None |
253 self._PythonIterator = lambda:"" |
253 self._PythonIterator = lambda: "" |
254 self._GetLogCount = None |
254 self._GetLogCount = None |
255 self._LogMessage = lambda l,m,s:PLCprint("OFF LOG :"+m) |
255 self._LogMessage = lambda l, m, s: PLCprint("OFF LOG :"+m) |
256 self._GetLogMessage = None |
256 self._GetLogMessage = None |
257 self.PLClibraryHandle = None |
257 self.PLClibraryHandle = None |
258 # Unload library explicitely |
258 # Unload library explicitely |
259 if getattr(self,"_PLClibraryHandle",None) is not None: |
259 if getattr(self, "_PLClibraryHandle", None) is not None: |
260 dlclose(self._PLClibraryHandle) |
260 dlclose(self._PLClibraryHandle) |
261 self._PLClibraryHandle = None |
261 self._PLClibraryHandle = None |
262 |
262 |
263 self.PLClibraryLock.release() |
263 self.PLClibraryLock.release() |
264 return False |
264 return False |
267 """ |
267 """ |
268 Calls init, start, stop or cleanup method provided by |
268 Calls init, start, stop or cleanup method provided by |
269 runtime python files, loaded when new PLC uploaded |
269 runtime python files, loaded when new PLC uploaded |
270 """ |
270 """ |
271 for method in self.python_runtime_vars.get("_runtime_%s" % methodname, []): |
271 for method in self.python_runtime_vars.get("_runtime_%s" % methodname, []): |
272 res,exp = self.evaluator(method) |
272 res, exp = self.evaluator(method) |
273 if exp is not None: |
273 if exp is not None: |
274 self.LogMessage(0,'\n'.join(traceback.format_exception(*exp))) |
274 self.LogMessage(0, '\n'.join(traceback.format_exception(*exp))) |
275 |
275 |
276 def PythonRuntimeInit(self): |
276 def PythonRuntimeInit(self): |
277 MethodNames = ["init", "start", "stop", "cleanup"] |
277 MethodNames = ["init", "start", "stop", "cleanup"] |
278 self.python_runtime_vars = globals().copy() |
278 self.python_runtime_vars = globals().copy() |
279 self.python_runtime_vars.update(self.pyruntimevars) |
279 self.python_runtime_vars.update(self.pyruntimevars) |
290 def __setattr__(_self, name, value): |
290 def __setattr__(_self, name, value): |
291 try: |
291 try: |
292 t = self.python_runtime_vars["_"+name+"_ctype"] |
292 t = self.python_runtime_vars["_"+name+"_ctype"] |
293 except KeyError: |
293 except KeyError: |
294 raise KeyError("Try to set unknown shared global variable : %s" % name) |
294 raise KeyError("Try to set unknown shared global variable : %s" % name) |
295 v = self.python_runtime_vars["_"+name+"_pack"](t,value) |
295 v = self.python_runtime_vars["_"+name+"_pack"](t, value) |
296 self.python_runtime_vars["_PySafeSetPLCGlob_"+name](ctypes.byref(v)) |
296 self.python_runtime_vars["_PySafeSetPLCGlob_"+name](ctypes.byref(v)) |
297 |
297 |
298 self.python_runtime_vars.update({ |
298 self.python_runtime_vars.update({ |
299 "PLCGlobals": PLCSafeGlobals(), |
299 "PLCGlobals": PLCSafeGlobals(), |
300 "WorkingDir": self.workingdir, |
300 "WorkingDir": self.workingdir, |
330 |
330 |
331 self.python_runtime_vars = None |
331 self.python_runtime_vars = None |
332 |
332 |
333 def PythonThreadProc(self): |
333 def PythonThreadProc(self): |
334 self.StartSem.release() |
334 self.StartSem.release() |
335 res,cmd,blkid = "None","None",ctypes.c_void_p() |
335 res, cmd, blkid = "None", "None", ctypes.c_void_p() |
336 compile_cache={} |
336 compile_cache={} |
337 while True: |
337 while True: |
338 # print "_PythonIterator(", res, ")", |
338 # print "_PythonIterator(", res, ")", |
339 cmd = self._PythonIterator(res,blkid) |
339 cmd = self._PythonIterator(res, blkid) |
340 FBID = blkid.value |
340 FBID = blkid.value |
341 # print " -> ", cmd, blkid |
341 # print " -> ", cmd, blkid |
342 if cmd is None: |
342 if cmd is None: |
343 break |
343 break |
344 try: |
344 try: |
345 self.python_runtime_vars["FBID"]=FBID |
345 self.python_runtime_vars["FBID"]=FBID |
346 ccmd,AST =compile_cache.get(FBID, (None,None)) |
346 ccmd, AST =compile_cache.get(FBID, (None, None)) |
347 if ccmd is None or ccmd!=cmd: |
347 if ccmd is None or ccmd!=cmd: |
348 AST = compile(cmd, '<plc>', 'eval') |
348 AST = compile(cmd, '<plc>', 'eval') |
349 compile_cache[FBID]=(cmd,AST) |
349 compile_cache[FBID]=(cmd, AST) |
350 result,exp = self.evaluator(eval,AST,self.python_runtime_vars) |
350 result, exp = self.evaluator(eval, AST, self.python_runtime_vars) |
351 if exp is not None: |
351 if exp is not None: |
352 res = "#EXCEPTION : "+str(exp[1]) |
352 res = "#EXCEPTION : "+str(exp[1]) |
353 self.LogMessage(1,('PyEval@0x%x(Code="%s") Exception "%s"') % (FBID,cmd, |
353 self.LogMessage(1, ('PyEval@0x%x(Code="%s") Exception "%s"') % (FBID, cmd, |
354 '\n'.join(traceback.format_exception(*exp)))) |
354 '\n'.join(traceback.format_exception(*exp)))) |
355 else: |
355 else: |
356 res=str(result) |
356 res=str(result) |
357 self.python_runtime_vars["FBID"]=None |
357 self.python_runtime_vars["FBID"]=None |
358 except Exception,e: |
358 except Exception, e: |
359 res = "#EXCEPTION : "+str(e) |
359 res = "#EXCEPTION : "+str(e) |
360 self.LogMessage(1,('PyEval@0x%x(Code="%s") Exception "%s"') % (FBID,cmd,str(e))) |
360 self.LogMessage(1, ('PyEval@0x%x(Code="%s") Exception "%s"') % (FBID, cmd, str(e))) |
361 |
361 |
362 def StartPLC(self): |
362 def StartPLC(self): |
363 if self.CurrentPLCFilename is not None and self.PLCStatus == "Stopped": |
363 if self.CurrentPLCFilename is not None and self.PLCStatus == "Stopped": |
364 c_argv = ctypes.c_char_p * len(self.argv) |
364 c_argv = ctypes.c_char_p * len(self.argv) |
365 error = None |
365 error = None |
366 res = self._startPLC(len(self.argv),c_argv(*self.argv)) |
366 res = self._startPLC(len(self.argv), c_argv(*self.argv)) |
367 if res == 0: |
367 if res == 0: |
368 self.PLCStatus = "Started" |
368 self.PLCStatus = "Started" |
369 self.StatusChange() |
369 self.StatusChange() |
370 self.PythonRuntimeCall("start") |
370 self.PythonRuntimeCall("start") |
371 self.StartSem=Semaphore(0) |
371 self.StartSem=Semaphore(0) |
372 self.PythonThread = Thread(target=self.PythonThreadProc) |
372 self.PythonThread = Thread(target=self.PythonThreadProc) |
373 self.PythonThread.start() |
373 self.PythonThread.start() |
374 self.StartSem.acquire() |
374 self.StartSem.acquire() |
375 self.LogMessage("PLC started") |
375 self.LogMessage("PLC started") |
376 else: |
376 else: |
377 self.LogMessage(0,_("Problem starting PLC : error %d" % res)) |
377 self.LogMessage(0, _("Problem starting PLC : error %d" % res)) |
378 self.PLCStatus = "Broken" |
378 self.PLCStatus = "Broken" |
379 self.StatusChange() |
379 self.StatusChange() |
380 |
380 |
381 def StopPLC(self): |
381 def StopPLC(self): |
382 if self.PLCStatus == "Started": |
382 if self.PLCStatus == "Started": |
394 return False |
394 return False |
395 |
395 |
396 def _Reload(self): |
396 def _Reload(self): |
397 self.daemon.shutdown(True) |
397 self.daemon.shutdown(True) |
398 self.daemon.sock.close() |
398 self.daemon.sock.close() |
399 os.execv(sys.executable,[sys.executable]+sys.argv[:]) |
399 os.execv(sys.executable, [sys.executable]+sys.argv[:]) |
400 # never reached |
400 # never reached |
401 return 0 |
401 return 0 |
402 |
402 |
403 def ForceReload(self): |
403 def ForceReload(self): |
404 # respawn python interpreter |
404 # respawn python interpreter |
405 Timer(0.1,self._Reload).start() |
405 Timer(0.1, self._Reload).start() |
406 return True |
406 return True |
407 |
407 |
408 def GetPLCstatus(self): |
408 def GetPLCstatus(self): |
409 return self.PLCStatus, map(self.GetLogCount,xrange(LogLevelsCount)) |
409 return self.PLCStatus, map(self.GetLogCount, xrange(LogLevelsCount)) |
410 |
410 |
411 def NewPLC(self, md5sum, data, extrafiles): |
411 def NewPLC(self, md5sum, data, extrafiles): |
412 if self.PLCStatus in ["Stopped", "Empty", "Broken"]: |
412 if self.PLCStatus in ["Stopped", "Empty", "Broken"]: |
413 NewFileName = md5sum + lib_ext |
413 NewFileName = md5sum + lib_ext |
414 extra_files_log = os.path.join(self.workingdir,"extra_files.txt") |
414 extra_files_log = os.path.join(self.workingdir, "extra_files.txt") |
415 |
415 |
416 self.UnLoadPLC() |
416 self.UnLoadPLC() |
417 |
417 |
418 self.LogMessage("NewPLC (%s)" % md5sum) |
418 self.LogMessage("NewPLC (%s)" % md5sum) |
419 self.PLCStatus = "Empty" |
419 self.PLCStatus = "Empty" |
429 except: |
429 except: |
430 pass |
430 pass |
431 |
431 |
432 try: |
432 try: |
433 # Create new PLC file |
433 # Create new PLC file |
434 open(os.path.join(self.workingdir,NewFileName), |
434 open(os.path.join(self.workingdir, NewFileName), |
435 'wb').write(data) |
435 'wb').write(data) |
436 |
436 |
437 # Store new PLC filename based on md5 key |
437 # Store new PLC filename based on md5 key |
438 open(self._GetMD5FileName(), "w").write(md5sum) |
438 open(self._GetMD5FileName(), "w").write(md5sum) |
439 |
439 |
440 # Then write the files |
440 # Then write the files |
441 log = file(extra_files_log, "w") |
441 log = file(extra_files_log, "w") |
442 for fname,fdata in extrafiles: |
442 for fname, fdata in extrafiles: |
443 fpath = os.path.join(self.workingdir,fname) |
443 fpath = os.path.join(self.workingdir, fname) |
444 open(fpath, "wb").write(fdata) |
444 open(fpath, "wb").write(fdata) |
445 log.write(fname+'\n') |
445 log.write(fname+'\n') |
446 |
446 |
447 # Store new PLC filename |
447 # Store new PLC filename |
448 self.CurrentPLCFilename = NewFileName |
448 self.CurrentPLCFilename = NewFileName |
478 if idxs: |
478 if idxs: |
479 # suspend but dont disable |
479 # suspend but dont disable |
480 if self._suspendDebug(False) == 0: |
480 if self._suspendDebug(False) == 0: |
481 # keep a copy of requested idx |
481 # keep a copy of requested idx |
482 self._ResetDebugVariables() |
482 self._ResetDebugVariables() |
483 for idx,iectype,force in idxs: |
483 for idx, iectype, force in idxs: |
484 if force !=None: |
484 if force !=None: |
485 c_type,unpack_func, pack_func = \ |
485 c_type, unpack_func, pack_func = \ |
486 TypeTranslator.get(iectype, |
486 TypeTranslator.get(iectype, |
487 (None,None,None)) |
487 (None, None, None)) |
488 force = ctypes.byref(pack_func(c_type,force)) |
488 force = ctypes.byref(pack_func(c_type, force)) |
489 self._RegisterDebugVariable(idx, force) |
489 self._RegisterDebugVariable(idx, force) |
490 self._TracesSwap() |
490 self._TracesSwap() |
491 self._resumeDebug() |
491 self._resumeDebug() |
492 else: |
492 else: |
493 self._suspendDebug(True) |
493 self._suspendDebug(True) |