direct_output zu RevPiModIO hinzugefügt

Outputs werden direkt in Processimage geschrieben
Der Puffer wird nur durch gängige Techniken aktualisiert
TODO: Umsetzung für procimg=file fehlt
This commit is contained in:
2019-07-14 08:28:01 +02:00
parent 56945d607e
commit d28de43a7d
5 changed files with 130 additions and 57 deletions

View File

@@ -164,7 +164,7 @@ Static Methods</h3>
<a NAME="RevPiModIO.__init__" ID="RevPiModIO.__init__"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiModIO (Constructor)</h3>
<b>RevPiModIO</b>(<i>autorefresh=False, monitoring=False, syncoutputs=True, procimg=None, configrsc=None, simulator=False, debug=False, replace_io_file=None</i>)
<b>RevPiModIO</b>(<i>autorefresh=False, monitoring=False, syncoutputs=True, procimg=None, configrsc=None, simulator=False, debug=False, replace_io_file=None, direct_output=False</i>)
<p>
Instantiiert die Grundfunktionen.
</p><dl>
@@ -192,6 +192,9 @@ Gibt bei allen Fehlern komplette Meldungen aus
</dd><dt><i>replace_io_file</i></dt>
<dd>
Replace IO Konfiguration aus Datei laden
</dd><dt><i>direct_output</i></dt>
<dd>
Write outputs immediately to process image (slow)
</dd>
</dl><a NAME="RevPiModIO.__del__" ID="RevPiModIO.__del__"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
@@ -632,7 +635,7 @@ Static Methods</h3>
<a NAME="RevPiModIODriver.__init__" ID="RevPiModIODriver.__init__"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiModIODriver (Constructor)</h3>
<b>RevPiModIODriver</b>(<i>virtdev, autorefresh=False, monitoring=False, syncoutputs=True, procimg=None, configrsc=None, debug=False, replace_io_file=None</i>)
<b>RevPiModIODriver</b>(<i>virtdev, autorefresh=False, monitoring=False, syncoutputs=True, procimg=None, configrsc=None, debug=False, replace_io_file=None, direct_output=False</i>)
<p>
Instantiiert die Grundfunktionen.
</p><p>
@@ -692,7 +695,7 @@ Static Methods</h3>
<a NAME="RevPiModIOSelected.__init__" ID="RevPiModIOSelected.__init__"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiModIOSelected (Constructor)</h3>
<b>RevPiModIOSelected</b>(<i>deviceselection, autorefresh=False, monitoring=False, syncoutputs=True, procimg=None, configrsc=None, simulator=False, debug=False, replace_io_file=None</i>)
<b>RevPiModIOSelected</b>(<i>deviceselection, autorefresh=False, monitoring=False, syncoutputs=True, procimg=None, configrsc=None, simulator=False, debug=False, replace_io_file=None, direct_output=False</i>)
<p>
Instantiiert nur fuer angegebene Devices die Grundfunktionen.
</p><p>

View File

@@ -175,9 +175,9 @@ revpimodio2.modio.RevPiModIO.setdefaultvalues?4(device=None)
revpimodio2.modio.RevPiModIO.simulator?7
revpimodio2.modio.RevPiModIO.syncoutputs?4(device=None)
revpimodio2.modio.RevPiModIO.writeprocimg?4(device=None)
revpimodio2.modio.RevPiModIO?1(autorefresh=False, monitoring=False, syncoutputs=True, procimg=None, configrsc=None, simulator=False, debug=False, replace_io_file=None)
revpimodio2.modio.RevPiModIODriver?1(virtdev, autorefresh=False, monitoring=False, syncoutputs=True, procimg=None, configrsc=None, debug=False, replace_io_file=None)
revpimodio2.modio.RevPiModIOSelected?1(deviceselection, autorefresh=False, monitoring=False, syncoutputs=True, procimg=None, configrsc=None, simulator=False, debug=False, replace_io_file=None)
revpimodio2.modio.RevPiModIO?1(autorefresh=False, monitoring=False, syncoutputs=True, procimg=None, configrsc=None, simulator=False, debug=False, replace_io_file=None, direct_output=False)
revpimodio2.modio.RevPiModIODriver?1(virtdev, autorefresh=False, monitoring=False, syncoutputs=True, procimg=None, configrsc=None, debug=False, replace_io_file=None, direct_output=False)
revpimodio2.modio.RevPiModIOSelected?1(deviceselection, autorefresh=False, monitoring=False, syncoutputs=True, procimg=None, configrsc=None, simulator=False, debug=False, replace_io_file=None, direct_output=False)
revpimodio2.netio.NetFH._connect?5()
revpimodio2.netio.NetFH._direct_send?5(send_bytes, recv_count)
revpimodio2.netio.NetFH.clear_dirtybytes?4(position=None)

View File

@@ -481,7 +481,7 @@ class ProcimgWriter(Thread):
fh.seek(0)
bytesbuff = bytearray(fh.read(self._modio._length))
if self._modio._monitoring:
if self._modio._monitoring or self._modio._direct_output:
# Inputs und Outputs in Puffer
for dev in self._modio._lst_refresh:
with dev._filelock:

View File

@@ -8,7 +8,7 @@ import struct
import warnings
from re import match as rematch
from threading import Event
from revpimodio2 import RISING, FALLING, BOTH, INP, OUT, MEM, consttostr
from revpimodio2 import RISING, FALLING, BOTH, INP, MEM, consttostr
from .netio import RevPiNetIO
try:
# Funktioniert nur auf Unix
@@ -259,7 +259,8 @@ class IOBase(object):
"""
__slots__ = "_bitaddress", "_bitlength", "_byteorder", "_defaultvalue", \
__slots__ = "__bit_ioctl_off", "__bit_ioctl_on", \
"_bitaddress", "_bitlength", "_byteorder", "_defaultvalue", \
"_iotype", "_length", "_name", "_parentdevice", \
"_signed", "_slc_address", "bmk", "export"
@@ -285,6 +286,8 @@ class IOBase(object):
self._bitlength = int(valuelist[2])
self._length = 1 if self._bitaddress == 0 else int(self._bitlength / 8)
self.__bit_ioctl_off = None
self.__bit_ioctl_on = None
self._byteorder = byteorder
self._iotype = iotype
self._name = valuelist[0]
@@ -345,6 +348,12 @@ class IOBase(object):
except Exception:
self._defaultvalue = False
# Ioctl für Bitsetzung setzen
self.__bit_ioctl_off = \
self._get_address().to_bytes(2, "little") \
+ self._bitaddress.to_bytes(1, "little")
self.__bit_ioctl_on = self.__bit_ioctl_off + b'\x01'
def __bool__(self):
"""<class 'bool'>-Wert der Klasse.
@return <class 'bool'> Nur False wenn False oder 0 sonst True"""
@@ -506,10 +515,60 @@ class IOBase(object):
def set_value(self, value):
"""Setzt den Wert des IOs.
@param value IO-Wert als <class bytes'> oder <class 'bool'>"""
if self._iotype == OUT:
if self._bitaddress >= 0:
# Versuchen egal welchen Typ in Bool zu konvertieren
value = bool(value)
if self._iotype == INP:
if self._parentdevice._modio._simulator:
raise RuntimeError(
"can not write to output '{0}' in simulator mode"
"".format(self._name)
)
else:
raise RuntimeError(
"can not write to input '{0}'".format(self._name)
)
if self._iotype == MEM:
raise RuntimeError(
"can not write to memory '{0}'".format(self._name)
)
if self._bitaddress >= 0:
# Versuchen egal welchen Typ in Bool zu konvertieren
value = bool(value)
if self._parentdevice._modio._direct_output:
# Direktes Schreiben der Outputs
# TODO: Abfragen minimieren für Schreiben der Outputs
if isinstance(self._parentdevice._modio, RevPiNetIO):
# IOCTL über Netzwerk
with self._parentdevice._modio._myfh_lck:
try:
self._parentdevice._modio._myfh.ioctl(
19216,
self.__bit_ioctl_on if value
else self.__bit_ioctl_off
)
except Exception as e:
self._parentdevice._modio._gotioerror(
"net_ioctl", e)
else:
# IOCTL auf dem RevPi
with self._parentdevice._modio._myfh_lck:
try:
# Set value durchführen (Funktion K+16)
ioctl(
self._parentdevice._modio._myfh,
19216,
self.__bit_ioctl_on if value
else self.__bit_ioctl_off
)
except Exception as e:
self._parentdevice._modio._gotioerror("ioset", e)
else:
# Gepuffertes Schreiben der Outputs
# Für Bitoperationen sperren
self._parentdevice._filelock.acquire()
# ganzes Byte laden
byte_buff = self._parentdevice._ba_devdata[self._slc_address]
@@ -530,39 +589,37 @@ class IOBase(object):
self._parentdevice._ba_devdata[self._slc_address] = \
int_byte.to_bytes(int_len, byteorder=self._byteorder)
else:
if type(value) == bytes:
if self._length == len(value):
self._parentdevice._ba_devdata[self._slc_address] = \
value
else:
raise ValueError(
"'{0}' requires a <class 'bytes'> object of "
"length {1}, but {2} was given".format(
self._name, self._length, len(value)
)
)
else:
raise TypeError(
"'{0}' requires a <class 'bytes'> object, not {1}"
"".format(self._name, type(value))
self._parentdevice._filelock.release()
else:
if type(value) != bytes:
raise TypeError(
"'{0}' requires a <class 'bytes'> object, not {1}".format(
self._name, type(value)
)
elif self._iotype == INP:
if self._parentdevice._modio._simulator:
raise RuntimeError(
"can not write to output '{0}' in simulator mode"
"".format(self._name)
)
if self._length != len(value):
raise ValueError(
"'{0}' requires a <class 'bytes'> object of "
"length {1}, but {2} was given".format(
self._name, self._length, len(value)
)
)
if self._parentdevice._modio._direct_output:
with self._parentdevice._modio._myfh_lck:
try:
self._parentdevice._modio._myfh.seek(
self._get_address()
)
self._parentdevice._modio._myfh.write(value)
if self._parentdevice._modio._buffedwrite:
self._parentdevice._modio._myfh.flush()
except IOError as e:
self._parentdevice._modio._gotioerror("ioset", e)
else:
raise RuntimeError(
"can not write to input '{0}'".format(self._name)
)
elif self._iotype == MEM:
raise RuntimeError(
"can not write to memory '{0}'".format(self._name)
)
self._parentdevice._ba_devdata[self._slc_address] = value
def unreg_event(self, func=None, edge=None):
"""Entfernt ein Event aus der Eventueberwachung.

View File

@@ -30,17 +30,17 @@ class RevPiModIO(object):
"""
__slots__ = "__cleanupfunc", "_autorefresh", "_buffedwrite", \
"_configrsc", "_exit", "_imgwriter", "_ioerror", "_length", \
"_looprunning", "_lst_devselect", "_lst_refresh", "_maxioerrors", \
"_myfh", "_myfh_lck", "_monitoring", "_procimg", "_simulator", \
"_syncoutputs", "_th_mainloop", "_waitexit", \
"_configrsc", "_direct_output", "_exit", "_imgwriter", "_ioerror", \
"_length", "_looprunning", "_lst_devselect", "_lst_refresh", \
"_maxioerrors", "_myfh", "_myfh_lck", "_monitoring", "_procimg", \
"_simulator", "_syncoutputs", "_th_mainloop", "_waitexit", \
"core", "app", "device", "exitsignal", "io", "summary", "_debug", \
"_lck_replace_io", "_replace_io_file"
def __init__(
self, autorefresh=False, monitoring=False, syncoutputs=True,
procimg=None, configrsc=None, simulator=False, debug=False,
replace_io_file=None):
replace_io_file=None, direct_output=False):
"""Instantiiert die Grundfunktionen.
@param autorefresh Wenn True, alle Devices zu autorefresh hinzufuegen
@@ -51,12 +51,14 @@ class RevPiModIO(object):
@param simulator Laedt das Modul als Simulator und vertauscht IOs
@param debug Gibt bei allen Fehlern komplette Meldungen aus
@param replace_io_file Replace IO Konfiguration aus Datei laden
@param direct_output Write outputs immediately to process image (slow)
"""
# Parameterprüfung
acheck(
bool, autorefresh=autorefresh, monitoring=monitoring,
syncoutputs=syncoutputs, simulator=simulator, debug=debug
syncoutputs=syncoutputs, simulator=simulator, debug=debug,
direct_output=direct_output
)
acheck(
str, procimg_noneok=procimg, configrsc_noneok=configrsc,
@@ -65,6 +67,7 @@ class RevPiModIO(object):
self._autorefresh = autorefresh
self._configrsc = configrsc
self._direct_output = direct_output
self._monitoring = monitoring
self._procimg = "/dev/piControl0" if procimg is None else procimg
self._simulator = simulator
@@ -103,6 +106,13 @@ class RevPiModIO(object):
# Event für Benutzeraktionen
self.exitsignal = Event()
if self._direct_output and not \
(self._procimg == "/dev/piControl0" or
isinstance(self, RevPiNetIO)):
raise RuntimeError(
"use direct_output with piControl0 or RevPiNetIO only"
)
# Nur Konfigurieren, wenn nicht vererbt
if type(self) == RevPiModIO:
self._configure(self.get_jconfigrsc())
@@ -368,9 +378,7 @@ class RevPiModIO(object):
except Exception as e:
raise RuntimeError(
"replace_io_file: can not replace '{0}' with '{1}' "
"| RevPiModIO message: {2}".format(
parentio, io, e
)
"| RevPiModIO message: {2}".format(parentio, io, e)
)
def _create_myfh(self):
@@ -854,7 +862,7 @@ class RevPiModIO(object):
# FileHandler sperren
dev._filelock.acquire()
if self._monitoring:
if self._monitoring or self._direct_output:
# Alles vom Bus einlesen
dev._ba_devdata[:] = bytesbuff[dev._slc_devoff]
else:
@@ -942,6 +950,10 @@ class RevPiModIO(object):
@return True, wenn Arbeiten an allen Devices erfolgreich waren
"""
if self._direct_output:
# TODO: Wie soll das bei direct_output umgesetzt werden?
return True
if self._monitoring:
raise RuntimeError(
"can not write process image, while system is in monitoring "
@@ -1018,7 +1030,8 @@ class RevPiModIOSelected(RevPiModIO):
def __init__(
self, deviceselection, autorefresh=False, monitoring=False,
syncoutputs=True, procimg=None, configrsc=None,
simulator=False, debug=False, replace_io_file=None):
simulator=False, debug=False, replace_io_file=None,
direct_output=False):
"""Instantiiert nur fuer angegebene Devices die Grundfunktionen.
Der Parameter deviceselection kann eine einzelne
@@ -1031,7 +1044,7 @@ class RevPiModIOSelected(RevPiModIO):
"""
super().__init__(
autorefresh, monitoring, syncoutputs, procimg, configrsc,
simulator, debug, replace_io_file
simulator, debug, replace_io_file, direct_output
)
# Device liste erstellen
@@ -1086,7 +1099,7 @@ class RevPiModIODriver(RevPiModIOSelected):
def __init__(
self, virtdev, autorefresh=False, monitoring=False,
syncoutputs=True, procimg=None, configrsc=None, debug=False,
replace_io_file=None):
replace_io_file=None, direct_output=False):
"""Instantiiert die Grundfunktionen.
Parameter 'monitoring' und 'simulator' stehen hier nicht zur
@@ -1099,7 +1112,7 @@ class RevPiModIODriver(RevPiModIOSelected):
# Parent mit monitoring=False und simulator=True laden
super().__init__(
virtdev, autorefresh, False, syncoutputs, procimg, configrsc,
True, debug, replace_io_file
True, debug, replace_io_file, direct_output
)