diff --git a/doc/revpimodio2.modio.html b/doc/revpimodio2.modio.html index 09665ce..69dfa04 100644 --- a/doc/revpimodio2.modio.html +++ b/doc/revpimodio2.modio.html @@ -116,6 +116,9 @@ Methods _set_maxioerrors Setzt Anzahl der maximal erlaubten Fehler bei Prozessabbildzugriff. +_simulate_ioctl +Simuliert IOCTL Funktionen auf procimg Datei. + autorefresh_all Setzt alle Devices in autorefresh Funktion. @@ -365,6 +368,20 @@ Setzt Anzahl der maximal erlaubten Fehler bei Prozessabbildzugriff.
Anzahl erlaubte Fehler
+ +

+RevPiModIO._simulate_ioctl

+_simulate_ioctl(request, arg=b'') +

+Simuliert IOCTL Funktionen auf procimg Datei. +

+
request
+
+IO Request +
arg:
+
+Request argument +

RevPiModIO.autorefresh_all

diff --git a/doc/revpimodio2.netio.html b/doc/revpimodio2.netio.html index 4c614a8..48b8224 100644 --- a/doc/revpimodio2.netio.html +++ b/doc/revpimodio2.netio.html @@ -423,7 +423,7 @@ Static Methods

RevPiNetIO (Constructor)

-RevPiNetIO(address, autorefresh=False, monitoring=False, syncoutputs=True, simulator=False, debug=False, replace_io_file=None) +RevPiNetIO(address, autorefresh=False, monitoring=False, syncoutputs=True, simulator=False, debug=False, replace_io_file=None, direct_output=False)

Instantiiert die Grundfunktionen.

@@ -448,6 +448,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)

@@ -539,7 +542,7 @@ Static Methods

RevPiNetIODriver (Constructor)

-RevPiNetIODriver(address, virtdev, autorefresh=False, monitoring=False, syncoutputs=True, debug=False, replace_io_file=None) +RevPiNetIODriver(address, virtdev, autorefresh=False, monitoring=False, syncoutputs=True, debug=False, replace_io_file=None, direct_output=False)

Instantiiert die Grundfunktionen.

@@ -602,7 +605,7 @@ Static Methods

RevPiNetIOSelected (Constructor)

-RevPiNetIOSelected(address, deviceselection, autorefresh=False, monitoring=False, syncoutputs=True, simulator=False, debug=False, replace_io_file=None) +RevPiNetIOSelected(address, deviceselection, autorefresh=False, monitoring=False, syncoutputs=True, 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 fcae3d2..a088155 100644 --- a/eric-revpimodio2.api +++ b/eric-revpimodio2.api @@ -154,6 +154,7 @@ revpimodio2.modio.RevPiModIO._get_simulator?5() revpimodio2.modio.RevPiModIO._gotioerror?5(action, e=None) revpimodio2.modio.RevPiModIO._set_cycletime?5(milliseconds) revpimodio2.modio.RevPiModIO._set_maxioerrors?5(value) +revpimodio2.modio.RevPiModIO._simulate_ioctl?5(request, arg=b'') revpimodio2.modio.RevPiModIO.autorefresh_all?4() revpimodio2.modio.RevPiModIO.cleanup?4() revpimodio2.modio.RevPiModIO.configrsc?7 @@ -204,9 +205,9 @@ revpimodio2.netio.RevPiNetIO.disconnect?4() revpimodio2.netio.RevPiNetIO.get_jconfigrsc?4() revpimodio2.netio.RevPiNetIO.net_cleardefaultvalues?4(device=None) revpimodio2.netio.RevPiNetIO.net_setdefaultvalues?4(device=None) -revpimodio2.netio.RevPiNetIO?1(address, autorefresh=False, monitoring=False, syncoutputs=True, simulator=False, debug=False, replace_io_file=None) -revpimodio2.netio.RevPiNetIODriver?1(address, virtdev, autorefresh=False, monitoring=False, syncoutputs=True, debug=False, replace_io_file=None) -revpimodio2.netio.RevPiNetIOSelected?1(address, deviceselection, autorefresh=False, monitoring=False, syncoutputs=True, simulator=False, debug=False, replace_io_file=None) +revpimodio2.netio.RevPiNetIO?1(address, autorefresh=False, monitoring=False, syncoutputs=True, simulator=False, debug=False, replace_io_file=None, direct_output=False) +revpimodio2.netio.RevPiNetIODriver?1(address, virtdev, autorefresh=False, monitoring=False, syncoutputs=True, debug=False, replace_io_file=None, direct_output=False) +revpimodio2.netio.RevPiNetIOSelected?1(address, deviceselection, autorefresh=False, monitoring=False, syncoutputs=True, simulator=False, debug=False, replace_io_file=None, direct_output=False) revpimodio2.netio._sysdeldirty?8 revpimodio2.netio._sysexit?8 revpimodio2.netio._sysflush?8 diff --git a/revpimodio2/io.py b/revpimodio2/io.py index 9f01b42..9829185 100644 --- a/revpimodio2/io.py +++ b/revpimodio2/io.py @@ -5,11 +5,9 @@ __copyright__ = "Copyright (C) 2018 Sven Sager" __license__ = "LGPLv3" import struct -import warnings from re import match as rematch from threading import Event from revpimodio2 import RISING, FALLING, BOTH, INP, MEM, consttostr -from .netio import RevPiNetIO try: # Funktioniert nur auf Unix from fcntl import ioctl @@ -536,21 +534,8 @@ class IOBase(object): 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: + if self._parentdevice._modio._run_on_pi: # IOCTL auf dem RevPi with self._parentdevice._modio._myfh_lck: try: @@ -564,6 +549,31 @@ class IOBase(object): except Exception as e: self._parentdevice._modio._gotioerror("ioset", e) + elif hasattr(self._parentdevice._modio._myfh, "ioctl"): + # 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_ioset", e) + + else: + # IOCTL in Datei simulieren + try: + # Set value durchführen (Funktion K+16) + self._parentdevice._modio._simulate_ioctl( + 19216, + self.__bit_ioctl_on if value + else self.__bit_ioctl_off + ) + except Exception as e: + self._parentdevice._modio._gotioerror("file_ioset", e) + else: # Gepuffertes Schreiben der Outputs @@ -901,24 +911,7 @@ class IntIOCounter(IntIO): "can not reset counter, while system is in simulator mode" ) - if isinstance(self._parentdevice._modio, RevPiNetIO): - # IOCTL über Netzwerk - with self._parentdevice._modio._myfh_lck: - try: - self._parentdevice._modio._myfh.ioctl( - 19220, self.__ioctl_arg - ) - except Exception as e: - self._parentdevice._modio._gotioerror("net_ioctl", e) - - elif self._parentdevice._modio._procimg != "/dev/piControl0": - # NOTE: Soll hier eine 0 in den Input geschrieben werden? - warnings.warn( - "this will work on a revolution pi only", - RuntimeWarning - ) - - else: + if self._parentdevice._modio._run_on_pi: # IOCTL auf dem RevPi with self._parentdevice._modio._myfh_lck: try: @@ -928,7 +921,27 @@ class IntIOCounter(IntIO): 19220, self.__ioctl_arg ) except Exception as e: - self._parentdevice._modio._gotioerror("ioctl", e) + self._parentdevice._modio._gotioerror("iorst", e) + + elif hasattr(self._parentdevice._modio._myfh, "ioctl"): + # IOCTL über Netzwerk + with self._parentdevice._modio._myfh_lck: + try: + self._parentdevice._modio._myfh.ioctl( + 19220, self.__ioctl_arg + ) + except Exception as e: + self._parentdevice._modio._gotioerror("net_iorst", e) + + else: + # IOCTL in Datei simulieren + try: + # Set value durchführen (Funktion K+20) + self._parentdevice._modio._simulate_ioctl( + 19220, self.__ioctl_arg + ) + except Exception as e: + self._parentdevice._modio._gotioerror("file_iorst", e) class IntIOReplaceable(IntIO): diff --git a/revpimodio2/modio.py b/revpimodio2/modio.py index 4b850e5..3ddbe77 100644 --- a/revpimodio2/modio.py +++ b/revpimodio2/modio.py @@ -9,9 +9,11 @@ from configparser import ConfigParser from json import load as jload from multiprocessing import cpu_count from os import access, F_OK, R_OK +from os import stat as osstat from queue import Empty from revpimodio2 import acheck from signal import signal, SIG_DFL, SIGINT, SIGTERM +from stat import S_ISCHR from threading import Thread, Event, Lock from timeit import default_timer @@ -35,7 +37,7 @@ class RevPiModIO(object): "_maxioerrors", "_myfh", "_myfh_lck", "_monitoring", "_procimg", \ "_simulator", "_syncoutputs", "_th_mainloop", "_waitexit", \ "core", "app", "device", "exitsignal", "io", "summary", "_debug", \ - "_lck_replace_io", "_replace_io_file" + "_lck_replace_io", "_replace_io_file", "_run_on_pi" def __init__( self, autorefresh=False, monitoring=False, syncoutputs=True, @@ -106,12 +108,10 @@ 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" - ) + try: + self._run_on_pi = S_ISCHR(osstat(self._procimg).st_mode) + except Exception: + self._run_on_pi = False # Nur Konfigurieren, wenn nicht vererbt if type(self) == RevPiModIO: @@ -471,6 +471,57 @@ class RevPiModIO(object): else: raise ValueError("value must be 0 or a positive integer") + def _simulate_ioctl(self, request, arg=b''): + """Simuliert IOCTL Funktionen auf procimg Datei. + @param request IO Request + @param arg: Request argument""" + if request == 19216: + # Einzelnes Bit setzen + byte_address = int.from_bytes(arg[:2], byteorder="little") + bit_address = arg[2] + new_value = bool(0 if len(arg) <= 3 else arg[3]) + + # Simulatonsmodus schreibt direkt in Datei + with self._myfh_lck: + self._myfh.seek(byte_address) + int_byte = int.from_bytes( + self._myfh.read(1), byteorder="little" + ) + int_bit = 1 << bit_address + + if not bool(int_byte & int_bit) == new_value: + if new_value: + int_byte += int_bit + else: + int_byte -= int_bit + + self._myfh.seek(byte_address) + self._myfh.write(int_byte.to_bytes(1, byteorder="little")) + if self._buffedwrite: + self._myfh.flush() + + elif request == 19220: + # FIXME: Implement + # Counterwert auf 0 setzen + dev_position = arg[0] + bit_field = int.from_bytes(arg[2:], byteorder="little") + io_byte = -1 + + for i in range(16): + if bool(bit_field & 1 << i): + io_byte = self.device[dev_position].offset \ + + int(self.device[dev_position]._lst_counter[i]) + break + + if io_byte == -1: + raise RuntimeError("count not reset counter io in file") + + with self._myfh_lck: + self._myfh.seek(io_byte) + self._myfh.write(b'\x00\x00\x00\x00') + if self._buffedwrite: + self._myfh.flush() + def autorefresh_all(self): """Setzt alle Devices in autorefresh Funktion.""" for dev in self.device: @@ -951,7 +1002,6 @@ class RevPiModIO(object): """ if self._direct_output: - # TODO: Wie soll das bei direct_output umgesetzt werden? return True if self._monitoring: diff --git a/revpimodio2/netio.py b/revpimodio2/netio.py index d8c899f..97cd5b4 100644 --- a/revpimodio2/netio.py +++ b/revpimodio2/netio.py @@ -490,7 +490,7 @@ class RevPiNetIO(_RevPiModIO): def __init__( self, address, autorefresh=False, monitoring=False, syncoutputs=True, simulator=False, debug=False, - replace_io_file=None): + replace_io_file=None, direct_output=False): """Instantiiert die Grundfunktionen. @param address: IP-Adresse / (IP, Port) @@ -500,6 +500,7 @@ class RevPiNetIO(_RevPiModIO): @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) """ check_ip = compile( @@ -549,7 +550,8 @@ class RevPiNetIO(_RevPiModIO): None, simulator, debug, - replace_io_file + replace_io_file, + direct_output ) # Netzwerkfilehandler anlegen @@ -661,7 +663,7 @@ class RevPiNetIOSelected(RevPiNetIO): def __init__( self, address, deviceselection, autorefresh=False, monitoring=False, syncoutputs=True, simulator=False, debug=False, - replace_io_file=None): + replace_io_file=None, direct_output=False): """Instantiiert nur fuer angegebene Devices die Grundfunktionen. Der Parameter deviceselection kann eine einzelne @@ -675,7 +677,7 @@ class RevPiNetIOSelected(RevPiNetIO): """ super().__init__( address, autorefresh, monitoring, syncoutputs, simulator, debug, - replace_io_file + replace_io_file, direct_output ) # Device liste erstellen @@ -729,7 +731,8 @@ class RevPiNetIODriver(RevPiNetIOSelected): def __init__( self, address, virtdev, autorefresh=False, monitoring=False, - syncoutputs=True, debug=False, replace_io_file=None): + syncoutputs=True, debug=False, replace_io_file=None, + direct_output=False): """Instantiiert die Grundfunktionen. Parameter 'monitoring' und 'simulator' stehen hier nicht zur @@ -743,5 +746,5 @@ class RevPiNetIODriver(RevPiNetIOSelected): # Parent mit monitoring=False und simulator=True laden super().__init__( address, virtdev, autorefresh, False, syncoutputs, True, debug, - replace_io_file + replace_io_file, direct_output )