Added support for optimizing debug, preventing to filling buffers with only the last value for debug data consumers that only show the current state
--- a/ProjectController.py Mon Oct 14 10:49:04 2013 +0200
+++ b/ProjectController.py Mon Oct 14 12:28:44 2013 +0200
@@ -1202,7 +1202,7 @@
self.IECdebug_lock.acquire()
IECPathsToPop = []
for IECPath,data_tuple in self.IECdebug_datas.iteritems():
- WeakCallableDict, data_log, status, fvalue = data_tuple
+ WeakCallableDict, data_log, status, fvalue, buffer_list = data_tuple
if len(WeakCallableDict) == 0:
# Callable Dict is empty.
# This variable is not needed anymore!
@@ -1268,10 +1268,13 @@
WeakKeyDictionary(), # Callables
[], # Data storage [(tick, data),...]
"Registered", # Variable status
- None] # Forced value
+ None,
+ buffer_list] # Forced value
self.IECdebug_datas[IECPath] = IECdebug_data
-
- IECdebug_data[0][callableobj]=(args, kwargs)
+ else:
+ IECdebug_data[4] |= buffer_list
+
+ IECdebug_data[0][callableobj]=(buffer_list, args, kwargs)
self.IECdebug_lock.release()
@@ -1286,6 +1289,12 @@
IECdebug_data[0].pop(callableobj,None)
if len(IECdebug_data[0]) == 0:
self.IECdebug_datas.pop(IECPath)
+ else:
+ IECdebug_data[4] = reduce(
+ lambda x, y: x|y,
+ [buffer_list for buffer_list,args,kwargs
+ in IECdebug_data[0].itervalues()],
+ False)
self.IECdebug_lock.release()
self.ReArmDebugRegisterTimer()
@@ -1330,16 +1339,15 @@
def CallWeakcallables(self, IECPath, function_name, *cargs):
data_tuple = self.IECdebug_datas.get(IECPath, None)
if data_tuple is not None:
- WeakCallableDict, data_log, status, fvalue = data_tuple
+ WeakCallableDict, data_log, status, fvalue, buffer_list = data_tuple
#data_log.append((debug_tick, value))
- for weakcallable,(args,kwargs) in WeakCallableDict.iteritems():
+ for weakcallable,(buffer_list,args,kwargs) in WeakCallableDict.iteritems():
function = getattr(weakcallable, function_name, None)
if function is not None:
- if status == "Forced" and cargs[1] == fvalue:
- function(*(cargs + (True,) + args), **kwargs)
+ if buffer_list:
+ function(*(cargs + args), **kwargs)
else:
- function(*(cargs + args), **kwargs)
- # This will block thread if more than one call is waiting
+ function(*(tuple([lst[-1] for lst in cargs]) + args), **kwargs)
def GetTicktime(self):
return self._Ticktime
@@ -1365,13 +1373,19 @@
#print [dict.keys() for IECPath, (dict, log, status, fvalue) in self.IECdebug_datas.items()]
if plc_status == "Started":
self.IECdebug_lock.acquire()
- if len(debug_vars) == len(self.DebugValuesBuffers):
+ if (len(debug_vars) == len(self.DebugValuesBuffers) and
+ len(debug_vars) == len(self.TracedIECPath)):
if debug_getvar_retry > DEBUG_RETRIES_WARN:
self.logger.write(_("... debugger recovered\n"))
debug_getvar_retry = 0
- for values_buffer, value in zip(self.DebugValuesBuffers, debug_vars):
- if value is not None:
- values_buffer.append(value)
+ for IECPath, values_buffer, value in zip(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)
self.IECdebug_lock.release()
if debug_getvar_retry == DEBUG_RETRIES_WARN:
--- a/controls/DebugVariablePanel/DebugVariableItem.py Mon Oct 14 10:49:04 2013 +0200
+++ b/controls/DebugVariablePanel/DebugVariableItem.py Mon Oct 14 12:28:44 2013 +0200
@@ -232,14 +232,14 @@
return (self.Parent.IsNumType(self.VariableType) or
self.VariableType in ["STRING", "WSTRING"])
- def NewValues(self, ticks, values, forced=False):
+ def NewValues(self, ticks, values):
"""
Function called by debug thread when a new debug value is available
@param tick: PLC tick when value was captured
@param value: Value captured
@param forced: Forced flag, True if value is forced (default: False)
"""
- DebugDataConsumer.NewValues(self, ticks, values, forced, raw=None)
+ DebugDataConsumer.NewValues(self, ticks[-1], values[-1], raw=None)
if self.Data is not None:
@@ -247,13 +247,12 @@
last_raw_data = (self.RawData[-1]
if len(self.RawData) > 0 else None)
last_raw_data_idx = len(self.RawData) - 1
-
- # Translate forced flag to float for storing in Data table
- forced_value = float(forced)
data_values = []
- for tick, value in zip(ticks, values):
-
+ for tick, (value, forced) in zip(ticks, values):
+ # Translate forced flag to float for storing in Data table
+ forced_value = float(forced)
+
# String data value is CRC
num_value = (binascii.crc32(value) & STRING_CRC_MASK
if self.VariableType in ["STRING", "WSTRING"]
--- a/controls/DebugVariablePanel/DebugVariablePanel.py Mon Oct 14 10:49:04 2013 +0200
+++ b/controls/DebugVariablePanel/DebugVariablePanel.py Mon Oct 14 12:28:44 2013 +0200
@@ -754,7 +754,7 @@
if idx is None:
idx = len(self.GraphicPanels)
item = DebugVariableItem(self, iec_path, True)
- result = self.AddDataConsumer(iec_path.upper(), item)
+ result = self.AddDataConsumer(iec_path.upper(), item, True)
if result is not None or force:
self.Freeze()
@@ -832,7 +832,7 @@
if source_item is None:
item = DebugVariableItem(self, source, True)
if item.IsNumVariable():
- result = self.AddDataConsumer(source.upper(), item)
+ result = self.AddDataConsumer(source.upper(), item, True)
if result is not None or force:
source_item = item
if source_item is not None and source_item.IsNumVariable():
--- a/controls/DebugVariablePanel/DebugVariableViewer.py Mon Oct 14 10:49:04 2013 +0200
+++ b/controls/DebugVariablePanel/DebugVariableViewer.py Mon Oct 14 12:28:44 2013 +0200
@@ -149,7 +149,7 @@
self.RemoveItem(item)
else:
# If it exist, resubscribe and refresh data type
- self.ParentWindow.AddDataConsumer(iec_path.upper(), item)
+ self.ParentWindow.AddDataConsumer(iec_path.upper(), item, True)
item.RefreshVariableType()
def ResetItemsData(self):
--- a/editors/DebugViewer.py Mon Oct 14 10:49:04 2013 +0200
+++ b/editors/DebugViewer.py Mon Oct 14 12:28:44 2013 +0200
@@ -106,7 +106,7 @@
# Subscribe tick to new data producer
if producer is not None:
- producer.SubscribeDebugIECVariable("__tick__", self)
+ producer.SubscribeDebugIECVariable("__tick__", self, True)
# Unsubscribe tick from old data producer
if getattr(self, "DataProducer", None) is not None:
@@ -134,7 +134,7 @@
# Save inhibit flag
self.Inhibited = inhibit
- def AddDataConsumer(self, iec_path, consumer):
+ def AddDataConsumer(self, iec_path, consumer, buffer_list=False):
"""
Subscribe data consumer to DataProducer
@param iec_path: Path in PLC of variable needed by data consumer
@@ -148,7 +148,7 @@
# Subscribe data consumer to DataProducer
result = self.DataProducer.SubscribeDebugIECVariable(
- iec_path, consumer)
+ iec_path, consumer, buffer_list)
if result is not None and consumer != self:
# Store data consumer if successfully subscribed and inform
@@ -178,7 +178,7 @@
"""
# Subscribe tick if needed
if self.SubscribeTick and self.Debug and self.DataProducer is not None:
- self.DataProducer.SubscribeDebugIECVariable("__tick__", self)
+ self.DataProducer.SubscribeDebugIECVariable("__tick__", self, True)
def UnsubscribeAllDataConsumers(self, tick=True):
"""
--- a/graphics/DebugDataConsumer.py Mon Oct 14 10:49:04 2013 +0200
+++ b/graphics/DebugDataConsumer.py Mon Oct 14 12:28:44 2013 +0200
@@ -197,7 +197,7 @@
"""
self.DataType = data_type
- def NewValues(self, ticks, values, forced=False, raw="BOOL"):
+ def NewValues(self, tick, values, raw="BOOL"):
"""
Function called by debug thread when a new debug value is available
@param tick: PLC tick when value was captured
@@ -205,7 +205,7 @@
@param forced: Forced flag, True if value is forced (default: False)
@param raw: Data type of values not translated (default: 'BOOL')
"""
- tick, value = ticks[-1], values[-1]
+ value, forced = values
# Translate value to IEC literal
if self.DataType != raw: