plugger.py
changeset 235 a66e150f2888
parent 228 848da15cf513
child 236 a32817e81f5e
--- a/plugger.py	Tue Sep 02 12:24:25 2008 +0200
+++ b/plugger.py	Wed Sep 03 17:28:17 2008 +0200
@@ -600,7 +600,7 @@
 ieclib_path = os.path.join(base_folder, "matiec", "lib")
 
 # import for project creation timestamping
-from threading import Timer, Lock
+from threading import Timer, Lock, Thread
 from time import localtime
 from datetime import datetime
 # import necessary stuff from PLCOpenEditor
@@ -617,6 +617,7 @@
 import targets
 import connectors
 from discovery import DiscoveryDialog
+from weakref import WeakKeyDictionary
 
 class PluginsRoot(PlugTemplate, PLCControler):
     """
@@ -666,10 +667,8 @@
         self.IECdebug_datas = {}
         self.IECdebug_lock = Lock()
 
-        # Timer to prevent rapid-fire when registering many variables
-        self.DebugTimer=Timer(0.5,self.RegisterDebugVarToConnector)
+        self.DebugTimer=None
         self.ResetIECProgramsAndVariables()
-
         
         #This method are not called here... but in NewProject and OpenProject
         #self._AddParamsMembers()
@@ -972,8 +971,8 @@
         self._ProgramList = None
         self._VariablesList = None
         self._IECPathToIdx = None
-        self._IdxToIECPath = None
-        
+        self.TracedIECPath = []
+
     def GetIECProgramsAndVariables(self):
         """
         Parse CSV-like file  VARIABLES.csv resulting from IEC2C compiler.
@@ -989,7 +988,6 @@
                 self._ProgramList = []
                 self._VariablesList = []
                 self._IECPathToIdx = {}
-                self._IdxToIECPath = {}
                 
                 # Separate sections
                 ListGroup = []
@@ -1023,7 +1021,6 @@
                     IEC_path=attrs["IEC_path"]
                     Idx=int(attrs["num"])
                     self._IECPathToIdx[IEC_path]=Idx
-                    self._IdxToIECPath[Idx]=IEC_path
             except Exception,e:
                 self.logger.write_error("Cannot open/parse VARIABLES.csv!\n")
                 self.logger.write_error(traceback.format_exc())
@@ -1059,28 +1056,31 @@
         return debug_code
 
     def RegisterDebugVarToConnector(self):
+        self.DebugTimer=None
         Idxs = []
+        self.TracedIECPath = []
         if self._connector is not None:
             self.IECdebug_lock.acquire()
-            for IECPath,data_tuple in self.IECdebug_datas:
+            for IECPath,data_tuple in self.IECdebug_datas.iteritems():
                 WeakCallableDict, data_log, status = data_tuple
                 if len(WeakCallableDict) == 0:
                     # Callable Dict is empty.
                     # This variable is not needed anymore!
                     # self.IECdebug_callables.pop(IECPath)
                     # TODO
-                    pass
+                    print "Unused : " + IECPath
                 else:
                     # Convert 
                     Idx = self._IECPathToIdx.get(IECPath,None)
                     if Idx is not None:
                         Idxs.append(Idx)
+                        self.TracedIECPath.append(IECPath)
                     else:
                         self.logger.write_warning("Debug : Unknown variable %s\n"%IECPath)
+            self._connector.SetTraceVariablesList(Idxs)
             self.IECdebug_lock.release()
-            self._connector.TraceVariables(Idxs)
-        
-    def SubscribeDebugIECVariable(self, IECPath, callable, *args, **kwargs):
+        
+    def SubscribeDebugIECVariable(self, IECPath, callableobj, *args, **kwargs):
         """
         Dispatching use a dictionnary linking IEC variable paths
         to a WeakKeyDictionary linking 
@@ -1096,12 +1096,20 @@
                     "Registered"]        # Variable status
             self.IECdebug_datas[IECPath] = IECdebug_data
         
-        IECdebug_data[0][callable]=(args, kwargs)
+        IECdebug_data[0][callableobj]=(args, kwargs)
 
         self.IECdebug_lock.release()
+
+        if self.DebugTimer is not None:
+            self.DebugTimer.cancel()
+
+        # Timer to prevent rapid-fire when registering many variables
+        # use wx.CallAfter use keep using same thread. TODO : use wx.Timer instead
+        self.DebugTimer=Timer(0.5,wx.CallAfter,args = [self.RegisterDebugVarToConnector])
         # Rearm anti-rapid-fire timer
-        self.DebugTimer.cancel()
         self.DebugTimer.start()
+
+        return IECdebug_data[1]
         
     def Generate_plc_common_main(self):
         """
@@ -1329,19 +1337,58 @@
             self.logger.write_error("Couldn't start PLC !\n")
         self.UpdateMethodsFromPLCStatus()
 
-    def _Debug(self): 
+    def DebugThreadProc(self):
+        while self._connector is not None:
+            debug_tick, debug_vars = self._connector.GetTraceVariables()
+            print debug_tick, debug_vars
+            if debug_vars is not None and \
+               len(debug_vars) == len(self.TracedIECPath):
+                for IECPath,value in zip(self.TracedIECPath, debug_vars):
+                    data_tuple = self.IECdebug_datas.get(IECPath, None)
+                    if data_tuple is not None:
+                        WeakCallableDict, data_log, status = data_tuple
+                        data_log.append((debug_tick, value))
+                        for weakcallable,(args,kwargs) in WeakCallableDict.iteritems():
+                            wx.CallAfter(weakcallable, value, *args, **kwargs)
+            elif debug_vars is not None:
+                wx.CallAfter(self.logger.write_warning, 
+                             "debug data not coherent %d != %d"%(len(debug_vars), len(self.TracedIECPath)))
+            elif debug_tick == -1:
+                #wx.CallAfter(self.logger.write, "Debugger unavailable\n")
+                pass
+            else:
+                wx.CallAfter(self.logger.write, "Debugger disabled\n")
+                break
+
+    def _Debug(self):
         """
         Start PLC (Debug Mode)
         """
-        if self.GetIECProgramsAndVariables() and self._connector.StartPLC():
+        if self.GetIECProgramsAndVariables() and \
+           self._connector.StartPLC(debug=True):
             self.logger.write("Starting PLC (debug mode)\n")
             # TODO : laucnch PLCOpenEditor in Debug Mode
-            self.logger.write_warning("Debug mode for PLCopenEditor not implemented\n")
-            self.logger.write_warning("Starting alternative test GUI\n")
-            # TODO : laucnch PLCOpenEditor in Debug Mode
+            self.DebugThread = Thread(target=self.DebugThreadProc)
+            self.DebugThread.start()
         else:
             self.logger.write_error("Couldn't start PLC debug !\n")
         self.UpdateMethodsFromPLCStatus()
+
+#    def _Do_Test_Debug(self):
+#        # debug code
+#        self.temporary_non_weak_callable_refs = []
+#        for IEC_Path, idx in self._IECPathToIdx.iteritems():
+#            class tmpcls:
+#                def __init__(self):
+#                    self.buf = None
+#                def setbuf(self,buf):
+#                    self.buf = buf
+#                def __call__(self, value, idx, name):
+#                    print "debug call:", value, idx, name, self.buf
+#            a = tmpcls()
+#            res = self.SubscribeDebugIECVariable(IEC_Path, a, idx, IEC_Path)
+#            a.setbuf(res)
+#            self.temporary_non_weak_callable_refs.append(a)
        
     def _Stop(self):
         """
@@ -1485,6 +1532,10 @@
          "shown" : False,
          "tooltip" : "Start PLC (debug mode)",
          "method" : "_Debug"},
+#        {"bitmap" : opjimg("Debug"),
+#         "name" : "Do_Test_Debug",
+#         "tooltip" : "Test debug mode)",
+#         "method" : "_Do_Test_Debug"},
         {"bitmap" : opjimg("Stop"),
          "name" : "Stop",
          "shown" : False,