Kleinste refresh-Zeit auf 5 ms gesetzt

Zykluszeit vom .cycleloop wird bei Aufruf auf 50 ms gesetzt
Standardrefreshzeit wird nach CPU-Anzahl bestimmt
Laufzeitüberwachung für Eventsystem eingebaut
IOBase.export gibt Wert von 'Export' in piCtory zurück
Device.get_* Parameter 'export' Filtert auf piCtory 'Export' Wert
This commit is contained in:
2018-08-18 19:01:13 +02:00
parent 6ef9a55f93
commit ebbdbcaceb
8 changed files with 205 additions and 57 deletions

View File

@@ -553,7 +553,7 @@ Methods</h3>
<td>Gibt eine Liste aller Inputs zurueck.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#Device.get_memories">get_memories</a></td>
<td>Gibt eine Liste aller mems zurueck.</td>
<td>Gibt eine Liste aller Memoryobjekte zurueck.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#Device.get_outputs">get_outputs</a></td>
<td>Gibt eine Liste aller Outputs zurueck.</td>
@@ -623,13 +623,16 @@ True, wenn IO auf Device vorhanden
</dl><a NAME="Device.__getioiter" ID="Device.__getioiter"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Device.__getioiter</h3>
<b>__getioiter</b>(<i>ioslc</i>)
<b>__getioiter</b>(<i>ioslc, export</i>)
<p>
Gibt <class 'iter'> mit allen IOs zurueck.
</p><dl>
<dt><i>ioslc</i></dt>
<dd>
IO Abschnitt <class 'slice'>
</dd><dt><i>export</i></dt>
<dd>
Filter fuer 'Export' Flag in piCtory
</dd>
</dl><dl>
<dt>Returns:</dt>
@@ -741,10 +744,20 @@ Default True fuegt Device zur Synchronisierung hinzu
</dl><a NAME="Device.get_allios" ID="Device.get_allios"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Device.get_allios</h3>
<b>get_allios</b>(<i></i>)
<b>get_allios</b>(<i>export=None</i>)
<p>
Gibt eine Liste aller Inputs und Outputs zurueck, keine MEMs.
</p><p>
Bleibt Parameter 'export' auf None werden alle Inputs und Outputs
zurueckgegeben. Wird 'export' auf True/False gesetzt, werden nur Inputs
und Outputs zurueckgegeben, bei denen der Wert 'Export' in piCtory
uebereinstimmt.
</p><dl>
<dt><i>export</i></dt>
<dd>
Nur In-/Outputs mit angegebenen 'Export' Wert in piCtory
</dd>
</dl><dl>
<dt>Returns:</dt>
<dd>
<class 'list'> Input und Output, keine MEMs
@@ -752,10 +765,19 @@ Gibt eine Liste aller Inputs und Outputs zurueck, keine MEMs.
</dl><a NAME="Device.get_inputs" ID="Device.get_inputs"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Device.get_inputs</h3>
<b>get_inputs</b>(<i></i>)
<b>get_inputs</b>(<i>export=None</i>)
<p>
Gibt eine Liste aller Inputs zurueck.
</p><p>
Bleibt Parameter 'export' auf None werden alle Inputs zurueckgegeben.
Wird 'export' auf True/False gesetzt, werden nur Inputs zurueckgegeben,
bei denen der Wert 'Export' in piCtory uebereinstimmt.
</p><dl>
<dt><i>export</i></dt>
<dd>
Nur Inputs mit angegebenen 'Export' Wert in piCtory
</dd>
</dl><dl>
<dt>Returns:</dt>
<dd>
<class 'list'> Inputs
@@ -763,10 +785,19 @@ Gibt eine Liste aller Inputs zurueck.
</dl><a NAME="Device.get_memories" ID="Device.get_memories"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Device.get_memories</h3>
<b>get_memories</b>(<i></i>)
<b>get_memories</b>(<i>export=None</i>)
<p>
Gibt eine Liste aller mems zurueck.
Gibt eine Liste aller Memoryobjekte zurueck.
</p><p>
Bleibt Parameter 'export' auf None werden alle Mems zurueckgegeben.
Wird 'export' auf True/False gesetzt, werden nur Mems zurueckgegeben,
bei denen der Wert 'Export' in piCtory uebereinstimmt.
</p><dl>
<dt><i>export</i></dt>
<dd>
Nur Mems mit angegebenen 'Export' Wert in piCtory
</dd>
</dl><dl>
<dt>Returns:</dt>
<dd>
<class 'list'> Mems
@@ -774,10 +805,19 @@ Gibt eine Liste aller mems zurueck.
</dl><a NAME="Device.get_outputs" ID="Device.get_outputs"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Device.get_outputs</h3>
<b>get_outputs</b>(<i></i>)
<b>get_outputs</b>(<i>export=None</i>)
<p>
Gibt eine Liste aller Outputs zurueck.
</p><p>
Bleibt Parameter 'export' auf None werden alle Outputs zurueckgegeben.
Wird 'export' auf True/False gesetzt, werden nur Outputs
zurueckgegeben, bei denen der Wert 'Export' in piCtory uebereinstimmt.
</p><dl>
<dt><i>export</i></dt>
<dd>
Nur Outputs mit angegebenen 'Export' Wert in piCtory
</dd>
</dl><dl>
<dt>Returns:</dt>
<dd>
<class 'list'> Outputs

View File

@@ -26,6 +26,9 @@ Classes</h3>
</tr><tr>
<td><a style="color:#0000FF" href="#ProcimgWriter">ProcimgWriter</a></td>
<td>Klasse fuer Synchroniseriungs-Thread.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#Var">Var</a></td>
<td></td>
</tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
@@ -65,7 +68,7 @@ None
<h3 style="background-color:#FFFFFF;color:#FF0000">
Class Attributes</h3>
<table>
<tr><td>None</td></tr>
<tr><td>__slots__</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Class Methods</h3>
@@ -351,7 +354,7 @@ Thread
<h3 style="background-color:#FFFFFF;color:#FF0000">
Class Attributes</h3>
<table>
<tr><td>None</td></tr>
<tr><td>__slots__</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Class Methods</h3>
@@ -426,7 +429,7 @@ Thread
<h3 style="background-color:#FFFFFF;color:#FF0000">
Class Attributes</h3>
<table>
<tr><td>ioerrors</td></tr><tr><td>maxioerrors</td></tr><tr><td>refresh</td></tr>
<tr><td>__slots__</td></tr><tr><td>ioerrors</td></tr><tr><td>maxioerrors</td></tr><tr><td>refresh</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Class Methods</h3>
@@ -592,6 +595,35 @@ ProcimgWriter.stop</h3>
<p>
Beendet die automatische Prozessabbildsynchronisierung.
</p>
<div align="right"><a style="color:#0000FF" href="#top">Up</a></div>
<hr /><hr />
<a NAME="Var" ID="Var"></a>
<h2 style="background-color:#FFFFFF;color:#0000FF">Var</h2>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Derived from</h3>
None
<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>None</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Static Methods</h3>
<table>
<tr><td>None</td></tr>
</table>
<div align="right"><a style="color:#0000FF" href="#top">Up</a></div>
<hr />
</body></html>

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=None</i>)
<b>cycleloop</b>(<i>func, cycletime=50</i>)
<p>
Startet den Cycleloop.
</p><p>
@@ -358,23 +358,24 @@ Startet den Cycleloop.
Prozessabbild geschrieben.
</p><p>
Verlassen wird der Cycleloop, wenn die aufgerufene Funktion einen
Rueckgabewert nicht gleich None liefert, oder durch Aufruf von
revpimodio.exit().
Rueckgabewert nicht gleich None liefert (z.B. return True), oder durch
Aufruf von .exit().
</p><p>
HINWEIS: Die Aktualisierungszeit und die Laufzeit der Funktion duerfen
die eingestellte autorefresh Zeit, bzw. uebergebene cycletime nicht
ueberschreiten!
</p><p>
Ueber das Attribut cycletime kann die Aktualisierungsrate fuer das
Prozessabbild gesetzt werden.
Ueber den Parameter cycletime wird die gewuenschte Zukluszeit der
uebergebenen Funktion gesetzt. Der Standardwert betraegt
50 Millisekunden, in denen das Prozessabild eingelesen, die uebergebene
Funktion ausgefuert und das Prozessabbild geschrieben wird.
</p><dl>
<dt><i>func</i></dt>
<dd>
Funktion, die ausgefuehrt werden soll
</dd><dt><i>cycletime</i></dt>
<dd>
Zykluszeit in Millisekunden, bei Nichtangabe wird
aktuelle .cycletime Zeit verwendet - Standardwert 50 ms
Zykluszeit in Millisekunden - Standardwert 50 ms
</dd>
</dl><dl>
<dt>Returns:</dt>

View File

@@ -43,10 +43,10 @@ revpimodio2.device.Device._devconfigure?5()
revpimodio2.device.Device._get_offset?5()
revpimodio2.device.Device._get_producttype?5()
revpimodio2.device.Device.autorefresh?4(activate=True)
revpimodio2.device.Device.get_allios?4()
revpimodio2.device.Device.get_inputs?4()
revpimodio2.device.Device.get_memories?4()
revpimodio2.device.Device.get_outputs?4()
revpimodio2.device.Device.get_allios?4(export=None)
revpimodio2.device.Device.get_inputs?4(export=None)
revpimodio2.device.Device.get_memories?4(export=None)
revpimodio2.device.Device.get_outputs?4(export=None)
revpimodio2.device.Device.length?7
revpimodio2.device.Device.name?7
revpimodio2.device.Device.offset?7
@@ -152,7 +152,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=None)
revpimodio2.modio.RevPiModIO.cycleloop?4(func, cycletime=50)
revpimodio2.modio.RevPiModIO.cycletime?7
revpimodio2.modio.RevPiModIO.exit?4(full=True)
revpimodio2.modio.RevPiModIO.get_jconfigrsc?4()

View File

@@ -213,7 +213,7 @@ class Device(object):
def __iter__(self):
"""Gibt Iterator aller IOs zurueck.
@return <class 'iter'> aller IOs"""
return self.__getioiter(self._slc_devoff)
return self.__getioiter(self._slc_devoff, None)
def __len__(self):
"""Gibt Anzahl der Bytes zurueck, die dieses Device belegt.
@@ -225,13 +225,17 @@ class Device(object):
@return Devicename"""
return self._name
def __getioiter(self, ioslc):
def __getioiter(self, ioslc, export):
"""Gibt <class 'iter'> mit allen IOs zurueck.
@param ioslc IO Abschnitt <class 'slice'>
@return IOs als Iterator"""
@param export Filter fuer 'Export' Flag in piCtory
@return IOs als Iterator
"""
for lst_io in self._modio.io[ioslc]:
for io in lst_io:
if io is not None:
if io is not None and (export is None or io.export == export):
yield io
def _buildio(self, dict_io, iotype):
@@ -335,27 +339,60 @@ class Device(object):
if not self._modio._monitoring:
self._modio.writeprocimg(self)
def get_allios(self):
def get_allios(self, export=None):
"""Gibt eine Liste aller Inputs und Outputs zurueck, keine MEMs.
@return <class 'list'> Input und Output, keine MEMs"""
Bleibt Parameter 'export' auf None werden alle Inputs und Outputs
zurueckgegeben. Wird 'export' auf True/False gesetzt, werden nur Inputs
und Outputs zurueckgegeben, bei denen der Wert 'Export' in piCtory
uebereinstimmt.
@param export Nur In-/Outputs mit angegebenen 'Export' Wert in piCtory
@return <class 'list'> Input und Output, keine MEMs
"""
return list(self.__getioiter(
slice(self._slc_inpoff.start, self._slc_outoff.stop)
slice(self._slc_inpoff.start, self._slc_outoff.stop), export
))
def get_inputs(self):
def get_inputs(self, export=None):
"""Gibt eine Liste aller Inputs zurueck.
@return <class 'list'> Inputs"""
return list(self.__getioiter(self._slc_inpoff))
def get_outputs(self):
Bleibt Parameter 'export' auf None werden alle Inputs zurueckgegeben.
Wird 'export' auf True/False gesetzt, werden nur Inputs zurueckgegeben,
bei denen der Wert 'Export' in piCtory uebereinstimmt.
@param export Nur Inputs mit angegebenen 'Export' Wert in piCtory
@return <class 'list'> Inputs
"""
return list(self.__getioiter(self._slc_inpoff, export))
def get_outputs(self, export=None):
"""Gibt eine Liste aller Outputs zurueck.
@return <class 'list'> Outputs"""
return list(self.__getioiter(self._slc_outoff))
def get_memories(self):
"""Gibt eine Liste aller mems zurueck.
@return <class 'list'> Mems"""
return list(self.__getioiter(self._slc_memoff))
Bleibt Parameter 'export' auf None werden alle Outputs zurueckgegeben.
Wird 'export' auf True/False gesetzt, werden nur Outputs
zurueckgegeben, bei denen der Wert 'Export' in piCtory uebereinstimmt.
@param export Nur Outputs mit angegebenen 'Export' Wert in piCtory
@return <class 'list'> Outputs
"""
return list(self.__getioiter(self._slc_outoff, export))
def get_memories(self, export=None):
"""Gibt eine Liste aller Memoryobjekte zurueck.
Bleibt Parameter 'export' auf None werden alle Mems zurueckgegeben.
Wird 'export' auf True/False gesetzt, werden nur Mems zurueckgegeben,
bei denen der Wert 'Export' in piCtory uebereinstimmt.
@param export Nur Mems mit angegebenen 'Export' Wert in piCtory
@return <class 'list'> Mems
"""
return list(self.__getioiter(self._slc_memoff, export))
def readprocimg(self):
"""Alle Inputs fuer dieses Device vom Prozessabbild einlesen.
@@ -832,7 +869,7 @@ class Virtual(Gateway):
for io in self.get_inputs():
self._ba_devdata[io._slc_address] = io._defaultvalue
# Outpus auf Bus schreiben
# Outputs auf Bus schreiben
try:
self._modio._myfh.seek(self._slc_inpoff.start)
self._modio._myfh.write(self._ba_devdata[self._slc_inp])

View File

@@ -556,7 +556,6 @@ class ProcimgWriter(Thread):
def stop(self):
"""Beendet die automatische Prozessabbildsynchronisierung."""
self._collect_events(False)
self._work.set()
def set_maxioerrors(self, value):
@@ -570,13 +569,13 @@ class ProcimgWriter(Thread):
def set_refresh(self, value):
"""Setzt die Zykluszeit in Millisekunden.
@param value <class 'int'> Millisekunden"""
if type(value) == int and 10 <= value <= 2000:
if type(value) == int and 5 <= value <= 2000:
waitdiff = self._refresh - self._adjwait
self._refresh = value / 1000
self._adjwait = self._refresh - waitdiff
self._adjwait = 0 if waitdiff < 0 else self._refresh - waitdiff
else:
raise ValueError(
"refresh time must be 10 to 2000 milliseconds"
"refresh time must be 5 to 2000 milliseconds"
)
ioerrors = property(_get_ioerrors)

View File

@@ -254,7 +254,7 @@ class IOBase(object):
__slots__ = "_bitaddress", "_bitlength", "_byteorder", "_defaultvalue", \
"_iotype", "_length", "_name", "_parentdevice", \
"_signed", "_slc_address", "bmk"
"_signed", "_slc_address", "bmk", "export"
def __init__(self, parentdevice, valuelist, iotype, byteorder, signed):
"""Instantiierung der IOBase-Klasse.
@@ -268,7 +268,7 @@ class IOBase(object):
"""
# ["name","defval","bitlen","startaddrdev",exp,"idx","bmk","bitaddr"]
# [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 ]
# [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 ]
self._parentdevice = parentdevice
# Bitadressen auf Bytes aufbrechen und umrechnen
@@ -283,6 +283,7 @@ class IOBase(object):
self._name = valuelist[0]
self._signed = signed
self.bmk = valuelist[6]
self.export = bool(valuelist[4])
int_startaddress = int(valuelist[3])
if self._bitaddress == -1:

View File

@@ -6,10 +6,12 @@ __license__ = "LGPLv3"
import warnings
from json import load as jload
from multiprocessing import cpu_count
from os import access, F_OK, R_OK
from queue import Empty
from signal import signal, SIG_DFL, SIGINT, SIGTERM
from threading import Thread, Event
from timeit import default_timer
from . import app as appmodule
from . import device as devicemodule
@@ -224,6 +226,10 @@ class RevPiModIO(object):
# ImgWriter erstellen
self._imgwriter = helpermodule.ProcimgWriter(self)
# Refreshzeit CM1 25 Hz / CM3 50 Hz
if not isinstance(self, RevPiNetIO):
self._imgwriter.refresh = 20 if cpu_count() > 1 else 40
# Aktuellen Outputstatus von procimg einlesen
if self._syncoutputs:
self.syncoutputs()
@@ -349,7 +355,7 @@ class RevPiModIO(object):
self.io = None
self.summary = None
def cycleloop(self, func, cycletime=None):
def cycleloop(self, func, cycletime=50):
"""Startet den Cycleloop.
Der aktuelle Programmthread wird hier bis Aufruf von
@@ -361,19 +367,20 @@ class RevPiModIO(object):
Prozessabbild geschrieben.
Verlassen wird der Cycleloop, wenn die aufgerufene Funktion einen
Rueckgabewert nicht gleich None liefert, oder durch Aufruf von
revpimodio.exit().
Rueckgabewert nicht gleich None liefert (z.B. return True), oder durch
Aufruf von .exit().
HINWEIS: Die Aktualisierungszeit und die Laufzeit der Funktion duerfen
die eingestellte autorefresh Zeit, bzw. uebergebene cycletime nicht
ueberschreiten!
Ueber das Attribut cycletime kann die Aktualisierungsrate fuer das
Prozessabbild gesetzt werden.
Ueber den Parameter cycletime wird die gewuenschte Zukluszeit der
uebergebenen Funktion gesetzt. Der Standardwert betraegt
50 Millisekunden, in denen das Prozessabild eingelesen, die uebergebene
Funktion ausgefuert und das Prozessabbild geschrieben wird.
@param func Funktion, die ausgefuehrt werden soll
@param cycletime Zykluszeit in Millisekunden, bei Nichtangabe wird
aktuelle .cycletime Zeit verwendet - Standardwert 50 ms
@param cycletime Zykluszeit in Millisekunden - Standardwert 50 ms
@return None
"""
@@ -385,7 +392,10 @@ class RevPiModIO(object):
# Prüfen ob Devices in autorefresh sind
if len(self._lst_refresh) == 0:
raise RuntimeError("no device with autorefresh activated")
raise RuntimeError(
"no device with autorefresh activated - use autorefresh=True "
"or call .autorefresh_all() before entering cycleloop"
)
# Prüfen ob Funktion callable ist
if not callable(func):
@@ -394,7 +404,8 @@ class RevPiModIO(object):
)
# Zykluszeit übernehmen
if not (cycletime is None or cycletime == self._imgwriter.refresh):
old_cycletime = self._imgwriter.refresh
if not cycletime == self._imgwriter.refresh:
self._imgwriter.refresh = cycletime
# Zeitänderung in _imgwriter neuladen
@@ -439,6 +450,9 @@ class RevPiModIO(object):
# Cycleloop beenden
self._looprunning = False
# Alte autorefresh Zeit setzen
self._imgwriter.refresh = old_cycletime
return ec
def exit(self, full=True):
@@ -568,7 +582,10 @@ class RevPiModIO(object):
# Prüfen ob Devices in autorefresh sind
if len(self._lst_refresh) == 0:
raise RuntimeError("no device with autorefresh activated")
raise RuntimeError(
"no device with autorefresh activated - use autorefresh=True "
"or call .autorefresh_all() before entering mainloop"
)
# Thread erstellen, wenn nicht blockieren soll
if not blocking:
@@ -593,12 +610,33 @@ class RevPiModIO(object):
# ImgWriter mit Eventüberwachung aktivieren
self._imgwriter._collect_events(True)
e = None
runtime = 0
while not self._exit.is_set():
# Laufzeit der Eventqueue auf 0 setzen
if self._imgwriter._eventq.qsize() == 0:
runtime = 0
try:
tup_fire = self._imgwriter._eventq.get(timeout=1)
# Messung Laufzeit der Queue starten
if runtime == 0:
runtime = default_timer()
# Direct callen da Prüfung in io.IOBase.reg_event ist
tup_fire[0].func(tup_fire[1], tup_fire[2])
# Laufzeitprüfung
if runtime != -1 and \
default_timer() - runtime > self._imgwriter._refresh:
runtime = -1
warnings.warn(
"can not execute all event functions in one cycle - "
"rise .cycletime or optimize your event functions",
RuntimeWarning
)
except Empty:
if not self._exit.is_set() and not self._imgwriter.is_alive():
self.exit(full=False)
@@ -889,4 +927,4 @@ class RevPiModIODriver(RevPiModIOSelected):
# Nachträglicher Import
from .netio import RevPiNetIODriver
from .netio import RevPiNetIODriver, RevPiNetIO