Moved and rewrote DebugViewer and DebusDataConsumer classes
--- a/IDEFrame.py Mon May 27 09:24:39 2013 +0200
+++ b/IDEFrame.py Mon May 27 13:09:54 2013 +0200
@@ -2022,9 +2022,9 @@
elif isinstance(editor, GraphicViewer):
- editor.RegisterVariables()
+ editor.SubscribeAllDataConsumers() elif editor.IsDebugging():
- editor.RegisterVariables()
+ editor.SubscribeAllDataConsumers() self.DebugVariablePanel.UnregisterObsoleteData()
def AddDebugVariable(self, iec_path, force=False):
--- a/ProjectController.py Mon May 27 09:24:39 2013 +0200
+++ b/ProjectController.py Mon May 27 13:09:54 2013 +0200
@@ -21,7 +21,7 @@
from editors.FileManagementPanel import FileManagementPanel
from editors.ProjectNodeEditor import ProjectNodeEditor
from editors.IECCodeViewer import IECCodeViewer
-from graphics import DebugViewer
+from editors.DebugViewer import DebugViewer from dialogs import DiscoveryDialog
from PLCControler import PLCControler
from plcopen.structures import IEC_KEYWORDS
--- a/controls/DebugVariablePanel.py Mon May 27 09:24:39 2013 +0200
+++ b/controls/DebugVariablePanel.py Mon May 27 13:09:54 2013 +0200
@@ -45,7 +45,8 @@
-from graphics import DebugDataConsumer, DebugViewer, REFRESH_PERIOD
+from graphics.DebugDataConsumer import DebugDataConsumer +from editors.DebugViewer import DebugViewer, REFRESH_PERIOD from controls import CustomGrid, CustomTable
from dialogs.ForceVariableDialog import ForceVariableDialog
from util.BitmapLibrary import GetBitmap
@@ -1837,7 +1838,7 @@
def UnregisterObsoleteData(self):
- self.RegisterVariables()
+ self.SubscribeAllDataConsumers() if self.DataProducer is not None:
self.Ticktime = self.DataProducer.GetTicktime()
@@ -1872,7 +1873,7 @@
- self.DeleteDataConsumers()
+ self.UnsubscribeAllDataConsumers() for panel in self.GraphicPanels:
--- a/controls/LogViewer.py Mon May 27 09:24:39 2013 +0200
+++ b/controls/LogViewer.py Mon May 27 13:09:54 2013 +0200
@@ -29,7 +29,7 @@
from controls.CustomToolTip import CustomToolTip, TOOLTIP_WAIT_PERIOD
-from graphics import DebugViewer, REFRESH_PERIOD
+from editors.DebugViewer import DebugViewer, REFRESH_PERIOD from targets.typemapping import LogLevelsCount, LogLevels
from util.BitmapLibrary import GetBitmap
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/editors/DebugViewer.py Mon May 27 13:09:54 2013 +0200
@@ -0,0 +1,348 @@
+#This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor +#based on the plcopen standard. +#Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD +#See COPYING file for copyrights details. +#This library is free software; you can redistribute it and/or +#modify it under the terms of the GNU General Public +#License as published by the Free Software Foundation; either +#version 2.1 of the License, or (at your option) any later version. +#This library is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +#General Public License for more details. +#You should have received a copy of the GNU General Public +#License along with this library; if not, write to the Free Software +#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +from threading import Lock, Timer +from time import time as gettime +REFRESH_PERIOD = 0.1 # Minimum time between 2 refresh +DEBUG_REFRESH_LOCK = Lock() # Common refresh lock for all debug viewers +#------------------------------------------------------------------------------- +#------------------------------------------------------------------------------- +Class that implements common behavior of every viewers able to display debug + def __init__(self, producer, debug, subscribe_tick=True): + @param producer: Object receiving debug value and dispatching them to + @param debug: Flag indicating that Viewer is debugging + @param subscribe_tick: Flag indicating that viewer need tick value to + self.SubscribeTick = subscribe_tick + # Flag indicating that consumer value update inhibited + # (DebugViewer is refreshing) + # List of data consumers subscribed to DataProducer + self.DataConsumers = {} + # Time stamp indicating when last refresh have been initiated + self.LastRefreshTime = gettime() + # Flag indicating that DebugViewer has acquire common debug lock + self.HasAcquiredLock = False + # Lock for access to the two preceding variable + self.AccessLock = Lock() + # Timer to refresh Debug Viewer one last time in the case that a new + # value have been received during refresh was inhibited and no one + # after refresh was activated + self.LastRefreshTimer = None + # Lock for access to the timer + self.TimerAccessLock = Lock() + # Set DataProducer and subscribe tick if needed + self.SetDataProducer(producer) + # Unsubscribe all data consumers + self.UnsubscribeAllDataConsumers() + # Delete reference to DataProducer + self.DataProducer = None + # Stop last refresh timer + if self.LastRefreshTimer is not None: + self.LastRefreshTimer.cancel() + # Release Common debug lock if DebugViewer has acquired it + if self.HasAcquiredLock: + DEBUG_REFRESH_LOCK.release() + def SetDataProducer(self, producer): + @param producer: Data Producer + # In the case that tick need to be subscribed and DebugViewer is + if self.SubscribeTick and self.Debug: + # Subscribe tick to new data producer + if producer is not None: + producer.SubscribeDebugIECVariable("__tick__", self) + # Unsubscribe tick from old data producer + if getattr(self, "DataProducer", None) is not None: + self.DataProducer.UnsubscribeDebugIECVariable("__tick__", self) + # Save new data producer + self.DataProducer = producer + Get flag indicating if Debug Viewer is debugging + @return: Debugging flag + def Inhibit(self, inhibit): + Set consumer value update inhibit flag + @param inhibit: Inhibit flag + # Inhibit every data consumers in list + for consumer, iec_path in self.DataConsumers.iteritems(): + consumer.Inhibit(inhibit) + self.Inhibited = inhibit + def AddDataConsumer(self, iec_path, consumer): + Subscribe data consumer to DataProducer + @param iec_path: Path in PLC of variable needed by data consumer + @param consumer: Data consumer to subscribe + @return: List of value already received [(tick, data),...] (None if + # Return immediately if no DataProducer defined + if self.DataProducer is None: + # Subscribe data consumer to DataProducer + result = self.DataProducer.SubscribeDebugIECVariable( + if result is not None and consumer != self: + # Store data consumer if successfully subscribed and inform + # consumer of variable data type + self.DataConsumers[consumer] = iec_path + consumer.SetDataType(self.GetDataType(iec_path)) + def RemoveDataConsumer(self, consumer): + Unsubscribe data consumer from DataProducer + @param consumer: Data consumer to unsubscribe + # Remove consumer from data consumer list + iec_path = self.DataConsumers.pop(consumer, None) + # Unsubscribe consumer from DataProducer + if iec_path is not None: + self.DataProducer.UnsubscribeDebugIECVariable( + def SubscribeAllDataConsumers(self): + Called to Subscribe all data consumers contained in DebugViewer. + May be overridden by inherited classes. + # Subscribe tick if needed + if self.SubscribeTick and self.Debug and self.DataProducer is not None: + self.DataProducer.SubscribeDebugIECVariable("__tick__", self) + def UnsubscribeAllDataConsumers(self): + Called to Unsubscribe all data consumers. + if self.DataProducer is not None: + # Unsubscribe all data consumers in list + for consumer, iec_path in self.DataConsumers.iteritems(): + self.DataProducer.UnsubscribeDebugIECVariable( + # Unscribe tick if needed + if self.SubscribeTick and self.Debug: + self.DataProducer.UnsubscribeDebugIECVariable("__tick__", self) + self.DataConsumers = {} + def GetDataType(self, iec_path): + Return variable data type. + @param iec_path: Path in PLC of variable + @return: variable data type (None if not found) + if self.DataProducer is not None: + # Search for variable informations in project compilation files + data_type = self.DataProducer.GetDebugIECVariableType( + if data_type is not None: + # Search for variable informations in project data + infos = self.DataProducer.GetInstanceInfos(iec_path) + def IsNumType(self, data_type): + Indicate if data type given is a numeric data type + @param data_type: Data type to test + @return: True if data type given is numeric + if self.DataProducer is not None: + return self.DataProducer.IsNumType(data_type) + def ForceDataValue(self, iec_path, value): + Force PLC variable value + @param iec_path: Path in PLC of variable to force + @param value: Value forced + if self.DataProducer is not None: + self.DataProducer.ForceDebugIECVariable(iec_path, value) + def ReleaseDataValue(self, iec_path): + Release PLC variable value + @param iec_path: Path in PLC of variable to release + if self.DataProducer is not None: + self.DataProducer.ReleaseDebugIECVariable(iec_path) + def NewDataAvailable(self, tick, *args, **kwargs): + Called by DataProducer for each tick captured in + @param tick: PLC tick captured + All other parameters are passed to refresh function + # Stop last refresh timer + self.TimerAccessLock.acquire() + if self.LastRefreshTimer is not None: + self.LastRefreshTimer.cancel() + self.LastRefreshTimer=None + self.TimerAccessLock.release() + # Only try to refresh DebugViewer if it is visible on screen and not + if self.IsShown() and not self.Inhibited: + # Try to get acquire common refresh lock if minimum period between + # two refresh has expired + if gettime() - self.LastRefreshTime > REFRESH_PERIOD and \ + DEBUG_REFRESH_LOCK.acquire(False): + self.StartRefreshing(*args, **kwargs) + # If common lock wasn't acquired for any reason, restart last + self.StartLastRefreshTimer(*args, **kwargs) + # In the case that DebugViewer isn't visible on screen and has already + # acquired common refresh lock, reset DebugViewer + elif not self.IsShown() and self.HasAcquiredLock: + DebugViewer.RefreshNewData(self) + def ShouldRefresh(self, *args, **kwargs): + Callback function called when last refresh timer expired + All parameters are passed to refresh function + # Cancel if DebugViewer is not visible on screen + if self and self.IsShown(): + # Try to acquire common refresh lock + if DEBUG_REFRESH_LOCK.acquire(False): + self.StartRefreshing(*args, **kwargs) + # Restart last refresh timer if common refresh lock acquired failed + self.StartLastRefreshTimer(*args, **kwargs) + def StartRefreshing(self, *args, **kwargs): + Called to initiate a refresh of DebugViewer + All parameters are passed to refresh function + # Update last refresh time stamp and flag for common refresh + self.AccessLock.acquire() + self.HasAcquiredLock = True + self.LastRefreshTime = gettime() + self.AccessLock.release() + # Inhibit data consumer value update + # Initiate DebugViewer refresh + wx.CallAfter(self.RefreshNewData, *args, **kwargs) + def StartLastRefreshTimer(self, *args, **kwargs): + Called to start last refresh timer for the minimum time between 2 + All parameters are passed to refresh function + self.TimerAccessLock.acquire() + self.LastRefreshTimer = Timer( + REFRESH_PERIOD, self.ShouldRefresh, args, kwargs) + self.LastRefreshTimer.start() + self.TimerAccessLock.release() + def RefreshNewData(self, *args, **kwargs): + Called to refresh DebugViewer according to values received by data + May be overridden by inherited classes + Can receive any parameters depending on what is needed by inherited + # Activate data consumer value update + # Release common refresh lock if acquired and update + self.AccessLock.acquire() + if self.HasAcquiredLock: + DEBUG_REFRESH_LOCK.release() + self.HasAcquiredLock = False + if gettime() - self.LastRefreshTime > REFRESH_PERIOD: + self.LastRefreshTime = gettime() + self.AccessLock.release() --- a/editors/GraphicViewer.py Mon May 27 09:24:39 2013 +0200
+++ b/editors/GraphicViewer.py Mon May 27 13:09:54 2013 +0200
@@ -29,8 +29,9 @@
import wx.lib.plot as plot
-from graphics.GraphicCommons import DebugViewer, MODE_SELECTION, MODE_MOTION
-from EditorPanel import EditorPanel
+from graphics.GraphicCommons import MODE_SELECTION, MODE_MOTION +from editors.DebugViewer import DebugViewer +from editors.EditorPanel import EditorPanel from util.BitmapLibrary import GetBitmap
colours = ['blue', 'red', 'green', 'yellow', 'orange', 'purple', 'brown', 'cyan',
--- a/editors/Viewer.py Mon May 27 09:24:39 2013 +0200
+++ b/editors/Viewer.py Mon May 27 13:09:54 2013 +0200
@@ -35,6 +35,7 @@
+from editors.DebugViewer import DebugViewer from EditorPanel import EditorPanel
@@ -375,7 +376,7 @@
manipulating graphic elements
-class Viewer(EditorPanel, DebugViewer, DebugDataConsumer):
+class Viewer(EditorPanel, DebugViewer): if wx.VERSION < (2, 6, 0):
def Bind(self, event, function, id = None):
@@ -556,7 +557,6 @@
EditorPanel.__init__(self, parent, tagname, window, controler, debug)
DebugViewer.__init__(self, controler, debug)
- DebugDataConsumer.__init__(self)
# Adding a rubberband to Viewer
self.rubberBand = RubberBand(viewer=self)
@@ -892,7 +892,7 @@
self.ToolTipElement = None
- self.DeleteDataConsumers()
+ self.UnsubscribeAllDataConsumers() for block in self.Blocks.itervalues():
@@ -1048,8 +1048,8 @@
DebugViewer.RefreshNewData(self)
- def RegisterVariables(self):
- DebugViewer.RegisterVariables(self)
+ def SubscribeAllDataConsumers(self): + DebugViewer.SubscribeAllDataConsumers(self) # Refresh Viewer elements
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graphics/DebugDataConsumer.py Mon May 27 13:09:54 2013 +0200
@@ -0,0 +1,248 @@
+#This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor +#based on the plcopen standard. +#Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD +#See COPYING file for copyrights details. +#This library is free software; you can redistribute it and/or +#modify it under the terms of the GNU General Public +#License as published by the Free Software Foundation; either +#version 2.1 of the License, or (at your option) any later version. +#This library is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +#General Public License for more details. +#You should have received a copy of the GNU General Public +#License along with this library; if not, write to the Free Software +#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#------------------------------------------------------------------------------- +# Date and Time conversion function +#------------------------------------------------------------------------------- +SECOND = 1000000 # Number of microseconds in one second +MINUTE = 60 * SECOND # Number of microseconds in one minute +HOUR = 60 * MINUTE # Number of microseconds in one hour +DAY = 24 * HOUR # Number of microseconds in one day +# Date corresponding to Epoch (1970 January the first) +DATE_ORIGIN = datetime.datetime(1970, 1, 1) +def get_microseconds(value): + Function converting time duration expressed in day, second and microseconds + into one expressed in microseconds + @param value: Time duration to convert + @return: Time duration expressed in microsecond + return float(value.days * DAY + \ + value.seconds * SECOND + \ +def generate_time(value): + Function converting time duration expressed in day, second and microseconds + into a IEC 61131 TIME literal + @param value: Time duration to convert + @return: IEC 61131 TIME literal + microseconds = get_microseconds(value) + # Get absolute microseconds value and save if it was negative + negative = microseconds < 0 + microseconds = abs(microseconds) + # In TIME literal format, it isn't mandatory to indicate null values + # if no greater non-null values are available. This variable is used to + # inhibit formatting until a non-null value is found + (int(microseconds) / DAY, "%dd"), # Days + ((int(microseconds) % DAY) / HOUR, "%dh"), # Hours + ((int(microseconds) % HOUR) / MINUTE, "%dm"), # Minutes + ((int(microseconds) % MINUTE) / SECOND, "%ds")]: # Seconds + # Add value to TIME literal if value is non-null or another non-null + # value have already be found + if val > 0 or not_null: + # Update non-null variable + # In any case microseconds have to be added to TIME literal + data += "%gms" % (microseconds % SECOND / 1000.) +def generate_date(value): + Function converting time duration expressed in day, second and microseconds + into a IEC 61131 DATE literal + @param value: Time duration to convert + @return: IEC 61131 DATE literal + return (DATE_ORIGIN + value).strftime("DATE#%Y-%m-%d") +def generate_datetime(value): + Function converting time duration expressed in day, second and microseconds + into a IEC 61131 DATE_AND_TIME literal + @param value: Time duration to convert + @return: IEC 61131 DATE_AND_TIME literal + return (DATE_ORIGIN + value).strftime("DT#%Y-%m-%d-%H:%M:%S.%f") +def generate_timeofday(value): + Function converting time duration expressed in day, second and microseconds + into a IEC 61131 TIME_OF_DAY literal + @param value: Time duration to convert + @return: IEC 61131 TIME_OF_DAY literal + microseconds = get_microseconds(value) + # TIME_OF_DAY literal prefix + (int(microseconds) / HOUR, "%2.2d:"), # Hours + ((int(microseconds) % HOUR) / MINUTE, "%2.2d:"), # Minutes + ((int(microseconds) % MINUTE) / SECOND, "%2.2d."), # Seconds + (microseconds % SECOND, "%6.6d")]: # Microseconds + # Add value to TIME_OF_DAY literal +# Dictionary of translation functions from value send by debugger to IEC +# literal stored by type + "DT": generate_datetime, + "TOD": generate_timeofday, + "STRING": lambda v: "'%s'" % v, + "WSTRING": lambda v: '"%s"' % v, + "REAL": lambda v: "%.6g" % v, + "LREAL": lambda v: "%.6g" % v, +#------------------------------------------------------------------------------- +# Debug Data Consumer Class +#------------------------------------------------------------------------------- +Class that implements an element that consumes debug values +Value update can be inhibited during the time the associated Debug Viewer is +class DebugDataConsumer: + # Debug value and forced flag + # Store debug value and forced flag when value update is inhibited + self.LastForced = False + # Flag that value update is inhibited + def Inhibit(self, inhibit): + Set flag to inhibit or activate value update + @param inhibit: Inhibit flag + self.Inhibited = inhibit + # When reactivated update value and forced flag with stored values + if not inhibit and self.LastValue is not None: + self.SetForced(self.LastForced) + self.SetValue(self.LastValue) + self.LastForced = False + def SetDataType(self, data_type): + Set value IEC data type + @param data_type: Value IEC data type + self.DataType = data_type + def NewValue(self, tick, value, forced=False): + 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) + # Translate value to IEC literal + value = TYPE_TRANSLATOR.get(self.DataType, str)(value) + # Store value and forced flag when value update is inhibited + self.LastForced = forced + # Update value and forced flag in any other case + def SetValue(self, value): + May be overridden by inherited classes + @param value: New value + def SetForced(self, forced): + Update Forced flag. May be overridden by inherited classes + @param forced: New forced flag + Indicate if current value is forced + @return: Current forced flag --- a/graphics/FBD_Objects.py Mon May 27 09:24:39 2013 +0200
+++ b/graphics/FBD_Objects.py Mon May 27 13:09:54 2013 +0200
@@ -24,7 +24,7 @@
-from GraphicCommons import *
+from graphics.GraphicCommons import * from plcopen.structures import *
#-------------------------------------------------------------------------------
--- a/graphics/GraphicCommons.py Mon May 27 09:24:39 2013 +0200
+++ b/graphics/GraphicCommons.py Mon May 27 13:09:54 2013 +0200
@@ -23,13 +23,13 @@
#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-from time import time as gettime
from threading import Lock,Timer
from graphics.ToolTipProducer import ToolTipProducer
+from graphics.DebugDataConsumer import DebugDataConsumer #-------------------------------------------------------------------------------
@@ -186,56 +186,6 @@
-def generate_time(value):
- microseconds = float(value.days * DAY + value.seconds * SECOND + value.microseconds)
- negative = microseconds < 0
- microseconds = abs(microseconds)
- for val, format in [(int(microseconds) / DAY, "%dd"),
- ((int(microseconds) % DAY) / HOUR, "%dh"),
- ((int(microseconds) % HOUR) / MINUTE, "%dm"),
- ((int(microseconds) % MINUTE) / SECOND, "%ds")]:
- if val > 0 or not_null:
- data += "%gms" % (microseconds % SECOND / 1000.)
-def generate_date(value):
- base_date = datetime.datetime(1970, 1, 1)
- date = base_date + value
- return date.strftime("DATE#%Y-%m-%d")
-def generate_datetime(value):
- base_date = datetime.datetime(1970, 1, 1)
- date_time = base_date + value
- return date_time.strftime("DT#%Y-%m-%d-%H:%M:%S.%f")
-def generate_timeofday(value):
- microseconds = float(value.days * DAY + value.seconds * SECOND + value.microseconds)
- negative = microseconds < 0
- microseconds = abs(microseconds)
- for val, format in [(int(microseconds) / HOUR, "%2.2d:"),
- ((int(microseconds) % HOUR) / MINUTE, "%2.2d:"),
- ((int(microseconds) % MINUTE) / SECOND, "%2.2d."),
- (microseconds % SECOND, "%6.6d")]:
-TYPE_TRANSLATOR = {"TIME": generate_time,
- "DT": generate_datetime,
- "TOD": generate_timeofday}
def MiterPen(colour, width=1, style=wx.SOLID):
pen = wx.Pen(colour, width, style)
pen.SetJoin(wx.JOIN_MITER)
@@ -243,200 +193,6 @@
#-------------------------------------------------------------------------------
-# Debug Data Consumer Class
-#-------------------------------------------------------------------------------
-class DebugDataConsumer:
- self.LastForced = False
- def Inhibit(self, inhibit):
- self.Inhibited = inhibit
- if not inhibit and self.LastValue is not None:
- self.SetForced(self.LastForced)
- self.SetValue(self.LastValue)
- def SetDataType(self, data_type):
- self.DataType = data_type
- def NewValue(self, tick, value, forced=False):
- value = TYPE_TRANSLATOR.get(self.DataType, lambda x:x)(value)
- self.LastForced = forced
- def SetValue(self, value):
- def SetForced(self, forced):
-#-------------------------------------------------------------------------------
-#-------------------------------------------------------------------------------
-DEBUG_REFRESH_LOCK = Lock()
- def __init__(self, producer, debug, register_tick=True):
- self.DataProducer = None
- self.RegisterTick = register_tick
- self.DataConsumers = {}
- self.LastRefreshTime = gettime()
- self.HasAcquiredLock = False
- self.AccessLock = Lock()
- self.TimerAccessLock = Lock()
- self.LastRefreshTimer = None
- self.SetDataProducer(producer)
- self.DataProducer = None
- self.DeleteDataConsumers()
- if self.LastRefreshTimer is not None:
- self.LastRefreshTimer.Stop()
- if self.HasAcquiredLock:
- DEBUG_REFRESH_LOCK.release()
- def SetDataProducer(self, producer):
- if self.RegisterTick and self.Debug:
- if producer is not None:
- producer.SubscribeDebugIECVariable("__tick__", self)
- if self.DataProducer is not None:
- self.DataProducer.UnsubscribeDebugIECVariable("__tick__", self)
- self.DataProducer = producer
- def Inhibit(self, inhibit):
- for consumer, iec_path in self.DataConsumers.iteritems():
- consumer.Inhibit(inhibit)
- self.Inhibited = inhibit
- def AddDataConsumer(self, iec_path, consumer):
- if self.DataProducer is None:
- result = self.DataProducer.SubscribeDebugIECVariable(iec_path, consumer)
- if result is not None and consumer != self:
- self.DataConsumers[consumer] = iec_path
- consumer.SetDataType(self.GetDataType(iec_path))
- def RemoveDataConsumer(self, consumer):
- iec_path = self.DataConsumers.pop(consumer, None)
- if iec_path is not None:
- self.DataProducer.UnsubscribeDebugIECVariable(iec_path, consumer)
- def RegisterVariables(self):
- if self.RegisterTick and self.Debug and self.DataProducer is not None:
- self.DataProducer.SubscribeDebugIECVariable("__tick__", self)
- def GetDataType(self, iec_path):
- if self.DataProducer is not None:
- data_type = self.DataProducer.GetDebugIECVariableType(iec_path.upper())
- if data_type is not None:
- infos = self.DataProducer.GetInstanceInfos(iec_path)
- def IsNumType(self, data_type):
- return self.DataProducer.IsNumType(data_type)
- def ForceDataValue(self, iec_path, value):
- if self.DataProducer is not None:
- self.DataProducer.ForceDebugIECVariable(iec_path, value)
- def ReleaseDataValue(self, iec_path):
- if self.DataProducer is not None:
- self.DataProducer.ReleaseDebugIECVariable(iec_path)
- def DeleteDataConsumers(self):
- if self.DataProducer is not None:
- for consumer, iec_path in self.DataConsumers.iteritems():
- self.DataProducer.UnsubscribeDebugIECVariable(iec_path, consumer)
- self.DataConsumers = {}
- def ShouldRefresh(self):
- wx.CallAfter(self._ShouldRefresh)
- def _ShouldRefresh(self):
- if DEBUG_REFRESH_LOCK.acquire(False):
- self.AccessLock.acquire()
- self.HasAcquiredLock = True
- self.AccessLock.release()
- self.TimerAccessLock.acquire()
- self.LastRefreshTimer = Timer(REFRESH_PERIOD, self.ShouldRefresh)
- self.LastRefreshTimer.start()
- self.TimerAccessLock.release()
- def NewDataAvailable(self, tick, *args, **kwargs):
- self.TimerAccessLock.acquire()
- if self.LastRefreshTimer is not None:
- self.LastRefreshTimer.cancel()
- self.LastRefreshTimer=None
- self.TimerAccessLock.release()
- if self.IsShown() and not self.Inhibited:
- if gettime() - self.LastRefreshTime > REFRESH_PERIOD and DEBUG_REFRESH_LOCK.acquire(False):
- self.AccessLock.acquire()
- self.HasAcquiredLock = True
- self.AccessLock.release()
- self.LastRefreshTime = gettime()
- wx.CallAfter(self.RefreshViewOnNewData, *args, **kwargs)
- self.TimerAccessLock.acquire()
- self.LastRefreshTimer = Timer(REFRESH_PERIOD, self.ShouldRefresh)
- self.LastRefreshTimer.start()
- self.TimerAccessLock.release()
- elif not self.IsShown() and self.HasAcquiredLock:
- DebugViewer.RefreshNewData(self)
- def RefreshViewOnNewData(self, *args, **kwargs):
- self.RefreshNewData(*args, **kwargs)
- def RefreshNewData(self, *args, **kwargs):
- self.AccessLock.acquire()
- if self.HasAcquiredLock:
- DEBUG_REFRESH_LOCK.release()
- self.HasAcquiredLock = False
- if gettime() - self.LastRefreshTime > REFRESH_PERIOD:
- self.LastRefreshTime = gettime()
- self.AccessLock.release()
-#-------------------------------------------------------------------------------
# Helpers for highlighting text
#-------------------------------------------------------------------------------
@@ -1377,13 +1133,7 @@
def GetComputedValue(self):
if self.Value is not None and self.Value != "undefined" and not isinstance(self.Value, BooleanType):
- wire_type = self.GetType()
- if wire_type == "STRING":
- return "'%s'"%self.Value
- elif wire_type == "WSTRING":
- return "\"%s\""%self.Value
def GetToolTipValue(self):
@@ -1960,13 +1710,7 @@
def GetComputedValue(self):
if self.Value is not None and self.Value != "undefined" and not isinstance(self.Value, BooleanType):
- wire_type = self.GetEndConnectedType()
- if wire_type == "STRING":
- return "'%s'"%self.Value
- elif wire_type == "WSTRING":
- return "\"%s\""%self.Value
def GetToolTipValue(self):
--- a/graphics/LD_Objects.py Mon May 27 09:24:39 2013 +0200
+++ b/graphics/LD_Objects.py Mon May 27 13:09:54 2013 +0200
@@ -24,7 +24,8 @@
-from GraphicCommons import *
+from graphics.GraphicCommons import * +from graphics.DebugDataConsumer import DebugDataConsumer from plcopen.structures import *
#-------------------------------------------------------------------------------
--- a/graphics/SFC_Objects.py Mon May 27 09:24:39 2013 +0200
+++ b/graphics/SFC_Objects.py Mon May 27 13:09:54 2013 +0200
@@ -24,7 +24,8 @@
-from GraphicCommons import *
+from graphics.GraphicCommons import * +from graphics.DebugDataConsumer import DebugDataConsumer from plcopen.structures import *
--- a/graphics/__init__.py Mon May 27 09:24:39 2013 +0200
+++ b/graphics/__init__.py Mon May 27 13:09:54 2013 +0200
@@ -28,4 +28,5 @@
from FBD_Objects import *
from SFC_Objects import *
-from RubberBand import RubberBand
\ No newline at end of file
+from RubberBand import RubberBand +from DebugDataConsumer import DebugDataConsumer \ No newline at end of file