handlesignalend() prüfte immer auf cleanupfunc, auch wenn None

cycleloop cycletime=None gesetzt - bei Nichtangabe wurde immer 50 gesetzt
io.reg_timerevent() hinzugefügt
docstring
This commit is contained in:
2017-08-31 14:27:38 +02:00
parent 705ae09cd0
commit c226e91550
8 changed files with 148 additions and 24 deletions

View File

@@ -165,6 +165,9 @@ Methods</h3>
<td><a style="color:#0000FF" href="#IOBase.reg_event">reg_event</a></td>
<td>Registriert fuer IO ein Event bei der Eventueberwachung.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#IOBase.reg_timerevent">reg_timerevent</a></td>
<td>Registriert fuer IO einen Timer, welcher nach delay func ausfuehrt.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#IOBase.replace_io">replace_io</a></td>
<td>Ersetzt bestehenden IO mit Neuem.</td>
</tr><tr>
@@ -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.
</p><p>
HINWEIS: Die delay-Zeit muss in die .cycletime passen, ist dies nicht
der Fall, wird IMMER aufgerundet!
</p><dl>
<dt><i>func</i></dt>
<dd>
@@ -318,6 +324,36 @@ Ausfuehren bei RISING, FALLING or BOTH Wertaenderung
<dd>
Bei True, Funktion als EventCallback-Thread ausfuehren
</dd>
</dl><a NAME="IOBase.reg_timerevent" ID="IOBase.reg_timerevent"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
IOBase.reg_timerevent</h3>
<b>reg_timerevent</b>(<i>func, delay, edge=BOTH, as_thread=False</i>)
<p>
Registriert fuer IO einen Timer, welcher nach delay func ausfuehrt.
</p><p>
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.
</p><p>
HINWEIS: Die delay-Zeit muss in die .cycletime passen, ist dies nicht
der Fall, wird IMMER aufgerundet!
</p><dl>
<dt><i>func</i></dt>
<dd>
Funktion die bei Aenderung aufgerufen werden soll
</dd><dt><i>delay</i></dt>
<dd>
Verzoegerung in ms zum Ausloesen - auch bei Wertaenderung
</dd><dt><i>edge</i></dt>
<dd>
Ausfuehren bei RISING, FALLING or BOTH Wertaenderung
</dd><dt><i>as_thread</i></dt>
<dd>
Bei True, Funktion als EventCallback-Thread ausfuehren
</dd>
</dl><a NAME="IOBase.replace_io" ID="IOBase.replace_io"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
IOBase.replace_io</h3>

View File

@@ -345,7 +345,7 @@ Beendet autorefresh und alle Threads.
</p><a NAME="RevPiModIO.cycleloop" ID="RevPiModIO.cycleloop"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiModIO.cycleloop</h3>
<b>cycleloop</b>(<i>func, cycletime=50</i>)
<b>cycleloop</b>(<i>func, cycletime=None</i>)
<p>
Startet den Cycleloop.
</p><p>
@@ -373,7 +373,8 @@ Startet den Cycleloop.
Funktion, die ausgefuehrt werden soll
</dd><dt><i>cycletime</i></dt>
<dd>
autorefresh Wert in Millisekunden
Zykluszeit in Millisekunden, bei Nichtangabe wird
aktuelle .cycletime Zeit verwendet - Standardwert 50 ms
</dd>
</dl><dl>
<dt>Returns:</dt>

View File

@@ -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()

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Project SYSTEM "Project-5.1.dtd">
<!-- eric project file for project revpimodio2 -->
<!-- Saved: 2017-08-29, 18:21:17 -->
<!-- Saved: 2017-08-31, 13:28:15 -->
<!-- Copyright (C) 2017 Sven Sager, akira@narux.de -->
<Project version="5.1">
<Language>en_US</Language>
@@ -9,7 +9,7 @@
<ProgLanguage mixed="0">Python3</ProgLanguage>
<ProjectType>Console</ProjectType>
<Description>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.</Description>
<Version>2.0.1</Version>
<Version>2.0.2</Version>
<Author>Sven Sager</Author>
<Email>akira@narux.de</Email>
<Eol index="1"/>
@@ -28,6 +28,9 @@
<Source>test/test_net_leistung.py</Source>
<Source>test/web_cycleloop.py</Source>
<Source>test/web_mainloop.py</Source>
<Source>test/web_virtdevdriver.py</Source>
<Source>test/web_benniesrun.py</Source>
<Source>test/web_benniesrunxxl.py</Source>
</Sources>
<Forms/>
<Translations/>
@@ -349,7 +352,7 @@
<string>ExcludeFiles</string>
</key>
<value>
<string>*/test/*</string>
<string>*/test/*,*/setup.py</string>
</value>
</dict>
</value>

View File

@@ -24,7 +24,7 @@ __all__ = ["RevPiModIO", "RevPiModIOSelected", "RevPiModIODriver"]
__author__ = "Sven Sager <akira@revpimodio.org>"
__name__ = "revpimodio2"
__package__ = "revpimodio2"
__version__ = "2.0.1"
__version__ = "2.0.2"
# Global package values
OFF = 0

View File

@@ -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 <class 'int'> 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 <class 'int'> 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):

View File

@@ -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(

View File

@@ -16,7 +16,7 @@ setup(
license="LGPLv3",
name="revpimodio2",
version="2.0.1",
version="2.0.2",
packages=["revpimodio2"],