IOEvent-Klasse eingebaut - Ersetzt tuple()

reg_event, reg_timerevent über zentrale Funktion verwaltet
This commit is contained in:
2017-12-02 16:17:02 +01:00
parent b16af483dc
commit 87a648cbc6
5 changed files with 166 additions and 120 deletions

View File

@@ -24,6 +24,9 @@ Classes</h3>
<td><a style="color:#0000FF" href="#IOBase">IOBase</a></td>
<td>Basisklasse fuer alle IO-Objekte.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#IOEvent">IOEvent</a></td>
<td>Basisklasse fuer IO-Events.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#IOList">IOList</a></td>
<td>Basisklasse fuer direkten Zugriff auf IO Objekte.</td>
</tr><tr>
@@ -141,6 +144,9 @@ Methods</h3>
<td><a style="color:#0000FF" href="#IOBase.__len__">__len__</a></td>
<td>Gibt die Bytelaenge des IO zurueck.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#IOBase.__reg_xevent">__reg_xevent</a></td>
<td>Verwaltet reg_event und reg_timerevent.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#IOBase.__str__">__str__</a></td>
<td><class 'str'>-Wert der Klasse.</td>
</tr><tr>
@@ -228,6 +234,29 @@ Gibt die Bytelaenge des IO zurueck.
<dd>
Bytelaenge des IO - 0 bei BITs
</dd>
</dl><a NAME="IOBase.__reg_xevent" ID="IOBase.__reg_xevent"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
IOBase.__reg_xevent</h3>
<b>__reg_xevent</b>(<i>func, delay, edge, as_thread, overwrite</i>)
<p>
Verwaltet reg_event und reg_timerevent.
</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><dt><i>overwrite</i></dt>
<dd>
Wenn True, wird Event bei ueberschrieben
</dd>
</dl><a NAME="IOBase.__str__" ID="IOBase.__str__"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
IOBase.__str__</h3>
@@ -468,6 +497,46 @@ Zeit in ms nach der abgebrochen wird
</dl>
<div align="right"><a style="color:#0000FF" href="#top">Up</a></div>
<hr /><hr />
<a NAME="IOEvent" ID="IOEvent"></a>
<h2 style="background-color:#FFFFFF;color:#0000FF">IOEvent</h2>
<p>
Basisklasse fuer IO-Events.
</p>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Derived from</h3>
object
<h3 style="background-color:#FFFFFF;color:#FF0000">
Class Attributes</h3>
<table>
<tr><td>None</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Class Methods</h3>
<table>
<tr><td>None</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Methods</h3>
<table>
<tr>
<td><a style="color:#0000FF" href="#IOEvent.__init__">IOEvent</a></td>
<td>Init IOEvent class.</td>
</tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Static Methods</h3>
<table>
<tr><td>None</td></tr>
</table>
<a NAME="IOEvent.__init__" ID="IOEvent.__init__"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
IOEvent (Constructor)</h3>
<b>IOEvent</b>(<i>func, edge, as_thread, delay, overwrite</i>)
<p>
Init IOEvent class.
</p>
<div align="right"><a style="color:#0000FF" href="#top">Up</a></div>
<hr /><hr />
<a NAME="IOList" ID="IOList"></a>
<h2 style="background-color:#FFFFFF;color:#0000FF">IOList</h2>
<p>

View File

@@ -105,6 +105,7 @@ revpimodio2.io.IOBase.unreg_event?4(func=None, edge=None)
revpimodio2.io.IOBase.value?7
revpimodio2.io.IOBase.wait?4(edge=BOTH, exitevent=None, okvalue=None, timeout=0)
revpimodio2.io.IOBase?1(parentdevice, valuelist, iotype, byteorder, signed)
revpimodio2.io.IOEvent?1(func, edge, as_thread, delay, overwrite)
revpimodio2.io.IOList._private_register_new_io_object?5(new_io)
revpimodio2.io.IOList?1()
revpimodio2.io.IntIO._get_signed?5()

View File

@@ -321,11 +321,11 @@ class ProcimgWriter(Thread):
continue
for regfunc in dev._dict_events[io_event]:
if regfunc[1] == BOTH \
or regfunc[1] == RISING and boolor \
or regfunc[1] == FALLING and not boolor:
if regfunc[3] == 0:
if regfunc[2]:
if regfunc.edge == BOTH \
or regfunc.edge == RISING and boolor \
or regfunc.edge == FALLING and not boolor:
if regfunc.delay == 0:
if regfunc.as_thread:
self.__eventqth.put(
(regfunc, io_event._name, io_event.value),
False
@@ -340,14 +340,15 @@ class ProcimgWriter(Thread):
tupfire = (
regfunc, io_event._name, io_event.value
)
if regfunc[4] or tupfire not in self.__dict_delay:
if regfunc.overwrite \
or tupfire not in self.__dict_delay:
self.__dict_delay[tupfire] = ceil(
regfunc[3] / 1000 / self._refresh
regfunc.delay / 1000 / self._refresh
)
else:
for regfunc in dev._dict_events[io_event]:
if regfunc[3] == 0:
if regfunc[2]:
if regfunc.delay == 0:
if regfunc.as_thread:
self.__eventqth.put(
(regfunc, io_event._name, io_event.value),
False
@@ -362,9 +363,10 @@ class ProcimgWriter(Thread):
tupfire = (
regfunc, io_event._name, io_event.value
)
if regfunc[4] or tupfire not in self.__dict_delay:
if regfunc.overwrite \
or tupfire not in self.__dict_delay:
self.__dict_delay[tupfire] = ceil(
regfunc[3] / 1000 / self._refresh
regfunc.delay / 1000 / self._refresh
)
# Nach Verarbeitung aller IOs die Bytes kopieren (Lock ist noch drauf)
@@ -376,10 +378,9 @@ class ProcimgWriter(Thread):
try:
tup_fireth = self.__eventqth.get(timeout=1)
th = EventCallback(
tup_fireth[0][0], tup_fireth[1], tup_fireth[2]
tup_fireth[0].func, tup_fireth[1], tup_fireth[2]
)
th.start()
# TODO: Error handling
except queue.Empty:
pass
@@ -492,7 +493,7 @@ class ProcimgWriter(Thread):
# Verzögerte Events prüfen
if self.__eventwork:
for tup_fire in list(self.__dict_delay.keys()):
if tup_fire[0][4] \
if tup_fire[0].overwrite \
and getattr(self._modio.io, tup_fire[1]).value != \
tup_fire[2]:
del self.__dict_delay[tup_fire]
@@ -500,7 +501,7 @@ class ProcimgWriter(Thread):
self.__dict_delay[tup_fire] -= 1
if self.__dict_delay[tup_fire] <= 0:
# Verzögertes Event übernehmen und löschen
if tup_fire[0][2]:
if tup_fire[0].as_thread:
self.__eventqth.put(tup_fire, False)
else:
self._eventq.put(tup_fire, False)
@@ -530,6 +531,7 @@ class ProcimgWriter(Thread):
def stop(self):
"""Beendet die automatische Prozessabbildsynchronisierung."""
self._collect_events(False)
self._work.set()
def set_maxioerrors(self, value):

View File

@@ -11,6 +11,19 @@ from threading import Event
from revpimodio2 import RISING, FALLING, BOTH, INP, OUT, MEM, consttostr
class IOEvent(object):
"""Basisklasse fuer IO-Events."""
def __init__(self, func, edge, as_thread, delay, overwrite):
"""Init IOEvent class."""
self.as_thread = as_thread
self.delay = delay
self.edge = edge
self.func = func
self.overwrite = overwrite
class IOList(object):
"""Basisklasse fuer direkten Zugriff auf IO Objekte."""
@@ -317,6 +330,67 @@ class IOBase(object):
@return Namen des IOs"""
return self._name
def __reg_xevent(self, func, delay, edge, as_thread, overwrite):
"""Verwaltet reg_event und reg_timerevent.
@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
@param overwrite Wenn True, wird Event bei ueberschrieben
"""
# 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] = \
[IOEvent(func, edge, as_thread, delay, overwrite)]
else:
# Prüfen ob Funktion schon registriert ist
for regfunc in self._parentdevice._dict_events[self]:
if regfunc.func != func:
# Nächsten Eintrag testen
continue
if edge == BOTH or regfunc.edge == 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.edge), consttostr(edge)
)
)
elif regfunc.edge == 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(
IOEvent(func, edge, as_thread, delay, overwrite)
)
def _get_address(self):
"""Gibt die absolute Byteadresse im Prozessabbild zurueck.
@return Absolute Byteadresse"""
@@ -365,56 +439,7 @@ class IOBase(object):
@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, True)]
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, True)
)
self.__reg_xevent(func, delay, edge, as_thread, True)
def reg_timerevent(self, func, delay, edge=BOTH, as_thread=False):
"""Registriert fuer IO einen Timer, welcher nach delay func ausfuehrt.
@@ -435,56 +460,7 @@ class IOBase(object):
@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)
)
self.__reg_xevent(func, delay, edge, as_thread, False)
def replace_io(self, name, frm, **kwargs):
"""Ersetzt bestehenden IO mit Neuem.
@@ -613,8 +589,8 @@ class IOBase(object):
else:
newlist = []
for regfunc in self._parentdevice._dict_events[self]:
if regfunc[0] != func or edge is not None \
and regfunc[1] != edge:
if regfunc.func != func or edge is not None \
and regfunc.edge != edge:
newlist.append(regfunc)

View File

@@ -418,7 +418,6 @@ class RevPiModIO(object):
if self._imgwriter is not None and self._imgwriter.is_alive():
self._imgwriter.stop()
self._imgwriter.join(self._imgwriter._refresh)
# NOTE: Prüfen, ob es sauber läuft!
if self._th_mainloop is not None and self._th_mainloop.is_alive():
self._th_mainloop.join(1)
while len(self._lst_refresh) > 0:
@@ -426,7 +425,6 @@ class RevPiModIO(object):
dev._selfupdate = False
if not self._monitoring:
self.writeprocimg(dev)
# NOTE: Loops müssen sich selber IMMER sauber beenden
def get_jconfigrsc(self):
"""Laed die piCotry Konfiguration und erstellt ein <class 'dict'>.
@@ -540,7 +538,7 @@ class RevPiModIO(object):
try:
tup_fire = self._imgwriter._eventq.get(timeout=1)
# Direct callen da Prüfung in io.IOBase.reg_event ist
tup_fire[0][0](tup_fire[1], tup_fire[2])
tup_fire[0].func(tup_fire[1], tup_fire[2])
except Empty:
if not self._exit.is_set() and not self._imgwriter.is_alive():
self.exit(full=False)