diff -r d51af006fa6b -r 64d8f52bc8c8 editors/DebugViewer.py --- a/editors/DebugViewer.py Fri Aug 11 15:18:19 2017 +0300 +++ b/editors/DebugViewer.py Mon Aug 14 19:13:01 2017 +0300 @@ -35,12 +35,12 @@ #------------------------------------------------------------------------------- """ -Class that implements common behavior of every viewers able to display debug +Class that implements common behavior of every viewers able to display debug values """ class DebugViewer: - + def __init__(self, producer, debug, subscribe_tick=True): """ Constructor @@ -52,49 +52,49 @@ """ self.Debug = debug self.SubscribeTick = subscribe_tick - + # Flag indicating that consumer value update inhibited # (DebugViewer is refreshing) self.Inhibited = False - + # 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) - + def __del__(self): """ Destructor """ # 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): """ Set Data Producer @@ -103,25 +103,25 @@ # In the case that tick need to be subscribed and DebugViewer is # debugging if self.SubscribeTick and self.Debug: - + # Subscribe tick to new data producer if producer is not None: producer.SubscribeDebugIECVariable("__tick__", self, True) - + # 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 - + def IsDebugging(self): """ Get flag indicating if Debug Viewer is debugging @return: Debugging flag """ return self.Debug - + def Inhibit(self, inhibit): """ Set consumer value update inhibit flag @@ -130,10 +130,10 @@ # Inhibit every data consumers in list for consumer, iec_path in self.DataConsumers.iteritems(): consumer.Inhibit(inhibit) - + # Save inhibit flag self.Inhibited = inhibit - + def AddDataConsumer(self, iec_path, consumer, buffer_list=False): """ Subscribe data consumer to DataProducer @@ -145,19 +145,19 @@ # Return immediately if no DataProducer defined if self.DataProducer is None: return None - + # Subscribe data consumer to DataProducer result = self.DataProducer.SubscribeDebugIECVariable( iec_path, consumer, buffer_list) 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)) - + return result - + def RemoveDataConsumer(self, consumer): """ Unsubscribe data consumer from DataProducer @@ -165,12 +165,12 @@ """ # 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( iec_path, consumer) - + def SubscribeAllDataConsumers(self): """ Called to Subscribe all data consumers contained in DebugViewer. @@ -179,24 +179,24 @@ # Subscribe tick if needed if self.SubscribeTick and self.Debug and self.DataProducer is not None: self.DataProducer.SubscribeDebugIECVariable("__tick__", self, True) - + def UnsubscribeAllDataConsumers(self, tick=True): """ Called to Unsubscribe all data consumers. """ if self.DataProducer is not None: - + # Unscribe tick if needed if self.SubscribeTick and tick and self.Debug: self.DataProducer.UnsubscribeDebugIECVariable("__tick__", self) - + # Unsubscribe all data consumers in list for consumer, iec_path in self.DataConsumers.iteritems(): self.DataProducer.UnsubscribeDebugIECVariable( iec_path, consumer) - + self.DataConsumers = {} - + def GetDataType(self, iec_path): """ Return variable data type. @@ -204,20 +204,20 @@ @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( iec_path.upper()) if data_type is not None: return data_type - + # Search for variable informations in project data infos = self.DataProducer.GetInstanceInfos(iec_path) if infos is not None: return infos.type - + return None - + def IsNumType(self, data_type): """ Indicate if data type given is a numeric data type @@ -226,9 +226,9 @@ """ if self.DataProducer is not None: return self.DataProducer.IsNumType(data_type) - + return False - + def ForceDataValue(self, iec_path, value): """ Force PLC variable value @@ -237,7 +237,7 @@ """ if self.DataProducer is not None: self.DataProducer.ForceDebugIECVariable(iec_path, value) - + def ReleaseDataValue(self, iec_path): """ Release PLC variable value @@ -245,12 +245,12 @@ """ if self.DataProducer is not None: self.DataProducer.ReleaseDebugIECVariable(iec_path) - + def NewDataAvailable(self, ticks): """ Called by DataProducer for each tick captured @param tick: PLC tick captured - All other parameters are passed to refresh function + All other parameters are passed to refresh function """ # Stop last refresh timer self.TimerAccessLock.acquire() @@ -258,27 +258,27 @@ self.LastRefreshTimer.cancel() self.LastRefreshTimer=None self.TimerAccessLock.release() - + # Only try to refresh DebugViewer if it is visible on screen and not # already refreshing 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() - + # If common lock wasn't acquired for any reason, restart last # refresh timer else: self.StartLastRefreshTimer() - + # 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): """ Callback function called when last refresh timer expired @@ -286,15 +286,15 @@ """ # 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() - + # Restart last refresh timer if common refresh lock acquired failed else: self.StartLastRefreshTimer() - + def StartRefreshing(self): """ Called to initiate a refresh of DebugViewer @@ -306,13 +306,13 @@ self.HasAcquiredLock = True self.LastRefreshTime = gettime() self.AccessLock.release() - + # Inhibit data consumer value update self.Inhibit(True) - + # Initiate DebugViewer refresh wx.CallAfter(self.RefreshNewData) - + def StartLastRefreshTimer(self): """ Called to start last refresh timer for the minimum time between 2 @@ -324,19 +324,19 @@ REFRESH_PERIOD, self.ShouldRefresh) self.LastRefreshTimer.start() self.TimerAccessLock.release() - + def RefreshNewData(self): """ Called to refresh DebugViewer according to values received by data consumers May be overridden by inherited classes Can receive any parameters depending on what is needed by inherited - class + class """ if self: # Activate data consumer value update self.Inhibit(False) - + # Release common refresh lock if acquired and update # last refresh time self.AccessLock.acquire()