diff --git a/doc/revpimodio2.modio.html b/doc/revpimodio2.modio.html
index 2841f45..09665ce 100644
--- a/doc/revpimodio2.modio.html
+++ b/doc/revpimodio2.modio.html
@@ -164,7 +164,7 @@ Static Methods
RevPiModIO (Constructor)
-RevPiModIO(autorefresh=False, monitoring=False, syncoutputs=True, procimg=None, configrsc=None, simulator=False, debug=False, replace_io_file=None)
+RevPiModIO(autorefresh=False, monitoring=False, syncoutputs=True, procimg=None, configrsc=None, simulator=False, debug=False, replace_io_file=None, direct_output=False)
Instantiiert die Grundfunktionen.
@@ -192,6 +192,9 @@ Gibt bei allen Fehlern komplette Meldungen aus
- replace_io_file
-
Replace IO Konfiguration aus Datei laden
+
- direct_output
+-
+Write outputs immediately to process image (slow)
@@ -632,7 +635,7 @@ Static Methods
RevPiModIODriver (Constructor)
-RevPiModIODriver(virtdev, autorefresh=False, monitoring=False, syncoutputs=True, procimg=None, configrsc=None, debug=False, replace_io_file=None)
+RevPiModIODriver(virtdev, autorefresh=False, monitoring=False, syncoutputs=True, procimg=None, configrsc=None, debug=False, replace_io_file=None, direct_output=False)
Instantiiert die Grundfunktionen.
@@ -692,7 +695,7 @@ Static Methods
RevPiModIOSelected (Constructor)
-RevPiModIOSelected(deviceselection, autorefresh=False, monitoring=False, syncoutputs=True, procimg=None, configrsc=None, simulator=False, debug=False, replace_io_file=None)
+RevPiModIOSelected(deviceselection, autorefresh=False, monitoring=False, syncoutputs=True, procimg=None, configrsc=None, simulator=False, debug=False, replace_io_file=None, direct_output=False)
Instantiiert nur fuer angegebene Devices die Grundfunktionen.
diff --git a/eric-revpimodio2.api b/eric-revpimodio2.api
index 270362a..fcae3d2 100644
--- a/eric-revpimodio2.api
+++ b/eric-revpimodio2.api
@@ -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)
diff --git a/revpimodio2/helper.py b/revpimodio2/helper.py
index 37af3cb..1696312 100644
--- a/revpimodio2/helper.py
+++ b/revpimodio2/helper.py
@@ -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:
diff --git a/revpimodio2/io.py b/revpimodio2/io.py
index ce3ba20..9f01b42 100644
--- a/revpimodio2/io.py
+++ b/revpimodio2/io.py
@@ -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):
"""-Wert der Klasse.
@return 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 oder """
- 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 object of "
- "length {1}, but {2} was given".format(
- self._name, self._length, len(value)
- )
- )
- else:
- raise TypeError(
- "'{0}' requires a object, not {1}"
- "".format(self._name, type(value))
+ self._parentdevice._filelock.release()
+
+ else:
+ if type(value) != bytes:
+ raise TypeError(
+ "'{0}' requires a 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 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.
diff --git a/revpimodio2/modio.py b/revpimodio2/modio.py
index 589d297..4b850e5 100644
--- a/revpimodio2/modio.py
+++ b/revpimodio2/modio.py
@@ -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
)