ProjectController.py
changeset 1363 e87e0166d0a7
parent 1330 96b242e4c59d
child 1364 e9e17d3b2849
equal deleted inserted replaced
1362:077bcba2d485 1363:e87e0166d0a7
    20 from util.ProcessLogger import ProcessLogger
    20 from util.ProcessLogger import ProcessLogger
    21 from util.BitmapLibrary import GetBitmap
    21 from util.BitmapLibrary import GetBitmap
    22 from editors.FileManagementPanel import FileManagementPanel
    22 from editors.FileManagementPanel import FileManagementPanel
    23 from editors.ProjectNodeEditor import ProjectNodeEditor
    23 from editors.ProjectNodeEditor import ProjectNodeEditor
    24 from editors.IECCodeViewer import IECCodeViewer
    24 from editors.IECCodeViewer import IECCodeViewer
    25 from editors.DebugViewer import DebugViewer
    25 from editors.DebugViewer import DebugViewer, REFRESH_PERIOD
    26 from dialogs import DiscoveryDialog
    26 from dialogs import DiscoveryDialog
    27 from PLCControler import PLCControler
    27 from PLCControler import PLCControler
    28 from plcopen.structures import IEC_KEYWORDS
    28 from plcopen.structures import IEC_KEYWORDS
    29 from targets.typemapping import DebugTypesSize, LogLevelsCount, LogLevels
    29 from targets.typemapping import DebugTypesSize, LogLevelsCount, LogLevels
    30 from ConfigTreeNode import ConfigTreeNode, XSDSchemaErrorMessage
    30 from ConfigTreeNode import ConfigTreeNode, XSDSchemaErrorMessage
   108         PLCControler.__init__(self)
   108         PLCControler.__init__(self)
   109 
   109 
   110         self.MandatoryParams = None
   110         self.MandatoryParams = None
   111         self._builder = None
   111         self._builder = None
   112         self._connector = None
   112         self._connector = None
       
   113         self.DispatchDebugValuesTimer = None
       
   114         self.DebugValuesBuffers = []
       
   115         self.DebugTicks = []
   113         self.SetAppFrame(frame, logger)
   116         self.SetAppFrame(frame, logger)
   114         
   117         
   115         self.iec2c_path = os.path.join(base_folder, "matiec", "iec2c"+(".exe" if wx.Platform == '__WXMSW__' else ""))
   118         self.iec2c_path = os.path.join(base_folder, "matiec", "iec2c"+(".exe" if wx.Platform == '__WXMSW__' else ""))
   116         self.ieclib_path = os.path.join(base_folder, "matiec", "lib")
   119         self.ieclib_path = os.path.join(base_folder, "matiec", "lib")
   117         
   120         
   155     
   158     
   156     def SetAppFrame(self, frame, logger):
   159     def SetAppFrame(self, frame, logger):
   157         self.AppFrame = frame
   160         self.AppFrame = frame
   158         self.logger = logger
   161         self.logger = logger
   159         self.StatusTimer = None
   162         self.StatusTimer = None
       
   163         if self.DispatchDebugValuesTimer is not None:
       
   164             self.DispatchDebugValuesTimer.Stop()
       
   165         self.DispatchDebugValuesTimer = None
   160         
   166         
   161         if frame is not None:
   167         if frame is not None:
   162             frame.LogViewer.SetLogSource(self._connector)
   168             frame.LogViewer.SetLogSource(self._connector)
   163             
   169             
   164             # Timer to pull PLC status
   170             # Timer to pull PLC status
   165             ID_STATUSTIMER = wx.NewId()
   171             self.StatusTimer = wx.Timer(self.AppFrame, -1)
   166             self.StatusTimer = wx.Timer(self.AppFrame, ID_STATUSTIMER)
   172             self.AppFrame.Bind(wx.EVT_TIMER, 
   167             self.AppFrame.Bind(wx.EVT_TIMER, self.PullPLCStatusProc, self.StatusTimer)
   173                 self.PullPLCStatusProc, self.StatusTimer)
   168         
   174             
       
   175             # Timer to dispatch debug values to consumers
       
   176             self.DispatchDebugValuesTimer = wx.Timer(self.AppFrame, -1)
       
   177             self.AppFrame.Bind(wx.EVT_TIMER, 
       
   178                 self.DispatchDebugValuesProc, self.DispatchDebugValuesTimer)
       
   179             
   169             self.RefreshConfNodesBlockLists()
   180             self.RefreshConfNodesBlockLists()
   170 
   181 
   171     def ResetAppFrame(self, logger):
   182     def ResetAppFrame(self, logger):
   172         if self.AppFrame is not None:
   183         if self.AppFrame is not None:
   173             self.AppFrame.Unbind(wx.EVT_TIMER, self.StatusTimer)
   184             self.AppFrame.Unbind(wx.EVT_TIMER, self.StatusTimer)
  1175                     self.AppFrame.ConnectionStatusBar.SetStatusText(_(status), 2)
  1186                     self.AppFrame.ConnectionStatusBar.SetStatusText(_(status), 2)
  1176                 
  1187                 
  1177     def PullPLCStatusProc(self, event):
  1188     def PullPLCStatusProc(self, event):
  1178         self.UpdateMethodsFromPLCStatus()
  1189         self.UpdateMethodsFromPLCStatus()
  1179         
  1190         
       
  1191     def SnapshotAndResetDebugValuesBuffers(self):
       
  1192         buffers, self.DebugValuesBuffers = (self.DebugValuesBuffers, 
       
  1193             [list() for iec_path in self.TracedIECPath])
       
  1194         ticks, self.DebugTicks = self.DebugTicks, []
       
  1195         return ticks, buffers
       
  1196     
  1180     def RegisterDebugVarToConnector(self):
  1197     def RegisterDebugVarToConnector(self):
  1181         self.DebugTimer=None
  1198         self.DebugTimer=None
  1182         Idxs = []
  1199         Idxs = []
  1183         self.TracedIECPath = []
  1200         self.TracedIECPath = []
  1184         if self._connector is not None:
  1201         if self._connector is not None:
  1208                 self.TracedIECPath = zip(*Idxs)[3]
  1225                 self.TracedIECPath = zip(*Idxs)[3]
  1209                 self._connector.SetTraceVariablesList(zip(*zip(*Idxs)[0:3]))
  1226                 self._connector.SetTraceVariablesList(zip(*zip(*Idxs)[0:3]))
  1210             else:
  1227             else:
  1211                 self.TracedIECPath = []
  1228                 self.TracedIECPath = []
  1212                 self._connector.SetTraceVariablesList([])
  1229                 self._connector.SetTraceVariablesList([])
       
  1230             self.SnapshotAndResetDebugValuesBuffers()
  1213             self.IECdebug_lock.release()
  1231             self.IECdebug_lock.release()
  1214     
  1232     
  1215     def IsPLCStarted(self):
  1233     def IsPLCStarted(self):
  1216         return self.previous_plcstate == "Started"
  1234         return self.previous_plcstate == "Started"
  1217      
  1235     
  1218     def ReArmDebugRegisterTimer(self):
  1236     def ReArmDebugRegisterTimer(self):
  1219         if self.DebugTimer is not None:
  1237         if self.DebugTimer is not None:
  1220             self.DebugTimer.cancel()
  1238             self.DebugTimer.cancel()
  1221         
  1239         
  1222         # Prevent to call RegisterDebugVarToConnector when PLC is not started
  1240         # Prevent to call RegisterDebugVarToConnector when PLC is not started
  1231 
  1249 
  1232     def GetDebugIECVariableType(self, IECPath):
  1250     def GetDebugIECVariableType(self, IECPath):
  1233         Idx, IEC_Type = self._IECPathToIdx.get(IECPath,(None,None))
  1251         Idx, IEC_Type = self._IECPathToIdx.get(IECPath,(None,None))
  1234         return IEC_Type
  1252         return IEC_Type
  1235         
  1253         
  1236     def SubscribeDebugIECVariable(self, IECPath, callableobj, *args, **kwargs):
  1254     def SubscribeDebugIECVariable(self, IECPath, callableobj, buffer_list=False, *args, **kwargs):
  1237         """
  1255         """
  1238         Dispatching use a dictionnary linking IEC variable paths
  1256         Dispatching use a dictionnary linking IEC variable paths
  1239         to a WeakKeyDictionary linking 
  1257         to a WeakKeyDictionary linking 
  1240         weakly referenced callables to optionnal args
  1258         weakly referenced callables to optionnal args
  1241         """
  1259         """
  1248         if IECdebug_data is None:
  1266         if IECdebug_data is None:
  1249             IECdebug_data  = [
  1267             IECdebug_data  = [
  1250                     WeakKeyDictionary(), # Callables
  1268                     WeakKeyDictionary(), # Callables
  1251                     [],                  # Data storage [(tick, data),...]
  1269                     [],                  # Data storage [(tick, data),...]
  1252                     "Registered",        # Variable status
  1270                     "Registered",        # Variable status
  1253                     None]                # Forced value
  1271                     None,
       
  1272                     buffer_list]                # Forced value
  1254             self.IECdebug_datas[IECPath] = IECdebug_data
  1273             self.IECdebug_datas[IECPath] = IECdebug_data
  1255         
  1274         
  1256         IECdebug_data[0][callableobj]=(args, kwargs)
  1275         IECdebug_data[0][callableobj]=(args, kwargs)
  1257 
  1276 
  1258         self.IECdebug_lock.release()
  1277         self.IECdebug_lock.release()
  1345                 plc_status = None
  1364                 plc_status = None
  1346             debug_getvar_retry += 1
  1365             debug_getvar_retry += 1
  1347             #print [dict.keys() for IECPath, (dict, log, status, fvalue) in self.IECdebug_datas.items()]
  1366             #print [dict.keys() for IECPath, (dict, log, status, fvalue) in self.IECdebug_datas.items()]
  1348             if plc_status == "Started":
  1367             if plc_status == "Started":
  1349                 self.IECdebug_lock.acquire()
  1368                 self.IECdebug_lock.acquire()
  1350                 if len(debug_vars) == len(self.TracedIECPath):
  1369                 if len(debug_vars) == len(self.DebugValuesBuffers):
  1351                     if debug_getvar_retry > DEBUG_RETRIES_WARN:
  1370                     if debug_getvar_retry > DEBUG_RETRIES_WARN:
  1352                         self.logger.write(_("... debugger recovered\n"))
  1371                         self.logger.write(_("... debugger recovered\n"))
  1353                     debug_getvar_retry = 0
  1372                     debug_getvar_retry = 0
  1354                     for IECPath,value in zip(self.TracedIECPath, debug_vars):
  1373                     for values_buffer, value in zip(self.DebugValuesBuffers, debug_vars):
  1355                         if value is not None:
  1374                         if value is not None:
  1356                             self.CallWeakcallables(IECPath, "NewValue", debug_tick, value)
  1375                             values_buffer.append(value)
  1357                     self.CallWeakcallables("__tick__", "NewDataAvailable", debug_tick)
  1376                     self.DebugTicks.append(debug_tick)
  1358                 self.IECdebug_lock.release()
  1377                 self.IECdebug_lock.release()
  1359                 if debug_getvar_retry == DEBUG_RETRIES_WARN:
  1378                 if debug_getvar_retry == DEBUG_RETRIES_WARN:
  1360                     self.logger.write(_("Waiting debugger to recover...\n"))
  1379                     self.logger.write(_("Waiting debugger to recover...\n"))
  1361                 if debug_getvar_retry == DEBUG_RETRIES_REREGISTER:
  1380                 if debug_getvar_retry == DEBUG_RETRIES_REREGISTER:
  1362                     # re-register debug registry to PLC
  1381                     # re-register debug registry to PLC
  1366                     time.sleep(0.1)
  1385                     time.sleep(0.1)
  1367             else:
  1386             else:
  1368                 self.debug_break = True
  1387                 self.debug_break = True
  1369         self.logger.write(_("Debugger disabled\n"))
  1388         self.logger.write(_("Debugger disabled\n"))
  1370         self.DebugThread = None
  1389         self.DebugThread = None
       
  1390         if self.DispatchDebugValuesTimer is not None:
       
  1391             self.DispatchDebugValuesTimer.Stop()
       
  1392 
       
  1393     def DispatchDebugValuesProc(self, event):
       
  1394         self.IECdebug_lock.acquire()
       
  1395         debug_ticks, buffers = self.SnapshotAndResetDebugValuesBuffers()
       
  1396         self.IECdebug_lock.release()
       
  1397         if len(self.TracedIECPath) == len(buffers):
       
  1398             for IECPath, values in zip(self.TracedIECPath, buffers):
       
  1399                 if len(values) > 0:
       
  1400                     self.CallWeakcallables(IECPath, "NewValues", debug_ticks, values)
       
  1401             if len(debug_ticks) > 0:
       
  1402                 self.CallWeakcallables("__tick__", "NewDataAvailable", debug_ticks)
       
  1403         event.Skip()
  1371 
  1404 
  1372     def KillDebugThread(self):
  1405     def KillDebugThread(self):
  1373         tmp_debugthread = self.DebugThread
  1406         tmp_debugthread = self.DebugThread
  1374         self.debug_break = True
  1407         self.debug_break = True
  1375         if tmp_debugthread is not None:
  1408         if tmp_debugthread is not None:
  1378             if tmp_debugthread.isAlive() and self.logger:
  1411             if tmp_debugthread.isAlive() and self.logger:
  1379                 self.logger.write_warning(_("Couldn't stop debugger.\n"))
  1412                 self.logger.write_warning(_("Couldn't stop debugger.\n"))
  1380             else:
  1413             else:
  1381                 self.logger.write(_("Debugger stopped.\n"))
  1414                 self.logger.write(_("Debugger stopped.\n"))
  1382         self.DebugThread = None
  1415         self.DebugThread = None
       
  1416         if self.DispatchDebugValuesTimer is not None:
       
  1417             self.DispatchDebugValuesTimer.Stop()
  1383 
  1418 
  1384     def _connect_debug(self): 
  1419     def _connect_debug(self): 
  1385         self.previous_plcstate = None
  1420         self.previous_plcstate = None
  1386         if self.AppFrame:
  1421         if self.AppFrame:
  1387             self.AppFrame.ResetGraphicViewers()
  1422             self.AppFrame.ResetGraphicViewers()
  1388         self.RegisterDebugVarToConnector()
  1423         self.RegisterDebugVarToConnector()
       
  1424         if self.DispatchDebugValuesTimer is not None:
       
  1425             self.DispatchDebugValuesTimer.Start(int(REFRESH_PERIOD * 1000))
  1389         if self.DebugThread is None:
  1426         if self.DebugThread is None:
  1390             self.DebugThread = Thread(target=self.DebugThreadProc)
  1427             self.DebugThread = Thread(target=self.DebugThreadProc)
  1391             self.DebugThread.start()
  1428             self.DebugThread.start()
  1392     
  1429     
  1393     def _Run(self):
  1430     def _Run(self):