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 import Pyro.core as pyro |
24 import Pyro.core as pyro |
25 from threading import Timer, Thread, Lock, Semaphore, Event |
25 from threading import Timer, Thread, Lock, Semaphore, Event |
26 import ctypes, os, commands, types, sys |
26 import ctypes |
|
27 import os |
|
28 import commands |
|
29 import types |
|
30 import sys |
|
31 import traceback |
27 from targets.typemapping import LogLevelsDefault, LogLevelsCount, TypeTranslator, UnpackDebugBuffer |
32 from targets.typemapping import LogLevelsDefault, LogLevelsCount, TypeTranslator, UnpackDebugBuffer |
28 from time import time |
33 from time import time |
29 |
34 |
30 |
35 |
31 if os.name in ("nt", "ce"): |
36 if os.name in ("nt", "ce"): |
32 from _ctypes import LoadLibrary as dlopen |
37 from _ctypes import LoadLibrary as dlopen |
33 from _ctypes import FreeLibrary as dlclose |
38 from _ctypes import FreeLibrary as dlclose |
34 elif os.name == "posix": |
39 elif os.name == "posix": |
35 from _ctypes import dlopen, dlclose |
40 from _ctypes import dlopen, dlclose |
36 |
41 |
37 import traceback |
42 |
38 def get_last_traceback(tb): |
43 def get_last_traceback(tb): |
39 while tb.tb_next: |
44 while tb.tb_next: |
40 tb = tb.tb_next |
45 tb = tb.tb_next |
41 return tb |
46 return tb |
42 |
47 |
43 lib_ext ={ |
48 |
44 "linux2":".so", |
49 lib_ext = { |
45 "win32":".dll", |
50 "linux2": ".so", |
|
51 "win32": ".dll", |
46 }.get(sys.platform, "") |
52 }.get(sys.platform, "") |
|
53 |
47 |
54 |
48 def PLCprint(message): |
55 def PLCprint(message): |
49 sys.stdout.write("PLCobject : "+message+"\n") |
56 sys.stdout.write("PLCobject : "+message+"\n") |
50 sys.stdout.flush() |
57 sys.stdout.flush() |
|
58 |
51 |
59 |
52 class PLCObject(pyro.ObjBase): |
60 class PLCObject(pyro.ObjBase): |
53 def __init__(self, workingdir, daemon, argv, statuschange, evaluator, pyruntimevars): |
61 def __init__(self, workingdir, daemon, argv, statuschange, evaluator, pyruntimevars): |
54 pyro.ObjBase.__init__(self) |
62 pyro.ObjBase.__init__(self) |
55 self.evaluator = evaluator |
63 self.evaluator = evaluator |
56 self.argv = [workingdir] + argv # force argv[0] to be "path" to exec... |
64 self.argv = [workingdir] + argv # force argv[0] to be "path" to exec... |
57 self.workingdir = workingdir |
65 self.workingdir = workingdir |
58 self.PLCStatus = "Empty" |
66 self.PLCStatus = "Empty" |
59 self.PLClibraryHandle = None |
67 self.PLClibraryHandle = None |
60 self.PLClibraryLock = Lock() |
68 self.PLClibraryLock = Lock() |
61 self.DummyIteratorLock = None |
69 self.DummyIteratorLock = None |
100 def ResetLogCount(self): |
108 def ResetLogCount(self): |
101 if self._ResetLogCount is not None: |
109 if self._ResetLogCount is not None: |
102 self._ResetLogCount() |
110 self._ResetLogCount() |
103 |
111 |
104 def GetLogCount(self, level): |
112 def GetLogCount(self, level): |
105 if self._GetLogCount is not None : |
113 if self._GetLogCount is not None: |
106 return int(self._GetLogCount(level)) |
114 return int(self._GetLogCount(level)) |
107 elif self._loading_error is not None and level==0: |
115 elif self._loading_error is not None and level == 0: |
108 return 1 |
116 return 1 |
109 |
117 |
110 def GetLogMessage(self, level, msgid): |
118 def GetLogMessage(self, level, msgid): |
111 tick = ctypes.c_uint32() |
119 tick = ctypes.c_uint32() |
112 tv_sec = ctypes.c_uint32() |
120 tv_sec = ctypes.c_uint32() |
113 tv_nsec = ctypes.c_uint32() |
121 tv_nsec = ctypes.c_uint32() |
114 if self._GetLogMessage is not None: |
122 if self._GetLogMessage is not None: |
115 maxsz = len(self._log_read_buffer)-1 |
123 maxsz = len(self._log_read_buffer)-1 |
116 sz = self._GetLogMessage(level, msgid, |
124 sz = self._GetLogMessage(level, msgid, |
117 self._log_read_buffer, maxsz, |
125 self._log_read_buffer, maxsz, |
118 ctypes.byref(tick), |
126 ctypes.byref(tick), |
119 ctypes.byref(tv_sec), |
127 ctypes.byref(tv_sec), |
120 ctypes.byref(tv_nsec)) |
128 ctypes.byref(tv_nsec)) |
121 if sz and sz <= maxsz: |
129 if sz and sz <= maxsz: |
122 self._log_read_buffer[sz] = '\x00' |
130 self._log_read_buffer[sz] = '\x00' |
123 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 |
124 elif self._loading_error is not None and level==0: |
132 elif self._loading_error is not None and level == 0: |
125 return self._loading_error,0,0,0 |
133 return self._loading_error, 0, 0, 0 |
126 return None |
134 return None |
127 |
135 |
128 def _GetMD5FileName(self): |
136 def _GetMD5FileName(self): |
129 return os.path.join(self.workingdir, "lasttransferedPLC.md5") |
137 return os.path.join(self.workingdir, "lasttransferedPLC.md5") |
130 |
138 |
131 def _GetLibFileName(self): |
139 def _GetLibFileName(self): |
132 return os.path.join(self.workingdir,self.CurrentPLCFilename) |
140 return os.path.join(self.workingdir, self.CurrentPLCFilename) |
133 |
|
134 |
141 |
135 def LoadPLC(self): |
142 def LoadPLC(self): |
136 """ |
143 """ |
137 Load PLC library |
144 Load PLC library |
138 Declare all functions, arguments and return values |
145 Declare all functions, arguments and return values |
205 |
212 |
206 self._LogMessage = self.PLClibraryHandle.LogMessage |
213 self._LogMessage = self.PLClibraryHandle.LogMessage |
207 self._LogMessage.restype = ctypes.c_int |
214 self._LogMessage.restype = ctypes.c_int |
208 self._LogMessage.argtypes = [ctypes.c_uint8, ctypes.c_char_p, ctypes.c_uint32] |
215 self._LogMessage.argtypes = [ctypes.c_uint8, ctypes.c_char_p, ctypes.c_uint32] |
209 |
216 |
210 self._log_read_buffer = ctypes.create_string_buffer(1<<14) #16K |
217 self._log_read_buffer = ctypes.create_string_buffer(1 << 14) # 16K |
211 self._GetLogMessage = self.PLClibraryHandle.GetLogMessage |
218 self._GetLogMessage = self.PLClibraryHandle.GetLogMessage |
212 self._GetLogMessage.restype = ctypes.c_uint32 |
219 self._GetLogMessage.restype = ctypes.c_uint32 |
213 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)] |
220 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)] |
214 |
221 |
215 self._loading_error = None |
222 self._loading_error = None |
216 |
223 |
217 self.PythonRuntimeInit() |
224 self.PythonRuntimeInit() |
218 |
225 |
219 return True |
226 return True |
220 except: |
227 except Exception: |
221 self._loading_error = traceback.format_exc() |
228 self._loading_error = traceback.format_exc() |
222 PLCprint(self._loading_error) |
229 PLCprint(self._loading_error) |
223 return False |
230 return False |
224 |
231 |
225 def UnLoadPLC(self): |
232 def UnLoadPLC(self): |
231 Unload PLC library. |
238 Unload PLC library. |
232 This is also called by __init__ to create dummy C func proxies |
239 This is also called by __init__ to create dummy C func proxies |
233 """ |
240 """ |
234 self.PLClibraryLock.acquire() |
241 self.PLClibraryLock.acquire() |
235 # Forget all refs to library |
242 # Forget all refs to library |
236 self._startPLC = lambda x,y:None |
243 self._startPLC = lambda x, y: None |
237 self._stopPLC = lambda:None |
244 self._stopPLC = lambda: None |
238 self._ResetDebugVariables = lambda:None |
245 self._ResetDebugVariables = lambda: None |
239 self._RegisterDebugVariable = lambda x, y:None |
246 self._RegisterDebugVariable = lambda x, y: None |
240 self._IterDebugData = lambda x,y:None |
247 self._IterDebugData = lambda x, y: None |
241 self._FreeDebugData = lambda:None |
248 self._FreeDebugData = lambda: None |
242 self._GetDebugData = lambda:-1 |
249 self._GetDebugData = lambda: -1 |
243 self._suspendDebug = lambda x:-1 |
250 self._suspendDebug = lambda x: -1 |
244 self._resumeDebug = lambda:None |
251 self._resumeDebug = lambda: None |
245 self._PythonIterator = lambda:"" |
252 self._PythonIterator = lambda: "" |
246 self._GetLogCount = None |
253 self._GetLogCount = None |
247 self._LogMessage = lambda l,m,s:PLCprint("OFF LOG :"+m) |
254 self._LogMessage = lambda l, m, s: PLCprint("OFF LOG :"+m) |
248 self._GetLogMessage = None |
255 self._GetLogMessage = None |
249 self.PLClibraryHandle = None |
256 self.PLClibraryHandle = None |
250 # Unload library explicitely |
257 # Unload library explicitely |
251 if getattr(self,"_PLClibraryHandle",None) is not None: |
258 if getattr(self, "_PLClibraryHandle", None) is not None: |
252 dlclose(self._PLClibraryHandle) |
259 dlclose(self._PLClibraryHandle) |
253 self._PLClibraryHandle = None |
260 self._PLClibraryHandle = None |
254 |
261 |
255 self.PLClibraryLock.release() |
262 self.PLClibraryLock.release() |
256 return False |
263 return False |
258 def PythonRuntimeCall(self, methodname): |
265 def PythonRuntimeCall(self, methodname): |
259 """ |
266 """ |
260 Calls init, start, stop or cleanup method provided by |
267 Calls init, start, stop or cleanup method provided by |
261 runtime python files, loaded when new PLC uploaded |
268 runtime python files, loaded when new PLC uploaded |
262 """ |
269 """ |
263 for method in self.python_runtime_vars.get("_runtime_%s"%methodname, []): |
270 for method in self.python_runtime_vars.get("_runtime_%s" % methodname, []): |
264 res,exp = self.evaluator(method) |
271 res, exp = self.evaluator(method) |
265 if exp is not None: |
272 if exp is not None: |
266 self.LogMessage(0,'\n'.join(traceback.format_exception(*exp))) |
273 self.LogMessage(0, '\n'.join(traceback.format_exception(*exp))) |
267 |
274 |
268 def PythonRuntimeInit(self): |
275 def PythonRuntimeInit(self): |
269 MethodNames = ["init", "start", "stop", "cleanup"] |
276 MethodNames = ["init", "start", "stop", "cleanup"] |
270 self.python_runtime_vars = globals().copy() |
277 self.python_runtime_vars = globals().copy() |
271 self.python_runtime_vars.update(self.pyruntimevars) |
278 self.python_runtime_vars.update(self.pyruntimevars) |
272 |
279 |
273 class PLCSafeGlobals: |
280 class PLCSafeGlobals: |
274 def __getattr__(_self, name): |
281 def __getattr__(_self, name): |
275 try : |
282 try: |
276 t = self.python_runtime_vars["_"+name+"_ctype"] |
283 t = self.python_runtime_vars["_"+name+"_ctype"] |
277 except KeyError: |
284 except KeyError: |
278 raise KeyError("Try to get unknown shared global variable : %s"%name) |
285 raise KeyError("Try to get unknown shared global variable : %s" % name) |
279 v = t() |
286 v = t() |
280 r = self.python_runtime_vars["_PySafeGetPLCGlob_"+name](ctypes.byref(v)) |
287 r = self.python_runtime_vars["_PySafeGetPLCGlob_"+name](ctypes.byref(v)) |
281 return self.python_runtime_vars["_"+name+"_unpack"](v) |
288 return self.python_runtime_vars["_"+name+"_unpack"](v) |
|
289 |
282 def __setattr__(_self, name, value): |
290 def __setattr__(_self, name, value): |
283 try : |
291 try: |
284 t = self.python_runtime_vars["_"+name+"_ctype"] |
292 t = self.python_runtime_vars["_"+name+"_ctype"] |
285 except KeyError: |
293 except KeyError: |
286 raise KeyError("Try to set unknown shared global variable : %s"%name) |
294 raise KeyError("Try to set unknown shared global variable : %s" % name) |
287 v = self.python_runtime_vars["_"+name+"_pack"](t,value) |
295 v = self.python_runtime_vars["_"+name+"_pack"](t, value) |
288 self.python_runtime_vars["_PySafeSetPLCGlob_"+name](ctypes.byref(v)) |
296 self.python_runtime_vars["_PySafeSetPLCGlob_"+name](ctypes.byref(v)) |
289 |
297 |
290 self.python_runtime_vars.update({ |
298 self.python_runtime_vars.update({ |
291 "PLCGlobals" : PLCSafeGlobals(), |
299 "PLCGlobals": PLCSafeGlobals(), |
292 "WorkingDir" : self.workingdir, |
300 "WorkingDir": self.workingdir, |
293 "PLCObject" : self, |
301 "PLCObject": self, |
294 "PLCBinary" : self.PLClibraryHandle, |
302 "PLCBinary": self.PLClibraryHandle, |
295 "PLCGlobalsDesc" : []}) |
303 "PLCGlobalsDesc": []}) |
296 |
304 |
297 for methodname in MethodNames : |
305 for methodname in MethodNames: |
298 self.python_runtime_vars["_runtime_%s"%methodname] = [] |
306 self.python_runtime_vars["_runtime_%s" % methodname] = [] |
299 |
307 |
300 try: |
308 try: |
301 filenames = os.listdir(self.workingdir) |
309 filenames = os.listdir(self.workingdir) |
302 filenames.sort() |
310 filenames.sort() |
303 for filename in filenames: |
311 for filename in filenames: |
305 if name.upper().startswith("RUNTIME") and ext.upper() == ".PY": |
313 if name.upper().startswith("RUNTIME") and ext.upper() == ".PY": |
306 execfile(os.path.join(self.workingdir, filename), self.python_runtime_vars) |
314 execfile(os.path.join(self.workingdir, filename), self.python_runtime_vars) |
307 for methodname in MethodNames: |
315 for methodname in MethodNames: |
308 method = self.python_runtime_vars.get("_%s_%s" % (name, methodname), None) |
316 method = self.python_runtime_vars.get("_%s_%s" % (name, methodname), None) |
309 if method is not None: |
317 if method is not None: |
310 self.python_runtime_vars["_runtime_%s"%methodname].append(method) |
318 self.python_runtime_vars["_runtime_%s" % methodname].append(method) |
311 except: |
319 except Exception: |
312 self.LogMessage(0,traceback.format_exc()) |
320 self.LogMessage(0, traceback.format_exc()) |
313 raise |
321 raise |
314 |
322 |
315 self.PythonRuntimeCall("init") |
323 self.PythonRuntimeCall("init") |
316 |
|
317 |
|
318 |
324 |
319 def PythonRuntimeCleanup(self): |
325 def PythonRuntimeCleanup(self): |
320 if self.python_runtime_vars is not None: |
326 if self.python_runtime_vars is not None: |
321 self.PythonRuntimeCall("cleanup") |
327 self.PythonRuntimeCall("cleanup") |
322 |
328 |
323 self.python_runtime_vars = None |
329 self.python_runtime_vars = None |
324 |
330 |
325 def PythonThreadProc(self): |
331 def PythonThreadProc(self): |
326 self.StartSem.release() |
332 self.StartSem.release() |
327 res,cmd,blkid = "None","None",ctypes.c_void_p() |
333 res, cmd, blkid = "None", "None", ctypes.c_void_p() |
328 compile_cache={} |
334 compile_cache = {} |
329 while True: |
335 while True: |
330 # print "_PythonIterator(", res, ")", |
336 # print "_PythonIterator(", res, ")", |
331 cmd = self._PythonIterator(res,blkid) |
337 cmd = self._PythonIterator(res, blkid) |
332 FBID = blkid.value |
338 FBID = blkid.value |
333 # print " -> ", cmd, blkid |
339 # print " -> ", cmd, blkid |
334 if cmd is None: |
340 if cmd is None: |
335 break |
341 break |
336 try : |
342 try: |
337 self.python_runtime_vars["FBID"]=FBID |
343 self.python_runtime_vars["FBID"] = FBID |
338 ccmd,AST =compile_cache.get(FBID, (None,None)) |
344 ccmd, AST = compile_cache.get(FBID, (None, None)) |
339 if ccmd is None or ccmd!=cmd: |
345 if ccmd is None or ccmd != cmd: |
340 AST = compile(cmd, '<plc>', 'eval') |
346 AST = compile(cmd, '<plc>', 'eval') |
341 compile_cache[FBID]=(cmd,AST) |
347 compile_cache[FBID] = (cmd, AST) |
342 result,exp = self.evaluator(eval,AST,self.python_runtime_vars) |
348 result, exp = self.evaluator(eval, AST, self.python_runtime_vars) |
343 if exp is not None: |
349 if exp is not None: |
344 res = "#EXCEPTION : "+str(exp[1]) |
350 res = "#EXCEPTION : "+str(exp[1]) |
345 self.LogMessage(1,('PyEval@0x%x(Code="%s") Exception "%s"')%(FBID,cmd, |
351 self.LogMessage(1, ('PyEval@0x%x(Code="%s") Exception "%s"') % ( |
346 '\n'.join(traceback.format_exception(*exp)))) |
352 FBID, cmd, '\n'.join(traceback.format_exception(*exp)))) |
347 else: |
353 else: |
348 res=str(result) |
354 res = str(result) |
349 self.python_runtime_vars["FBID"]=None |
355 self.python_runtime_vars["FBID"] = None |
350 except Exception,e: |
356 except Exception, e: |
351 res = "#EXCEPTION : "+str(e) |
357 res = "#EXCEPTION : "+str(e) |
352 self.LogMessage(1,('PyEval@0x%x(Code="%s") Exception "%s"')%(FBID,cmd,str(e))) |
358 self.LogMessage(1, ('PyEval@0x%x(Code="%s") Exception "%s"') % (FBID, cmd, str(e))) |
353 |
359 |
354 def StartPLC(self): |
360 def StartPLC(self): |
355 if self.CurrentPLCFilename is not None and self.PLCStatus == "Stopped": |
361 if self.CurrentPLCFilename is not None and self.PLCStatus == "Stopped": |
356 c_argv = ctypes.c_char_p * len(self.argv) |
362 c_argv = ctypes.c_char_p * len(self.argv) |
357 error = None |
363 error = None |
358 res = self._startPLC(len(self.argv),c_argv(*self.argv)) |
364 res = self._startPLC(len(self.argv), c_argv(*self.argv)) |
359 if res == 0: |
365 if res == 0: |
360 self.PLCStatus = "Started" |
366 self.PLCStatus = "Started" |
361 self.StatusChange() |
367 self.StatusChange() |
362 self.PythonRuntimeCall("start") |
368 self.PythonRuntimeCall("start") |
363 self.StartSem=Semaphore(0) |
369 self.StartSem = Semaphore(0) |
364 self.PythonThread = Thread(target=self.PythonThreadProc) |
370 self.PythonThread = Thread(target=self.PythonThreadProc) |
365 self.PythonThread.start() |
371 self.PythonThread.start() |
366 self.StartSem.acquire() |
372 self.StartSem.acquire() |
367 self.LogMessage("PLC started") |
373 self.LogMessage("PLC started") |
368 else: |
374 else: |
369 self.LogMessage(0,_("Problem starting PLC : error %d" % res)) |
375 self.LogMessage(0, _("Problem starting PLC : error %d" % res)) |
370 self.PLCStatus = "Broken" |
376 self.PLCStatus = "Broken" |
371 self.StatusChange() |
377 self.StatusChange() |
372 |
378 |
373 def StopPLC(self): |
379 def StopPLC(self): |
374 if self.PLCStatus == "Started": |
380 if self.PLCStatus == "Started": |
376 self._stopPLC() |
382 self._stopPLC() |
377 self.PythonThread.join() |
383 self.PythonThread.join() |
378 self.PLCStatus = "Stopped" |
384 self.PLCStatus = "Stopped" |
379 self.StatusChange() |
385 self.StatusChange() |
380 self.PythonRuntimeCall("stop") |
386 self.PythonRuntimeCall("stop") |
381 if self.TraceThread is not None : |
387 if self.TraceThread is not None: |
382 self.TraceWakeup.set() |
388 self.TraceWakeup.set() |
383 self.TraceThread.join() |
389 self.TraceThread.join() |
384 self.TraceThread = None |
390 self.TraceThread = None |
385 return True |
391 return True |
386 return False |
392 return False |
387 |
393 |
388 def _Reload(self): |
394 def _Reload(self): |
389 self.daemon.shutdown(True) |
395 self.daemon.shutdown(True) |
390 self.daemon.sock.close() |
396 self.daemon.sock.close() |
391 os.execv(sys.executable,[sys.executable]+sys.argv[:]) |
397 os.execv(sys.executable, [sys.executable]+sys.argv[:]) |
392 # never reached |
398 # never reached |
393 return 0 |
399 return 0 |
394 |
400 |
395 def ForceReload(self): |
401 def ForceReload(self): |
396 # respawn python interpreter |
402 # respawn python interpreter |
397 Timer(0.1,self._Reload).start() |
403 Timer(0.1, self._Reload).start() |
398 return True |
404 return True |
399 |
405 |
400 def GetPLCstatus(self): |
406 def GetPLCstatus(self): |
401 return self.PLCStatus, map(self.GetLogCount,xrange(LogLevelsCount)) |
407 return self.PLCStatus, map(self.GetLogCount, xrange(LogLevelsCount)) |
402 |
408 |
403 def NewPLC(self, md5sum, data, extrafiles): |
409 def NewPLC(self, md5sum, data, extrafiles): |
404 if self.PLCStatus in ["Stopped", "Empty", "Broken"]: |
410 if self.PLCStatus in ["Stopped", "Empty", "Broken"]: |
405 NewFileName = md5sum + lib_ext |
411 NewFileName = md5sum + lib_ext |
406 extra_files_log = os.path.join(self.workingdir,"extra_files.txt") |
412 extra_files_log = os.path.join(self.workingdir, "extra_files.txt") |
407 |
413 |
408 self.UnLoadPLC() |
414 self.UnLoadPLC() |
409 |
415 |
410 self.LogMessage("NewPLC (%s)"%md5sum) |
416 self.LogMessage("NewPLC (%s)" % md5sum) |
411 self.PLCStatus = "Empty" |
417 self.PLCStatus = "Empty" |
412 |
418 |
413 try: |
419 try: |
414 os.remove(os.path.join(self.workingdir, |
420 os.remove(os.path.join(self.workingdir, |
415 self.CurrentPLCFilename)) |
421 self.CurrentPLCFilename)) |
416 for filename in file(extra_files_log, "r").readlines() + [extra_files_log]: |
422 for filename in file(extra_files_log, "r").readlines() + [extra_files_log]: |
417 try: |
423 try: |
418 os.remove(os.path.join(self.workingdir, filename.strip())) |
424 os.remove(os.path.join(self.workingdir, filename.strip())) |
419 except: |
425 except Exception: |
420 pass |
426 pass |
421 except: |
427 except Exception: |
422 pass |
428 pass |
423 |
429 |
424 try: |
430 try: |
425 # Create new PLC file |
431 # Create new PLC file |
426 open(os.path.join(self.workingdir,NewFileName), |
432 open(os.path.join(self.workingdir, NewFileName), |
427 'wb').write(data) |
433 'wb').write(data) |
428 |
434 |
429 # Store new PLC filename based on md5 key |
435 # Store new PLC filename based on md5 key |
430 open(self._GetMD5FileName(), "w").write(md5sum) |
436 open(self._GetMD5FileName(), "w").write(md5sum) |
431 |
437 |
432 # Then write the files |
438 # Then write the files |
433 log = file(extra_files_log, "w") |
439 log = file(extra_files_log, "w") |
434 for fname,fdata in extrafiles: |
440 for fname, fdata in extrafiles: |
435 fpath = os.path.join(self.workingdir,fname) |
441 fpath = os.path.join(self.workingdir, fname) |
436 open(fpath, "wb").write(fdata) |
442 open(fpath, "wb").write(fdata) |
437 log.write(fname+'\n') |
443 log.write(fname+'\n') |
438 |
444 |
439 # Store new PLC filename |
445 # Store new PLC filename |
440 self.CurrentPLCFilename = NewFileName |
446 self.CurrentPLCFilename = NewFileName |
441 except: |
447 except Exception: |
442 self.PLCStatus = "Broken" |
448 self.PLCStatus = "Broken" |
443 self.StatusChange() |
449 self.StatusChange() |
444 PLCprint(traceback.format_exc()) |
450 PLCprint(traceback.format_exc()) |
445 return False |
451 return False |
446 |
452 |
470 if idxs: |
476 if idxs: |
471 # suspend but dont disable |
477 # suspend but dont disable |
472 if self._suspendDebug(False) == 0: |
478 if self._suspendDebug(False) == 0: |
473 # keep a copy of requested idx |
479 # keep a copy of requested idx |
474 self._ResetDebugVariables() |
480 self._ResetDebugVariables() |
475 for idx,iectype,force in idxs: |
481 for idx, iectype, force in idxs: |
476 if force !=None: |
482 if force is not None: |
477 c_type,unpack_func, pack_func = \ |
483 c_type, unpack_func, pack_func = \ |
478 TypeTranslator.get(iectype, |
484 TypeTranslator.get(iectype, |
479 (None,None,None)) |
485 (None, None, None)) |
480 force = ctypes.byref(pack_func(c_type,force)) |
486 force = ctypes.byref(pack_func(c_type, force)) |
481 self._RegisterDebugVariable(idx, force) |
487 self._RegisterDebugVariable(idx, force) |
482 self._TracesSwap() |
488 self._TracesSwap() |
483 self._resumeDebug() |
489 self._resumeDebug() |
484 else: |
490 else: |
485 self._suspendDebug(True) |
491 self._suspendDebug(True) |
486 |
492 |
487 def _TracesPush(self, trace): |
493 def _TracesPush(self, trace): |
488 self.TraceLock.acquire() |
494 self.TraceLock.acquire() |
489 lT = len(self.Traces) |
495 lT = len(self.Traces) |
490 if lT != 0 and lT * len(self.Traces[0]) > 1024 * 1024 : |
496 if lT != 0 and lT * len(self.Traces[0]) > 1024 * 1024: |
491 self.Traces.pop(0) |
497 self.Traces.pop(0) |
492 self.Traces.append(trace) |
498 self.Traces.append(trace) |
493 self.TraceLock.release() |
499 self.TraceLock.release() |
494 |
500 |
495 def _TracesSwap(self): |
501 def _TracesSwap(self): |
544 if TraceBuffer is not None: |
550 if TraceBuffer is not None: |
545 self._TracesPush((tick.value, TraceBuffer)) |
551 self._TracesPush((tick.value, TraceBuffer)) |
546 self._TracesAutoSuspend() |
552 self._TracesAutoSuspend() |
547 self._TracesFlush() |
553 self._TracesFlush() |
548 |
554 |
549 |
|
550 def RemoteExec(self, script, *kwargs): |
555 def RemoteExec(self, script, *kwargs): |
551 try: |
556 try: |
552 exec script in kwargs |
557 exec script in kwargs |
553 except: |
558 except Exception: |
554 e_type, e_value, e_traceback = sys.exc_info() |
559 e_type, e_value, e_traceback = sys.exc_info() |
555 line_no = traceback.tb_lineno(get_last_traceback(e_traceback)) |
560 line_no = traceback.tb_lineno(get_last_traceback(e_traceback)) |
556 return (-1, "RemoteExec script failed!\n\nLine %d: %s\n\t%s" % |
561 return (-1, "RemoteExec script failed!\n\nLine %d: %s\n\t%s" % |
557 (line_no, e_value, script.splitlines()[line_no - 1])) |
562 (line_no, e_value, script.splitlines()[line_no - 1])) |
558 return (0, kwargs.get("returnVal", None)) |
563 return (0, kwargs.get("returnVal", None)) |
559 |
|
560 |
|