plugger.py
changeset 235 a66e150f2888
parent 228 848da15cf513
child 236 a32817e81f5e
equal deleted inserted replaced
234:aff053bad924 235:a66e150f2888
   598 
   598 
   599 iec2c_path = os.path.join(base_folder, "matiec", "iec2c"+exe_ext)
   599 iec2c_path = os.path.join(base_folder, "matiec", "iec2c"+exe_ext)
   600 ieclib_path = os.path.join(base_folder, "matiec", "lib")
   600 ieclib_path = os.path.join(base_folder, "matiec", "lib")
   601 
   601 
   602 # import for project creation timestamping
   602 # import for project creation timestamping
   603 from threading import Timer, Lock
   603 from threading import Timer, Lock, Thread
   604 from time import localtime
   604 from time import localtime
   605 from datetime import datetime
   605 from datetime import datetime
   606 # import necessary stuff from PLCOpenEditor
   606 # import necessary stuff from PLCOpenEditor
   607 from PLCControler import PLCControler
   607 from PLCControler import PLCControler
   608 from PLCOpenEditor import PLCOpenEditor, ProjectDialog
   608 from PLCOpenEditor import PLCOpenEditor, ProjectDialog
   615 
   615 
   616 import re
   616 import re
   617 import targets
   617 import targets
   618 import connectors
   618 import connectors
   619 from discovery import DiscoveryDialog
   619 from discovery import DiscoveryDialog
       
   620 from weakref import WeakKeyDictionary
   620 
   621 
   621 class PluginsRoot(PlugTemplate, PLCControler):
   622 class PluginsRoot(PlugTemplate, PLCControler):
   622     """
   623     """
   623     This class define Root object of the plugin tree. 
   624     This class define Root object of the plugin tree. 
   624     It is responsible of :
   625     It is responsible of :
   664         
   665         
   665         # Setup debug information
   666         # Setup debug information
   666         self.IECdebug_datas = {}
   667         self.IECdebug_datas = {}
   667         self.IECdebug_lock = Lock()
   668         self.IECdebug_lock = Lock()
   668 
   669 
   669         # Timer to prevent rapid-fire when registering many variables
   670         self.DebugTimer=None
   670         self.DebugTimer=Timer(0.5,self.RegisterDebugVarToConnector)
       
   671         self.ResetIECProgramsAndVariables()
   671         self.ResetIECProgramsAndVariables()
   672 
       
   673         
   672         
   674         #This method are not called here... but in NewProject and OpenProject
   673         #This method are not called here... but in NewProject and OpenProject
   675         #self._AddParamsMembers()
   674         #self._AddParamsMembers()
   676         #self.PluggedChilds = {}
   675         #self.PluggedChilds = {}
   677 
   676 
   970         CSV file generated by IEC2C compiler.
   969         CSV file generated by IEC2C compiler.
   971         """
   970         """
   972         self._ProgramList = None
   971         self._ProgramList = None
   973         self._VariablesList = None
   972         self._VariablesList = None
   974         self._IECPathToIdx = None
   973         self._IECPathToIdx = None
   975         self._IdxToIECPath = None
   974         self.TracedIECPath = []
   976         
   975 
   977     def GetIECProgramsAndVariables(self):
   976     def GetIECProgramsAndVariables(self):
   978         """
   977         """
   979         Parse CSV-like file  VARIABLES.csv resulting from IEC2C compiler.
   978         Parse CSV-like file  VARIABLES.csv resulting from IEC2C compiler.
   980         Each section is marked with a line staring with '//'
   979         Each section is marked with a line staring with '//'
   981         list of all variables used in various POUs
   980         list of all variables used in various POUs
   987                 ProgramsListAttributeName = ["num", "C_path", "type"]
   986                 ProgramsListAttributeName = ["num", "C_path", "type"]
   988                 VariablesListAttributeName = ["num", "vartype", "IEC_path", "C_path", "type"]
   987                 VariablesListAttributeName = ["num", "vartype", "IEC_path", "C_path", "type"]
   989                 self._ProgramList = []
   988                 self._ProgramList = []
   990                 self._VariablesList = []
   989                 self._VariablesList = []
   991                 self._IECPathToIdx = {}
   990                 self._IECPathToIdx = {}
   992                 self._IdxToIECPath = {}
       
   993                 
   991                 
   994                 # Separate sections
   992                 # Separate sections
   995                 ListGroup = []
   993                 ListGroup = []
   996                 for line in open(csvfile,'r').xreadlines():
   994                 for line in open(csvfile,'r').xreadlines():
   997                     strippedline = line.strip()
   995                     strippedline = line.strip()
  1021                     self._VariablesList.append(attrs)
  1019                     self._VariablesList.append(attrs)
  1022                     # Fill in IEC<->C translation dicts
  1020                     # Fill in IEC<->C translation dicts
  1023                     IEC_path=attrs["IEC_path"]
  1021                     IEC_path=attrs["IEC_path"]
  1024                     Idx=int(attrs["num"])
  1022                     Idx=int(attrs["num"])
  1025                     self._IECPathToIdx[IEC_path]=Idx
  1023                     self._IECPathToIdx[IEC_path]=Idx
  1026                     self._IdxToIECPath[Idx]=IEC_path
       
  1027             except Exception,e:
  1024             except Exception,e:
  1028                 self.logger.write_error("Cannot open/parse VARIABLES.csv!\n")
  1025                 self.logger.write_error("Cannot open/parse VARIABLES.csv!\n")
  1029                 self.logger.write_error(traceback.format_exc())
  1026                 self.logger.write_error(traceback.format_exc())
  1030                 self.ResetIECProgramsAndVariables()
  1027                 self.ResetIECProgramsAndVariables()
  1031                 return False
  1028                 return False
  1057                 for v in self._VariablesList if v["type"] in DebugTypes ])}
  1054                 for v in self._VariablesList if v["type"] in DebugTypes ])}
  1058         
  1055         
  1059         return debug_code
  1056         return debug_code
  1060 
  1057 
  1061     def RegisterDebugVarToConnector(self):
  1058     def RegisterDebugVarToConnector(self):
       
  1059         self.DebugTimer=None
  1062         Idxs = []
  1060         Idxs = []
       
  1061         self.TracedIECPath = []
  1063         if self._connector is not None:
  1062         if self._connector is not None:
  1064             self.IECdebug_lock.acquire()
  1063             self.IECdebug_lock.acquire()
  1065             for IECPath,data_tuple in self.IECdebug_datas:
  1064             for IECPath,data_tuple in self.IECdebug_datas.iteritems():
  1066                 WeakCallableDict, data_log, status = data_tuple
  1065                 WeakCallableDict, data_log, status = data_tuple
  1067                 if len(WeakCallableDict) == 0:
  1066                 if len(WeakCallableDict) == 0:
  1068                     # Callable Dict is empty.
  1067                     # Callable Dict is empty.
  1069                     # This variable is not needed anymore!
  1068                     # This variable is not needed anymore!
  1070                     # self.IECdebug_callables.pop(IECPath)
  1069                     # self.IECdebug_callables.pop(IECPath)
  1071                     # TODO
  1070                     # TODO
  1072                     pass
  1071                     print "Unused : " + IECPath
  1073                 else:
  1072                 else:
  1074                     # Convert 
  1073                     # Convert 
  1075                     Idx = self._IECPathToIdx.get(IECPath,None)
  1074                     Idx = self._IECPathToIdx.get(IECPath,None)
  1076                     if Idx is not None:
  1075                     if Idx is not None:
  1077                         Idxs.append(Idx)
  1076                         Idxs.append(Idx)
       
  1077                         self.TracedIECPath.append(IECPath)
  1078                     else:
  1078                     else:
  1079                         self.logger.write_warning("Debug : Unknown variable %s\n"%IECPath)
  1079                         self.logger.write_warning("Debug : Unknown variable %s\n"%IECPath)
       
  1080             self._connector.SetTraceVariablesList(Idxs)
  1080             self.IECdebug_lock.release()
  1081             self.IECdebug_lock.release()
  1081             self._connector.TraceVariables(Idxs)
  1082         
  1082         
  1083     def SubscribeDebugIECVariable(self, IECPath, callableobj, *args, **kwargs):
  1083     def SubscribeDebugIECVariable(self, IECPath, callable, *args, **kwargs):
       
  1084         """
  1084         """
  1085         Dispatching use a dictionnary linking IEC variable paths
  1085         Dispatching use a dictionnary linking IEC variable paths
  1086         to a WeakKeyDictionary linking 
  1086         to a WeakKeyDictionary linking 
  1087         weakly referenced callables to optionnal args
  1087         weakly referenced callables to optionnal args
  1088         """
  1088         """
  1094                     WeakKeyDictionary(), # Callables
  1094                     WeakKeyDictionary(), # Callables
  1095                     [],                  # Data storage [(tick, data),...]
  1095                     [],                  # Data storage [(tick, data),...]
  1096                     "Registered"]        # Variable status
  1096                     "Registered"]        # Variable status
  1097             self.IECdebug_datas[IECPath] = IECdebug_data
  1097             self.IECdebug_datas[IECPath] = IECdebug_data
  1098         
  1098         
  1099         IECdebug_data[0][callable]=(args, kwargs)
  1099         IECdebug_data[0][callableobj]=(args, kwargs)
  1100 
  1100 
  1101         self.IECdebug_lock.release()
  1101         self.IECdebug_lock.release()
       
  1102 
       
  1103         if self.DebugTimer is not None:
       
  1104             self.DebugTimer.cancel()
       
  1105 
       
  1106         # Timer to prevent rapid-fire when registering many variables
       
  1107         # use wx.CallAfter use keep using same thread. TODO : use wx.Timer instead
       
  1108         self.DebugTimer=Timer(0.5,wx.CallAfter,args = [self.RegisterDebugVarToConnector])
  1102         # Rearm anti-rapid-fire timer
  1109         # Rearm anti-rapid-fire timer
  1103         self.DebugTimer.cancel()
       
  1104         self.DebugTimer.start()
  1110         self.DebugTimer.start()
       
  1111 
       
  1112         return IECdebug_data[1]
  1105         
  1113         
  1106     def Generate_plc_common_main(self):
  1114     def Generate_plc_common_main(self):
  1107         """
  1115         """
  1108         Use plugins layout given in LocationCFilesAndCFLAGS to
  1116         Use plugins layout given in LocationCFilesAndCFLAGS to
  1109         generate glue code that dispatch calls to all plugins
  1117         generate glue code that dispatch calls to all plugins
  1327             self.logger.write("Starting PLC\n")
  1335             self.logger.write("Starting PLC\n")
  1328         else:
  1336         else:
  1329             self.logger.write_error("Couldn't start PLC !\n")
  1337             self.logger.write_error("Couldn't start PLC !\n")
  1330         self.UpdateMethodsFromPLCStatus()
  1338         self.UpdateMethodsFromPLCStatus()
  1331 
  1339 
  1332     def _Debug(self): 
  1340     def DebugThreadProc(self):
       
  1341         while self._connector is not None:
       
  1342             debug_tick, debug_vars = self._connector.GetTraceVariables()
       
  1343             print debug_tick, debug_vars
       
  1344             if debug_vars is not None and \
       
  1345                len(debug_vars) == len(self.TracedIECPath):
       
  1346                 for IECPath,value in zip(self.TracedIECPath, debug_vars):
       
  1347                     data_tuple = self.IECdebug_datas.get(IECPath, None)
       
  1348                     if data_tuple is not None:
       
  1349                         WeakCallableDict, data_log, status = data_tuple
       
  1350                         data_log.append((debug_tick, value))
       
  1351                         for weakcallable,(args,kwargs) in WeakCallableDict.iteritems():
       
  1352                             wx.CallAfter(weakcallable, value, *args, **kwargs)
       
  1353             elif debug_vars is not None:
       
  1354                 wx.CallAfter(self.logger.write_warning, 
       
  1355                              "debug data not coherent %d != %d"%(len(debug_vars), len(self.TracedIECPath)))
       
  1356             elif debug_tick == -1:
       
  1357                 #wx.CallAfter(self.logger.write, "Debugger unavailable\n")
       
  1358                 pass
       
  1359             else:
       
  1360                 wx.CallAfter(self.logger.write, "Debugger disabled\n")
       
  1361                 break
       
  1362 
       
  1363     def _Debug(self):
  1333         """
  1364         """
  1334         Start PLC (Debug Mode)
  1365         Start PLC (Debug Mode)
  1335         """
  1366         """
  1336         if self.GetIECProgramsAndVariables() and self._connector.StartPLC():
  1367         if self.GetIECProgramsAndVariables() and \
       
  1368            self._connector.StartPLC(debug=True):
  1337             self.logger.write("Starting PLC (debug mode)\n")
  1369             self.logger.write("Starting PLC (debug mode)\n")
  1338             # TODO : laucnch PLCOpenEditor in Debug Mode
  1370             # TODO : laucnch PLCOpenEditor in Debug Mode
  1339             self.logger.write_warning("Debug mode for PLCopenEditor not implemented\n")
  1371             self.DebugThread = Thread(target=self.DebugThreadProc)
  1340             self.logger.write_warning("Starting alternative test GUI\n")
  1372             self.DebugThread.start()
  1341             # TODO : laucnch PLCOpenEditor in Debug Mode
       
  1342         else:
  1373         else:
  1343             self.logger.write_error("Couldn't start PLC debug !\n")
  1374             self.logger.write_error("Couldn't start PLC debug !\n")
  1344         self.UpdateMethodsFromPLCStatus()
  1375         self.UpdateMethodsFromPLCStatus()
       
  1376 
       
  1377 #    def _Do_Test_Debug(self):
       
  1378 #        # debug code
       
  1379 #        self.temporary_non_weak_callable_refs = []
       
  1380 #        for IEC_Path, idx in self._IECPathToIdx.iteritems():
       
  1381 #            class tmpcls:
       
  1382 #                def __init__(self):
       
  1383 #                    self.buf = None
       
  1384 #                def setbuf(self,buf):
       
  1385 #                    self.buf = buf
       
  1386 #                def __call__(self, value, idx, name):
       
  1387 #                    print "debug call:", value, idx, name, self.buf
       
  1388 #            a = tmpcls()
       
  1389 #            res = self.SubscribeDebugIECVariable(IEC_Path, a, idx, IEC_Path)
       
  1390 #            a.setbuf(res)
       
  1391 #            self.temporary_non_weak_callable_refs.append(a)
  1345        
  1392        
  1346     def _Stop(self):
  1393     def _Stop(self):
  1347         """
  1394         """
  1348         Stop PLC
  1395         Stop PLC
  1349         """
  1396         """
  1483         {"bitmap" : opjimg("Debug"),
  1530         {"bitmap" : opjimg("Debug"),
  1484          "name" : "Debug",
  1531          "name" : "Debug",
  1485          "shown" : False,
  1532          "shown" : False,
  1486          "tooltip" : "Start PLC (debug mode)",
  1533          "tooltip" : "Start PLC (debug mode)",
  1487          "method" : "_Debug"},
  1534          "method" : "_Debug"},
       
  1535 #        {"bitmap" : opjimg("Debug"),
       
  1536 #         "name" : "Do_Test_Debug",
       
  1537 #         "tooltip" : "Test debug mode)",
       
  1538 #         "method" : "_Do_Test_Debug"},
  1488         {"bitmap" : opjimg("Stop"),
  1539         {"bitmap" : opjimg("Stop"),
  1489          "name" : "Stop",
  1540          "name" : "Stop",
  1490          "shown" : False,
  1541          "shown" : False,
  1491          "tooltip" : "Stop Running PLC",
  1542          "tooltip" : "Stop Running PLC",
  1492          "method" : "_Stop"},
  1543          "method" : "_Stop"},