From c226e915504a23bb053e8f4ad7e136f84956533c Mon Sep 17 00:00:00 2001 From: NaruX Date: Thu, 31 Aug 2017 14:27:38 +0200 Subject: [PATCH] =?UTF-8?q?handlesignalend()=20pr=C3=BCfte=20immer=20auf?= =?UTF-8?q?=20cleanupfunc,=20auch=20wenn=20None=20cycleloop=20cycletime=3D?= =?UTF-8?q?None=20gesetzt=20-=20bei=20Nichtangabe=20wurde=20immer=2050=20g?= =?UTF-8?q?esetzt=20io.reg=5Ftimerevent()=20hinzugef=C3=BCgt=20docstring?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/revpimodio2.io.html | 36 +++++++++++++++++ doc/revpimodio2.modio.html | 5 ++- eric-revpimodio2.api | 3 +- revpimodio2.e4p | 9 +++-- revpimodio2/__init__.py | 2 +- revpimodio2/io.py | 79 ++++++++++++++++++++++++++++++++++++-- revpimodio2/modio.py | 36 ++++++++++------- setup.py | 2 +- 8 files changed, 148 insertions(+), 24 deletions(-) diff --git a/doc/revpimodio2.io.html b/doc/revpimodio2.io.html index 9989511..8e17215 100644 --- a/doc/revpimodio2.io.html +++ b/doc/revpimodio2.io.html @@ -165,6 +165,9 @@ Methods reg_event Registriert fuer IO ein Event bei der Eventueberwachung. +reg_timerevent +Registriert fuer IO einen Timer, welcher nach delay func ausfuehrt. + replace_io Ersetzt bestehenden IO mit Neuem. @@ -304,6 +307,9 @@ Registriert fuer IO ein Event bei der Eventueberwachung. Die uebergebene Funktion wird ausgefuehrt, wenn sich der IO Wert aendert. Mit Angabe von optionalen Parametern kann das Ausloeseverhalten gesteuert werden. +

+ HINWEIS: Die delay-Zeit muss in die .cycletime passen, ist dies nicht + der Fall, wird IMMER aufgerundet!

func
@@ -318,6 +324,36 @@ Ausfuehren bei RISING, FALLING or BOTH Wertaenderung
Bei True, Funktion als EventCallback-Thread ausfuehren
+
+

+IOBase.reg_timerevent

+reg_timerevent(func, delay, edge=BOTH, as_thread=False) +

+Registriert fuer IO einen Timer, welcher nach delay func ausfuehrt. +

+ Der Timer wird gestartet, wenn sich der IO Wert aendert und fuehrt die + uebergebene Funktion aus - auch wenn sich der IO Wert in der + zwischenzeit geaendert hat. Sollte der Timer nicht abelaufen sein und + die Bedingugn erneut zutreffen, wird der Timer NICHT auf den delay Wert + zurueckgesetzt oder ein zweites Mal gestartet. Fuer dieses Verhalten + kann .reg_event(..., delay=wert) verwendet werden. +

+ HINWEIS: Die delay-Zeit muss in die .cycletime passen, ist dies nicht + der Fall, wird IMMER aufgerundet! +

+
func
+
+Funktion die bei Aenderung aufgerufen werden soll +
delay
+
+Verzoegerung in ms zum Ausloesen - auch bei Wertaenderung +
edge
+
+Ausfuehren bei RISING, FALLING or BOTH Wertaenderung +
as_thread
+
+Bei True, Funktion als EventCallback-Thread ausfuehren +

IOBase.replace_io

diff --git a/doc/revpimodio2.modio.html b/doc/revpimodio2.modio.html index ae91e2c..0a78558 100644 --- a/doc/revpimodio2.modio.html +++ b/doc/revpimodio2.modio.html @@ -345,7 +345,7 @@ Beendet autorefresh und alle Threads.

RevPiModIO.cycleloop

-cycleloop(func, cycletime=50) +cycleloop(func, cycletime=None)

Startet den Cycleloop.

@@ -373,7 +373,8 @@ Startet den Cycleloop. Funktion, die ausgefuehrt werden soll

cycletime
-autorefresh Wert in Millisekunden +Zykluszeit in Millisekunden, bei Nichtangabe wird + aktuelle .cycletime Zeit verwendet - Standardwert 50 ms
Returns:
diff --git a/eric-revpimodio2.api b/eric-revpimodio2.api index 9547b10..4c46bd6 100644 --- a/eric-revpimodio2.api +++ b/eric-revpimodio2.api @@ -86,6 +86,7 @@ revpimodio2.io.IOBase.get_value?4() revpimodio2.io.IOBase.length?7 revpimodio2.io.IOBase.name?7 revpimodio2.io.IOBase.reg_event?4(func, delay=0, edge=BOTH, as_thread=False) +revpimodio2.io.IOBase.reg_timerevent?4(func, delay, edge=BOTH, as_thread=False) revpimodio2.io.IOBase.replace_io?4(name, frm, **kwargs) revpimodio2.io.IOBase.set_value?4(value) revpimodio2.io.IOBase.type?7 @@ -134,7 +135,7 @@ revpimodio2.modio.RevPiModIO._set_maxioerrors?5(value) revpimodio2.modio.RevPiModIO.autorefresh_all?4() revpimodio2.modio.RevPiModIO.cleanup?4() revpimodio2.modio.RevPiModIO.configrsc?7 -revpimodio2.modio.RevPiModIO.cycleloop?4(func, cycletime=50) +revpimodio2.modio.RevPiModIO.cycleloop?4(func, cycletime=None) revpimodio2.modio.RevPiModIO.cycletime?7 revpimodio2.modio.RevPiModIO.exit?4(full=True) revpimodio2.modio.RevPiModIO.get_jconfigrsc?4() diff --git a/revpimodio2.e4p b/revpimodio2.e4p index 5655f68..d1701b5 100644 --- a/revpimodio2.e4p +++ b/revpimodio2.e4p @@ -1,7 +1,7 @@ - + en_US @@ -9,7 +9,7 @@ Python3 Console Das Modul stellt alle Devices und IOs aus der piCtory Konfiguration in Python3 zur Verfügung. Es ermöglicht den direkten Zugriff auf die Werte über deren vergebenen Namen. Lese- und Schreibaktionen mit dem Prozessabbild werden von dem Modul selbst verwaltet, ohne dass sich der Programmierer um Offsets und Adressen kümmern muss. Für die Gatewaymodule wie ModbusTCP oder Profinet sind eigene 'Inputs' und 'Outputs' über einen bestimmten Adressbereich definierbar. Auf diese IOs kann mit Python3 über den Namen direkt auf die Werte zugegriffen werden. - 2.0.1 + 2.0.2 Sven Sager akira@narux.de @@ -28,6 +28,9 @@ test/test_net_leistung.py test/web_cycleloop.py test/web_mainloop.py + test/web_virtdevdriver.py + test/web_benniesrun.py + test/web_benniesrunxxl.py @@ -349,7 +352,7 @@ ExcludeFiles - */test/* + */test/*,*/setup.py diff --git a/revpimodio2/__init__.py b/revpimodio2/__init__.py index c9a740d..29663d6 100644 --- a/revpimodio2/__init__.py +++ b/revpimodio2/__init__.py @@ -24,7 +24,7 @@ __all__ = ["RevPiModIO", "RevPiModIOSelected", "RevPiModIODriver"] __author__ = "Sven Sager " __name__ = "revpimodio2" __package__ = "revpimodio2" -__version__ = "2.0.1" +__version__ = "2.0.2" # Global package values OFF = 0 diff --git a/revpimodio2/io.py b/revpimodio2/io.py index 60371ee..64547a1 100644 --- a/revpimodio2/io.py +++ b/revpimodio2/io.py @@ -363,6 +363,9 @@ class IOBase(object): aendert. Mit Angabe von optionalen Parametern kann das Ausloeseverhalten gesteuert werden. + HINWEIS: Die delay-Zeit muss in die .cycletime passen, ist dies nicht + der Fall, wird IMMER aufgerundet! + @param func Funktion die bei Aenderung aufgerufen werden soll @param delay Verzoegerung in ms zum Ausloesen wenn Wert gleich bleibt @param edge Ausfuehren bei RISING, FALLING or BOTH Wertaenderung @@ -376,7 +379,7 @@ class IOBase(object): ) if type(delay) != int or delay < 0: raise AttributeError( - "parameter 'delay' must be greater or equal 0" + "'delay' must be and greater or equal 0" ) if edge != BOTH and self._bitaddress < 0: raise AttributeError( @@ -385,7 +388,7 @@ class IOBase(object): if self not in self._parentdevice._dict_events: self._parentdevice._dict_events[self] = \ - [(func, edge, as_thread, delay)] + [(func, edge, as_thread, delay, True)] else: # Prüfen ob Funktion schon registriert ist for regfunc in self._parentdevice._dict_events[self]: @@ -417,7 +420,77 @@ class IOBase(object): # Eventfunktion einfügen self._parentdevice._dict_events[self].append( - (func, edge, as_thread, delay) + (func, edge, as_thread, delay, True) + ) + + def reg_timerevent(self, func, delay, edge=BOTH, as_thread=False): + """Registriert fuer IO einen Timer, welcher nach delay func ausfuehrt. + + Der Timer wird gestartet, wenn sich der IO Wert aendert und fuehrt die + uebergebene Funktion aus - auch wenn sich der IO Wert in der + zwischenzeit geaendert hat. Sollte der Timer nicht abelaufen sein und + die Bedingugn erneut zutreffen, wird der Timer NICHT auf den delay Wert + zurueckgesetzt oder ein zweites Mal gestartet. Fuer dieses Verhalten + kann .reg_event(..., delay=wert) verwendet werden. + + HINWEIS: Die delay-Zeit muss in die .cycletime passen, ist dies nicht + der Fall, wird IMMER aufgerundet! + + @param func Funktion die bei Aenderung aufgerufen werden soll + @param delay Verzoegerung in ms zum Ausloesen - auch bei Wertaenderung + @param edge Ausfuehren bei RISING, FALLING or BOTH Wertaenderung + @param as_thread Bei True, Funktion als EventCallback-Thread ausfuehren + + """ + # Prüfen ob Funktion callable ist + if not callable(func): + raise AttributeError( + "registered function '{}' is not callable".format(func) + ) + if type(delay) != int or delay < 0: + raise AttributeError( + "'delay' must be and greater or equal 0" + ) + if edge != BOTH and self._bitaddress < 0: + raise AttributeError( + "parameter 'edge' can be used with bit io objects only" + ) + + if self not in self._parentdevice._dict_events: + self._parentdevice._dict_events[self] = \ + [(func, edge, as_thread, delay, False)] + else: + # Prüfen ob Funktion schon registriert ist + for regfunc in self._parentdevice._dict_events[self]: + if regfunc[0] != func: + # Nächsten Eintrag testen + continue + + if edge == BOTH or regfunc[1] == BOTH: + if self._bitaddress < 0: + raise AttributeError( + "io '{}' with function '{}' already in list." + "".format(self._name, func) + ) + else: + raise AttributeError( + "io '{}' with function '{}' already in list with " + "edge '{}' - edge '{}' not allowed anymore".format( + self._name, func, + consttostr(regfunc[1]), consttostr(edge) + ) + ) + elif regfunc[1] == edge: + raise AttributeError( + "io '{}' with function '{}' for given edge '{}' " + "already in list".format( + self._name, func, consttostr(edge) + ) + ) + + # Eventfunktion einfügen + self._parentdevice._dict_events[self].append( + (func, edge, as_thread, delay, False) ) def replace_io(self, name, frm, **kwargs): diff --git a/revpimodio2/modio.py b/revpimodio2/modio.py index 987c103..1695f4e 100644 --- a/revpimodio2/modio.py +++ b/revpimodio2/modio.py @@ -8,6 +8,7 @@ """RevPiModIO Hauptklasse.""" import warnings from json import load as jload +from math import ceil from os import access, F_OK, R_OK from signal import signal, SIG_DFL, SIGINT, SIGTERM from threading import Thread, Event @@ -313,7 +314,7 @@ class RevPiModIO(object): self.io = None self.summary = None - def cycleloop(self, func, cycletime=50): + def cycleloop(self, func, cycletime=None): """Startet den Cycleloop. Der aktuelle Programmthread wird hier bis Aufruf von @@ -336,7 +337,8 @@ class RevPiModIO(object): Prozessabbild gesetzt werden. @param func Funktion, die ausgefuehrt werden soll - @param cycletime autorefresh Wert in Millisekunden + @param cycletime Zykluszeit in Millisekunden, bei Nichtangabe wird + aktuelle .cycletime Zeit verwendet - Standardwert 50 ms @return None """ @@ -357,7 +359,7 @@ class RevPiModIO(object): ) # Zykluszeit übernehmen - if cycletime != self._imgwriter.refresh: + if not (cycletime is None or cycletime == self._imgwriter.refresh): self._imgwriter.refresh = cycletime # Cycleloop starten @@ -460,7 +462,7 @@ class RevPiModIO(object): """ # Prüfen ob Funktion callable ist - if not callable(cleanupfunc): + if not (cleanupfunc is None or callable(cleanupfunc)): raise RuntimeError( "registered function '{}' ist not callable".format(cleanupfunc) ) @@ -526,7 +528,6 @@ class RevPiModIO(object): lst_fire = [] dict_delay = {} while not self._exit.is_set(): - # Auf neue Daten warten und nur ausführen wenn set() if not self._imgwriter.newdata.wait(2.5): if not self._exit.is_set() and not self._imgwriter.is_alive(): @@ -573,11 +574,14 @@ class RevPiModIO(object): )) else: # Verzögertes Event in dict einfügen - dict_delay[( + tupfire = ( regfunc, io_event._name, io_event.value - )] = int( - regfunc[3] / self._imgwriter.refresh ) + if regfunc[4] or tupfire not in dict_delay: + dict_delay[tupfire] = ceil( + regfunc[3] / + self._imgwriter.refresh + ) else: for regfunc in dev._dict_events[io_event]: if regfunc[3] == 0: @@ -586,9 +590,12 @@ class RevPiModIO(object): ) else: # Verzögertes Event in dict einfügen - dict_delay[( - regfunc, io_event._name, io_event.value - )] = int(regfunc[3] / self._imgwriter.refresh) + if regfunc[4] or regfunc not in dict_delay: + dict_delay[( + regfunc, io_event._name, io_event.value + )] = ceil( + regfunc[3] / self._imgwriter.refresh + ) # Nach Verarbeitung aller IOs die Bytes kopieren dev._filelock.acquire() @@ -599,9 +606,13 @@ class RevPiModIO(object): if not freeze: self._imgwriter.lck_refresh.release() + # EventTuple: + # ((func, edge, as_thread, delay, löschen), ioname, iovalue) + # Verzögerte Events prüfen for tup_fire in list(dict_delay.keys()): - if getattr(self.io, tup_fire[1]).value != tup_fire[2]: + if tup_fire[0][4] \ + and getattr(self.io, tup_fire[1]).value != tup_fire[2]: del dict_delay[tup_fire] else: dict_delay[tup_fire] -= 1 @@ -612,7 +623,6 @@ class RevPiModIO(object): # Erst nach Datenübernahme alle Events feuern while len(lst_fire) > 0: - # EventTuple ((func, edge, as_thread, delay), ioname, iovalue) tup_fire = lst_fire.pop() if tup_fire[0][2]: th = helpermodule.EventCallback( diff --git a/setup.py b/setup.py index a321f41..e3a7ca5 100644 --- a/setup.py +++ b/setup.py @@ -16,7 +16,7 @@ setup( license="LGPLv3", name="revpimodio2", - version="2.0.1", + version="2.0.2", packages=["revpimodio2"],