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

View File

@@ -175,9 +175,9 @@ revpimodio2.modio.RevPiModIO.setdefaultvalues?4(device=None)
revpimodio2.modio.RevPiModIO.simulator?7 revpimodio2.modio.RevPiModIO.simulator?7
revpimodio2.modio.RevPiModIO.syncoutputs?4(device=None) revpimodio2.modio.RevPiModIO.syncoutputs?4(device=None)
revpimodio2.modio.RevPiModIO.writeprocimg?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.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) 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) 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._connect?5()
revpimodio2.netio.NetFH._direct_send?5(send_bytes, recv_count) revpimodio2.netio.NetFH._direct_send?5(send_bytes, recv_count)
revpimodio2.netio.NetFH.clear_dirtybytes?4(position=None) revpimodio2.netio.NetFH.clear_dirtybytes?4(position=None)

View File

@@ -481,7 +481,7 @@ class ProcimgWriter(Thread):
fh.seek(0) fh.seek(0)
bytesbuff = bytearray(fh.read(self._modio._length)) 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 # Inputs und Outputs in Puffer
for dev in self._modio._lst_refresh: for dev in self._modio._lst_refresh:
with dev._filelock: with dev._filelock:

View File

@@ -8,7 +8,7 @@ import struct
import warnings import warnings
from re import match as rematch from re import match as rematch
from threading import Event 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 from .netio import RevPiNetIO
try: try:
# Funktioniert nur auf Unix # 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", \ "_iotype", "_length", "_name", "_parentdevice", \
"_signed", "_slc_address", "bmk", "export" "_signed", "_slc_address", "bmk", "export"
@@ -285,6 +286,8 @@ class IOBase(object):
self._bitlength = int(valuelist[2]) self._bitlength = int(valuelist[2])
self._length = 1 if self._bitaddress == 0 else int(self._bitlength / 8) 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._byteorder = byteorder
self._iotype = iotype self._iotype = iotype
self._name = valuelist[0] self._name = valuelist[0]
@@ -345,6 +348,12 @@ class IOBase(object):
except Exception: except Exception:
self._defaultvalue = False 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): def __bool__(self):
"""<class 'bool'>-Wert der Klasse. """<class 'bool'>-Wert der Klasse.
@return <class 'bool'> Nur False wenn False oder 0 sonst True""" @return <class 'bool'> Nur False wenn False oder 0 sonst True"""
@@ -506,10 +515,60 @@ class IOBase(object):
def set_value(self, value): def set_value(self, value):
"""Setzt den Wert des IOs. """Setzt den Wert des IOs.
@param value IO-Wert als <class bytes'> oder <class 'bool'>""" @param value IO-Wert als <class bytes'> oder <class 'bool'>"""
if self._iotype == OUT: if self._iotype == INP:
if self._bitaddress >= 0: if self._parentdevice._modio._simulator:
# Versuchen egal welchen Typ in Bool zu konvertieren raise RuntimeError(
value = bool(value) "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 # ganzes Byte laden
byte_buff = self._parentdevice._ba_devdata[self._slc_address] byte_buff = self._parentdevice._ba_devdata[self._slc_address]
@@ -530,39 +589,37 @@ class IOBase(object):
self._parentdevice._ba_devdata[self._slc_address] = \ self._parentdevice._ba_devdata[self._slc_address] = \
int_byte.to_bytes(int_len, byteorder=self._byteorder) int_byte.to_bytes(int_len, byteorder=self._byteorder)
else: self._parentdevice._filelock.release()
if type(value) == bytes:
if self._length == len(value): else:
self._parentdevice._ba_devdata[self._slc_address] = \ if type(value) != bytes:
value raise TypeError(
else: "'{0}' requires a <class 'bytes'> object, not {1}".format(
raise ValueError( self._name, type(value)
"'{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))
) )
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: else:
raise RuntimeError( self._parentdevice._ba_devdata[self._slc_address] = value
"can not write to input '{0}'".format(self._name)
)
elif self._iotype == MEM:
raise RuntimeError(
"can not write to memory '{0}'".format(self._name)
)
def unreg_event(self, func=None, edge=None): def unreg_event(self, func=None, edge=None):
"""Entfernt ein Event aus der Eventueberwachung. """Entfernt ein Event aus der Eventueberwachung.

View File

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