beremiz

Parents 1fdc32be71b8
Children 4ae9c4447947
Removed DebugThread. Take advantage of the fact that buffering is done in runtime. No need to poll for traces more than ten per second, then use simple wxTimer for that. Also removed Debug Lock since now everything happens in wx' mainloop.
--- a/ProjectController.py Thu Apr 19 12:22:40 2018 +0200
+++ b/ProjectController.py Thu Apr 19 13:02:13 2018 +0200
@@ -242,7 +242,6 @@
# Setup debug information
self.IECdebug_datas = {}
- self.IECdebug_lock = Lock()
self.DebugTimer = None
self.ResetIECProgramsAndVariables()
@@ -258,7 +257,6 @@
# After __init__ root confnode is not valid
self.ProjectPath = None
self._setBuildPath(None)
- self.DebugThread = None
self.debug_break = False
self.previous_plcstate = None
# copy ConfNodeMethods so that it can be later customized
@@ -1420,9 +1418,32 @@
self.UpdateMethodsFromPLCStatus()
def SnapshotAndResetDebugValuesBuffers(self):
+ plc_status, Traces = self._connector.GetTraceVariables()
+ # print [dict.keys() for IECPath, (dict, log, status, fvalue) in self.IECdebug_datas.items()]
+ if plc_status == "Started":
+ if len(Traces) > 0:
+ for debug_tick, debug_buff in Traces:
+ debug_vars = UnpackDebugBuffer(debug_buff, self.TracedIECTypes)
+ if debug_vars is not None and len(debug_vars) == len(self.TracedIECPath):
+ for IECPath, values_buffer, value in izip(
+ self.TracedIECPath,
+ self.DebugValuesBuffers,
+ debug_vars):
+ IECdebug_data = self.IECdebug_datas.get(IECPath, None)
+ if IECdebug_data is not None and value is not None:
+ forced = IECdebug_data[2:4] == ["Forced", value]
+ if not IECdebug_data[4] and len(values_buffer) > 0:
+ values_buffer[-1] = (value, forced)
+ else:
+ values_buffer.append((value, forced))
+ self.DebugTicks.append(debug_tick)
+
+
buffers, self.DebugValuesBuffers = (self.DebugValuesBuffers,
[list() for dummy in xrange(len(self.TracedIECPath))])
+
ticks, self.DebugTicks = self.DebugTicks, []
+
return ticks, buffers
def RegisterDebugVarToConnector(self):
@@ -1431,7 +1452,6 @@
self.TracedIECPath = []
self.TracedIECTypes = []
if self._connector is not None:
- self.IECdebug_lock.acquire()
IECPathsToPop = []
for IECPath, data_tuple in self.IECdebug_datas.iteritems():
WeakCallableDict, _data_log, _status, fvalue, _buffer_list = data_tuple
@@ -1462,7 +1482,6 @@
self.TracedIECPath = []
self._connector.SetTraceVariablesList([])
self.SnapshotAndResetDebugValuesBuffers()
- self.IECdebug_lock.release()
def IsPLCStarted(self):
return self.previous_plcstate == "Started"
@@ -1494,7 +1513,6 @@
if IECPath != "__tick__" and IECPath not in self._IECPathToIdx:
return None
- self.IECdebug_lock.acquire()
# If no entry exist, create a new one with a fresh WeakKeyDictionary
IECdebug_data = self.IECdebug_datas.get(IECPath, None)
if IECdebug_data is None:
@@ -1510,14 +1528,11 @@
IECdebug_data[0][callableobj] = buffer_list
- self.IECdebug_lock.release()
-
self.ReArmDebugRegisterTimer()
return IECdebug_data[1]
def UnsubscribeDebugIECVariable(self, IECPath, callableobj):
- self.IECdebug_lock.acquire()
IECdebug_data = self.IECdebug_datas.get(IECPath, None)
if IECdebug_data is not None:
IECdebug_data[0].pop(callableobj, None)
@@ -1528,14 +1543,11 @@
lambda x, y: x | y,
IECdebug_data[0].itervalues(),
False)
- self.IECdebug_lock.release()
self.ReArmDebugRegisterTimer()
def UnsubscribeAllDebugIECVariable(self):
- self.IECdebug_lock.acquire()
self.IECdebug_datas = {}
- self.IECdebug_lock.release()
self.ReArmDebugRegisterTimer()
@@ -1543,14 +1555,12 @@
if IECPath not in self.IECdebug_datas:
return
- self.IECdebug_lock.acquire()
# If no entry exist, create a new one with a fresh WeakKeyDictionary
IECdebug_data = self.IECdebug_datas.get(IECPath, None)
IECdebug_data[2] = "Forced"
IECdebug_data[3] = fvalue
- self.IECdebug_lock.release()
self.ReArmDebugRegisterTimer()
@@ -1558,14 +1568,12 @@
if IECPath not in self.IECdebug_datas:
return
- self.IECdebug_lock.acquire()
# If no entry exist, create a new one with a fresh WeakKeyDictionary
IECdebug_data = self.IECdebug_datas.get(IECPath, None)
IECdebug_data[2] = "Registered"
IECdebug_data[3] = None
- self.IECdebug_lock.release()
self.ReArmDebugRegisterTimer()
@@ -1590,51 +1598,9 @@
return -1, "No runtime connected!"
return self._connector.RemoteExec(script, **kwargs)
- def DebugThreadProc(self):
- """
- This thread waid PLC debug data, and dispatch them to subscribers
- """
- self.debug_break = False
- debug_getvar_retry = 0
- while (not self.debug_break) and (self._connector is not None):
- plc_status, Traces = self._connector.GetTraceVariables()
- debug_getvar_retry += 1
- # print [dict.keys() for IECPath, (dict, log, status, fvalue) in self.IECdebug_datas.items()]
- if plc_status == "Started":
- if len(Traces) > 0:
- self.IECdebug_lock.acquire()
- for debug_tick, debug_buff in Traces:
- debug_vars = UnpackDebugBuffer(debug_buff, self.TracedIECTypes)
- if debug_vars is not None and len(debug_vars) == len(self.TracedIECPath):
- for IECPath, values_buffer, value in izip(
- self.TracedIECPath,
- self.DebugValuesBuffers,
- debug_vars):
- IECdebug_data = self.IECdebug_datas.get(IECPath, None) # FIXME get
- if IECdebug_data is not None and value is not None:
- forced = IECdebug_data[2:4] == ["Forced", value]
- if not IECdebug_data[4] and len(values_buffer) > 0:
- values_buffer[-1] = (value, forced)
- else:
- values_buffer.append((value, forced))
- self.DebugTicks.append(debug_tick)
- debug_getvar_retry = 0
- self.IECdebug_lock.release()
-
- if debug_getvar_retry != 0:
- # Be patient, tollerate PLC to come with fresh samples
- time.sleep(0.1)
- else:
- self.debug_break = True
- self.logger.write(_("Debugger disabled\n"))
- self.DebugThread = None
- if self.DispatchDebugValuesTimer is not None:
- self.DispatchDebugValuesTimer.Stop()
def DispatchDebugValuesProc(self, event):
- self.IECdebug_lock.acquire()
debug_ticks, buffers = self.SnapshotAndResetDebugValuesBuffers()
- self.IECdebug_lock.release()
start_time = time.time()
if len(self.TracedIECPath) == len(buffers):
for IECPath, values in izip(self.TracedIECPath, buffers):
@@ -1645,22 +1611,12 @@
delay = time.time() - start_time
next_refresh = max(REFRESH_PERIOD - delay, 0.2 * delay)
- if self.DispatchDebugValuesTimer is not None and self.DebugThread is not None:
+ if self.DispatchDebugValuesTimer is not None:
self.DispatchDebugValuesTimer.Start(
int(next_refresh * 1000), oneShot=True)
event.Skip()
def KillDebugThread(self):
- tmp_debugthread = self.DebugThread
- self.debug_break = True
- if tmp_debugthread is not None:
- self.logger.writeyield(_("Stopping debugger...\n"))
- tmp_debugthread.join(timeout=5)
- if tmp_debugthread.isAlive() and self.logger:
- self.logger.write_warning(_("Couldn't stop debugger.\n"))
- else:
- self.logger.write(_("Debugger stopped.\n"))
- self.DebugThread = None
if self.DispatchDebugValuesTimer is not None:
self.DispatchDebugValuesTimer.Stop()
@@ -1672,9 +1628,6 @@
if self.DispatchDebugValuesTimer is not None:
self.DispatchDebugValuesTimer.Start(
int(REFRESH_PERIOD * 1000), oneShot=True)
- if self.DebugThread is None:
- self.DebugThread = Thread(target=self.DebugThreadProc)
- self.DebugThread.start()
def _Run(self):
"""
--- a/connectors/PYRO/__init__.py Thu Apr 19 12:22:40 2018 +0200
+++ b/connectors/PYRO/__init__.py Thu Apr 19 13:02:13 2018 +0200
@@ -139,43 +139,23 @@
confnodesroot.logger.write_error(_("Cannot get PLC status - connection failed.\n"))
return None
+ _special_return_funcs = {
+ "StartPLC": False,
+ "GetTraceVariables": ("Broken", None),
+ "GetPLCstatus": ("Broken", None),
+ "RemoteExec": (-1, "RemoteExec script failed!")
+ }
class PyroProxyProxy(object):
"""
A proxy proxy class to handle Beremiz Pyro interface specific behavior.
And to put Pyro exception catcher in between caller and Pyro proxy
"""
- def __init__(self):
- # for safe use in from debug thread, must create a copy
- self.RemotePLCObjectProxyCopy = None
-
- def _PyroStartPLC(self, *args, **kwargs):
- return RemotePLCObjectProxy.StartPLC(*args, **kwargs)
- StartPLC = PyroCatcher(_PyroStartPLC, False)
-
- def _PyroGetTraceVariables(self):
- """
- for use from debug thread, use a copy
- pyro creates a new thread on server end proxy object is copied
- """
- if self.RemotePLCObjectProxyCopy is None:
- self.RemotePLCObjectProxyCopy = copy.copy(RemotePLCObjectProxy)
- return self.RemotePLCObjectProxyCopy.GetTraceVariables()
- GetTraceVariables = PyroCatcher(_PyroGetTraceVariables, ("Broken", None))
-
- def _PyroGetPLCstatus(self):
- return RemotePLCObjectProxy.GetPLCstatus()
- GetPLCstatus = PyroCatcher(_PyroGetPLCstatus, ("Broken", None))
-
- def _PyroRemoteExec(self, script, **kwargs):
- return RemotePLCObjectProxy.RemoteExec(script, **kwargs)
- RemoteExec = PyroCatcher(_PyroRemoteExec, (-1, "RemoteExec script failed!"))
-
def __getattr__(self, attrName):
member = self.__dict__.get(attrName, None)
if member is None:
def my_local_func(*args, **kwargs):
return RemotePLCObjectProxy.__getattr__(attrName)(*args, **kwargs)
- member = PyroCatcher(my_local_func, None)
+ member = PyroCatcher(my_local_func, _special_return_funcs.get(attrName, None))
self.__dict__[attrName] = member
return member