From d28de43a7df05bfcb3e14291c166600eb1a535a6 Mon Sep 17 00:00:00 2001 From: NaruX Date: Sun, 14 Jul 2019 08:28:01 +0200 Subject: [PATCH] =?UTF-8?q?direct=5Foutput=20zu=20RevPiModIO=20hinzugef?= =?UTF-8?q?=C3=BCgt=20Outputs=20werden=20direkt=20in=20Processimage=20gesc?= =?UTF-8?q?hrieben=20Der=20Puffer=20wird=20nur=20durch=20g=C3=A4ngige=20Te?= =?UTF-8?q?chniken=20aktualisiert=20TODO:=20Umsetzung=20f=C3=BCr=20procimg?= =?UTF-8?q?=3Dfile=20fehlt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/revpimodio2.modio.html | 9 ++- eric-revpimodio2.api | 6 +- revpimodio2/helper.py | 2 +- revpimodio2/io.py | 129 ++++++++++++++++++++++++++----------- revpimodio2/modio.py | 41 ++++++++---- 5 files changed, 130 insertions(+), 57 deletions(-) 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 )