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): |