runtime/PLCObject.py
changeset 1434 6e0cd0ceabb7
parent 1433 4a45f6642523
child 1435 291a17b755d1
--- a/runtime/PLCObject.py	Fri Jan 30 10:45:11 2015 +0100
+++ b/runtime/PLCObject.py	Fri Jan 30 20:42:24 2015 +0100
@@ -23,9 +23,10 @@
 #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
 import Pyro.core as pyro
-from threading import Timer, Thread, Lock, Semaphore
+from threading import Timer, Thread, Lock, Semaphore, Event
 import ctypes, os, commands, types, sys
 from targets.typemapping import LogLevelsDefault, LogLevelsCount, TypeTranslator, UnpackDebugBuffer
+from time import time
 
 
 if os.name in ("nt", "ce"):
@@ -50,7 +51,6 @@
     sys.stdout.flush()
 
 class PLCObject(pyro.ObjBase):
-    _Idxs = []
     def __init__(self, workingdir, daemon, argv, statuschange, evaluator, website):
         pyro.ObjBase.__init__(self)
         self.evaluator = evaluator
@@ -68,6 +68,10 @@
         self.website = website
         self._loading_error = None
         self.python_runtime_vars = None
+        self.TraceThread = None
+        self.TraceLock = Lock()
+        self.TraceWakeup = Event()
+        self.Traces = []
 
         # Get the last transfered PLC if connector must be restart
         try:
@@ -365,6 +369,10 @@
             self.LogMessage("PLC stopped")
             self._stopPLC()
             self.PythonThread.join()
+            if self.TraceThread is not None :
+                self.TraceWakeup.set()
+                self.TraceThread.join()
+                self.TraceThread = None
             return True
         return False
 
@@ -453,7 +461,6 @@
             # suspend but dont disable
             if self._suspendDebug(False) == 0:
                 # keep a copy of requested idx
-                self._Idxs = idxs[:]
                 self._ResetDebugVariables()
                 for idx,iectype,force in idxs:
                     if force !=None:
@@ -462,16 +469,55 @@
                                                     (None,None,None))
                         force = ctypes.byref(pack_func(c_type,force))
                     self._RegisterDebugVariable(idx, force)
+                self._TracesSwap()
                 self._resumeDebug()
         else:
             self._suspendDebug(True)
-            self._Idxs =  []
+
+    def _TracesPush(self, trace):
+        self.TraceLock.acquire()
+        lT = len(self.Traces)
+        if lT != 0 and lT * len(self.Traces[0]) > 1024 * 1024 :
+            self.Traces.pop(0)
+        self.Traces.append(trace)
+        self.TraceLock.release()
+
+    def _TracesSwap(self):
+        self.LastSwapTrace = time()
+        if self.TraceThread is None and self.PLCStatus == "Started":
+            self.TraceThread = Thread(target=self.TraceThreadProc)
+            self.TraceThread.start()
+        self.TraceLock.acquire()
+        Traces = self.Traces
+        self.Traces = []
+        self.TraceLock.release()
+        self.TraceWakeup.set()
+        return Traces
+
+    def _TracesAutoSuspend(self):
+        # TraceProc stops here if Traces not polled for 3 seconds
+        traces_age = time() - self.LastSwapTrace
+        if traces_age > 3:
+            self.TraceLock.acquire()
+            self.Traces = []
+            self.TraceLock.release()
+            self._suspendDebug(True) # Disable debugger
+            self.TraceWakeup.wait()
+            self._resumeDebug() # Re-enable debugger
+
+    def _TracesFlush(self):
+        self.TraceLock.acquire()
+        self.Traces = []
+        self.TraceLock.release()
 
     def GetTraceVariables(self):
-        """
-        Return a list of variables, corresponding to the list of required idx
-        """
-        if self.PLCStatus == "Started":
+        return self.PLCStatus, self._TracesSwap()
+
+    def TraceThreadProc(self):
+        """
+        Return a list of traces, corresponding to the list of required idx
+        """
+        while self.PLCStatus == "Started" :
             tick = ctypes.c_uint32()
             size = ctypes.c_uint32()
             buff = ctypes.c_void_p()
@@ -485,8 +531,10 @@
                     self._FreeDebugData()
                 self.PLClibraryLock.release()
             if TraceBuffer is not None:
-                return self.PLCStatus, tick.value, TraceBuffer
-        return self.PLCStatus, None, None
+                self._TracesPush((tick.value, TraceBuffer))
+            self._TracesAutoSuspend()
+        self._TracesFlush()
+
 
     def RemoteExec(self, script, **kwargs):
         try: