Add a debugger token to SetTraceVariables and GetTraceVariables to prevent crash an inconsistant data in case of multiple connections. Last connection now takes over existing connections's debug, and first connected IDE gets a wrning.
--- a/BeremizIDE.py Tue Jan 29 09:14:47 2019 +0100
+++ b/BeremizIDE.py Thu Jan 31 14:10:06 2019 +0100
@@ -209,10 +209,6 @@
def write_error(self, s):
self.write(s, self.red_yellow)
- def writeyield(self, s):
- self.write(s)
- wx.GetApp().Yield()
-
def flush(self):
# Temporary deactivate read only mode on StyledTextCtrl for clearing
# text. It seems that text modifications, even programmatically, are
--- a/ProjectController.py Tue Jan 29 09:14:47 2019 +0100
+++ b/ProjectController.py Thu Jan 31 14:10:06 2019 +0100
@@ -270,6 +270,8 @@
self.previous_plcstate = None
# copy StatusMethods so that it can be later customized
self.StatusMethods = [dic.copy() for dic in self.StatusMethods]
+ self.DebugToken = None
+ self.debug_status = PlcStatus.Stopped
def __del__(self):
if self.DebugTimer:
@@ -1479,11 +1481,12 @@
self.UpdateMethodsFromPLCStatus()
def SnapshotAndResetDebugValuesBuffers(self):
- if self._connector is not None:
- plc_status, Traces = self._connector.GetTraceVariables()
+ debug_status = PlcStatus.Disconnected
+ if self._connector is not None and self.DebugToken is not None:
+ debug_status, Traces = self._connector.GetTraceVariables(self.DebugToken)
# print [dict.keys() for IECPath, (dict, log, status, fvalue) in
# self.IECdebug_datas.items()]
- if plc_status == PlcStatus.Started:
+ if debug_status == PlcStatus.Started:
if len(Traces) > 0:
for debug_tick, debug_buff in Traces:
debug_vars = UnpackDebugBuffer(
@@ -1509,14 +1512,14 @@
ticks, self.DebugTicks = self.DebugTicks, []
- return ticks, buffers
+ return debug_status, ticks, buffers
def RegisterDebugVarToConnector(self):
self.DebugTimer = None
Idxs = []
self.TracedIECPath = []
self.TracedIECTypes = []
- if self._connector is not None:
+ if self._connector is not None and self.debug_status != PlcStatus.Broken:
IECPathsToPop = []
for IECPath, data_tuple in self.IECdebug_datas.iteritems():
WeakCallableDict, _data_log, _status, fvalue, _buffer_list = data_tuple
@@ -1545,11 +1548,12 @@
IdxsT = zip(*Idxs)
self.TracedIECPath = IdxsT[3]
self.TracedIECTypes = IdxsT[1]
- self._connector.SetTraceVariablesList(zip(*IdxsT[0:3]))
+ self.DebugToken = self._connector.SetTraceVariablesList(zip(*IdxsT[0:3]))
else:
self.TracedIECPath = []
self._connector.SetTraceVariablesList([])
- self.SnapshotAndResetDebugValuesBuffers()
+ self.DebugToken = None
+ self.debug_status, _debug_ticks, _buffers = self.SnapshotAndResetDebugValuesBuffers()
def IsPLCStarted(self):
return self.previous_plcstate == PlcStatus.Started
@@ -1665,7 +1669,7 @@
return self._connector.RemoteExec(script, **kwargs)
def DispatchDebugValuesProc(self, event):
- debug_ticks, buffers = self.SnapshotAndResetDebugValuesBuffers()
+ self.debug_status, debug_ticks, buffers = self.SnapshotAndResetDebugValuesBuffers()
start_time = time.time()
if len(self.TracedIECPath) == len(buffers):
for IECPath, values in zip(self.TracedIECPath, buffers):
@@ -1676,11 +1680,15 @@
self.CallWeakcallables(
"__tick__", "NewDataAvailable", debug_ticks)
- delay = time.time() - start_time
- next_refresh = max(REFRESH_PERIOD - delay, 0.2 * delay)
- if self.DispatchDebugValuesTimer is not None:
- self.DispatchDebugValuesTimer.Start(
- int(next_refresh * 1000), oneShot=True)
+ if self.debug_status == PlcStatus.Broken:
+ self.logger.write_warning(
+ _("Debug: token rejected - other debug took over - reconnect to recover\n"))
+ else:
+ delay = time.time() - start_time
+ next_refresh = max(REFRESH_PERIOD - delay, 0.2 * delay)
+ if self.DispatchDebugValuesTimer is not None:
+ self.DispatchDebugValuesTimer.Start(
+ int(next_refresh * 1000), oneShot=True)
event.Skip()
def KillDebugThread(self):
@@ -1691,6 +1699,9 @@
self.previous_plcstate = None
if self.AppFrame:
self.AppFrame.ResetGraphicViewers()
+
+ self.debug_status = PlcStatus.Started
+
self.RegisterDebugVarToConnector()
if self.DispatchDebugValuesTimer is not None:
self.DispatchDebugValuesTimer.Start(
@@ -1727,7 +1738,6 @@
if connector is not None:
if self.StatusTimer is not None:
# Start the status Timer
- wx.Yield()
self.StatusTimer.Start(milliseconds=500, oneShot=False)
else:
if self.StatusTimer is not None:
--- a/runtime/PLCObject.py Tue Jan 29 09:14:47 2019 +0100
+++ b/runtime/PLCObject.py Thu Jan 31 14:10:06 2019 +0100
@@ -99,6 +99,7 @@
self.TraceThread = None
self.TraceLock = Lock()
self.Traces = []
+ self.DebugToken = 0
self._init_blobs()
@@ -567,11 +568,13 @@
pass
return False
+ @RunInMain
def SetTraceVariablesList(self, idxs):
"""
Call ctype imported function to append
these indexes to registred variables in PLC debugger
"""
+ self.DebugToken += 1
if idxs:
# suspend but dont disable
if self._suspendDebug(False) == 0:
@@ -586,8 +589,10 @@
self._RegisterDebugVariable(idx, force)
self._TracesSwap()
self._resumeDebug()
+ return self.DebugToken
else:
self._suspendDebug(True)
+ return None
def _TracesSwap(self):
self.LastSwapTrace = time()
@@ -601,8 +606,11 @@
return Traces
@RunInMain
- def GetTraceVariables(self):
- return self.PLCStatus, self._TracesSwap()
+ def GetTraceVariables(self, DebugToken):
+ if (DebugToken is not None and
+ DebugToken == self.DebugToken):
+ return self.PLCStatus, self._TracesSwap()
+ return PlcStatus.Broken, []
def TraceThreadProc(self):
"""