diff --git a/.idea/dictionaries/akira.xml b/.idea/dictionaries/akira.xml new file mode 100644 index 0000000..19f244e --- /dev/null +++ b/.idea/dictionaries/akira.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml index 105ce2d..dd4c951 100644 --- a/.idea/inspectionProfiles/profiles_settings.xml +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -1,5 +1,6 @@ + diff --git a/.idea/revpimodio2.iml b/.idea/revpimodio2.iml index c8efcbb..779b2fa 100644 --- a/.idea/revpimodio2.iml +++ b/.idea/revpimodio2.iml @@ -1,7 +1,9 @@ - + + + diff --git a/docs/revpimodio2.app.rst b/docs/revpimodio2.app.rst new file mode 100644 index 0000000..e588c23 --- /dev/null +++ b/docs/revpimodio2.app.rst @@ -0,0 +1,7 @@ +revpimodio2\.app module +======================= + +.. automodule:: revpimodio2.app + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/revpimodio2.device.rst b/docs/revpimodio2.device.rst new file mode 100644 index 0000000..3f1fc70 --- /dev/null +++ b/docs/revpimodio2.device.rst @@ -0,0 +1,7 @@ +revpimodio2\.device module +========================== + +.. automodule:: revpimodio2.device + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/revpimodio2.helper.rst b/docs/revpimodio2.helper.rst new file mode 100644 index 0000000..f82992a --- /dev/null +++ b/docs/revpimodio2.helper.rst @@ -0,0 +1,7 @@ +revpimodio2\.helper module +========================== + +.. automodule:: revpimodio2.helper + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/revpimodio2.io.rst b/docs/revpimodio2.io.rst new file mode 100644 index 0000000..95d9f95 --- /dev/null +++ b/docs/revpimodio2.io.rst @@ -0,0 +1,7 @@ +revpimodio2\.io module +====================== + +.. automodule:: revpimodio2.io + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/revpimodio2.modio.rst b/docs/revpimodio2.modio.rst new file mode 100644 index 0000000..8fa4c5d --- /dev/null +++ b/docs/revpimodio2.modio.rst @@ -0,0 +1,7 @@ +revpimodio2\.modio module +========================= + +.. automodule:: revpimodio2.modio + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/revpimodio2.netio.rst b/docs/revpimodio2.netio.rst new file mode 100644 index 0000000..175acb0 --- /dev/null +++ b/docs/revpimodio2.netio.rst @@ -0,0 +1,7 @@ +revpimodio2\.netio module +========================= + +.. automodule:: revpimodio2.netio + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/revpimodio2.rst b/docs/revpimodio2.rst index 6668bf0..a5c890a 100644 --- a/docs/revpimodio2.rst +++ b/docs/revpimodio2.rst @@ -4,62 +4,15 @@ revpimodio2 package Submodules ---------- -revpimodio2\.app module ------------------------ - -.. automodule:: revpimodio2.app - :members: - :undoc-members: - :show-inheritance: - -revpimodio2\.device module --------------------------- - -.. automodule:: revpimodio2.device - :members: - :undoc-members: - :show-inheritance: - -revpimodio2\.helper module --------------------------- - -.. automodule:: revpimodio2.helper - :members: - :undoc-members: - :show-inheritance: - -revpimodio2\.io module ----------------------- - -.. automodule:: revpimodio2.io - :members: - :undoc-members: - :show-inheritance: - -revpimodio2\.modio module -------------------------- - -.. automodule:: revpimodio2.modio - :members: - :undoc-members: - :show-inheritance: - -revpimodio2\.netio module -------------------------- - -.. automodule:: revpimodio2.netio - :members: - :undoc-members: - :show-inheritance: - -revpimodio2\.summary module ---------------------------- - -.. automodule:: revpimodio2.summary - :members: - :undoc-members: - :show-inheritance: +.. toctree:: + revpimodio2.app + revpimodio2.device + revpimodio2.helper + revpimodio2.io + revpimodio2.modio + revpimodio2.netio + revpimodio2.summary Module contents --------------- diff --git a/docs/revpimodio2.summary.rst b/docs/revpimodio2.summary.rst new file mode 100644 index 0000000..89d9f5c --- /dev/null +++ b/docs/revpimodio2.summary.rst @@ -0,0 +1,7 @@ +revpimodio2\.summary module +=========================== + +.. automodule:: revpimodio2.summary + :members: + :undoc-members: + :show-inheritance: diff --git a/revpimodio2/__init__.py b/revpimodio2/__init__.py index 4ea6607..3d99751 100644 --- a/revpimodio2/__init__.py +++ b/revpimodio2/__init__.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- -"""Stellt alle Klassen fuer den RevolutionPi zur Verfuegung. +""" +Stellt alle Klassen fuer den RevolutionPi zur Verfuegung. Webpage: https://revpimodio.org/ @@ -10,11 +11,10 @@ gemacht. Fuer Gateways sind eigene IOs ueber mehrere Bytes konfigurierbar Mit den definierten Namen greift man direkt auf die gewuenschten Daten zu. Auf alle IOs kann der Benutzer Funktionen als Events registrieren. Diese fuehrt das Modul bei Datenaenderung aus. - """ __all__ = [ - "RevPiModIO", "RevPiModIOSelected", "RevPiModIODriver", - "RevPiNetIO", "RevPiNetIOSelected", "RevPiNetIODriver", + "RevPiModIO", "RevPiModIODriver", "RevPiModIOSelected", + "RevPiNetIO", "RevPiNetIODriver", "RevPiNetIOSelected", "Cycletools", ] __author__ = "Sven Sager " @@ -36,27 +36,25 @@ MEM = 302 class DeviceNotFoundError(Exception): - """Fehler wenn ein Device nicht gefunden wird.""" pass -def acheck(check_type, **kwargs): - """Check type of given arguments. +def acheck(check_type, **kwargs) -> None: + """ + Check type of given arguments. Use the argument name as keyword and the argument itself as value. - @param check_type Type to check - @param kwargs Arguments to check - + :param check_type: Type to check + :param kwargs: Arguments to check """ for var_name in kwargs: none_okay = var_name.endswith("_noneok") if not (isinstance(kwargs[var_name], check_type) or none_okay and kwargs[var_name] is None): - msg = "Argument '{0}' must be {1}{2}".format( var_name.rstrip("_noneok"), str(check_type), " or " if none_okay else "" @@ -64,14 +62,14 @@ def acheck(check_type, **kwargs): raise TypeError(msg) -def consttostr(value): - """Gibt fuer Konstanten zurueck. +def consttostr(value) -> str: + """ + Gibt fuer Konstanten zurueck. Diese Funktion ist erforderlich, da enum in Python 3.2 nicht existiert. - @param value Konstantenwert - @return Name der Konstanten - + :param value: Konstantenwert + :return: Name der Konstanten """ if value == 0: return "OFF" @@ -97,5 +95,5 @@ def consttostr(value): # Benötigte Klassen importieren from .helper import Cycletools -from .modio import RevPiModIO, RevPiModIOSelected, RevPiModIODriver -from .netio import RevPiNetIO, RevPiNetIOSelected, RevPiNetIODriver +from .modio import RevPiModIO, RevPiModIODriver, RevPiModIOSelected +from .netio import RevPiNetIO, RevPiNetIODriver, RevPiNetIOSelected diff --git a/revpimodio2/app.py b/revpimodio2/app.py index d56aa8f..1977f60 100644 --- a/revpimodio2/app.py +++ b/revpimodio2/app.py @@ -1,27 +1,36 @@ # -*- coding: utf-8 -*- """Bildet die App Sektion von piCtory ab.""" +from time import strptime + __author__ = "Sven Sager" __copyright__ = "Copyright (C) 2018 Sven Sager" __license__ = "LGPLv3" -from time import strptime - class App(object): - """Bildet die App Sektion der config.rsc ab.""" __slots__ = "name", "version", "language", "layout", "savets" def __init__(self, app): - """Instantiiert die App-Klasse. - @param app piCtory Appinformationen""" + """ + Instantiiert die App-Klasse. + + :param app: piCtory Appinformationen + """ self.name = app["name"] + """Name of creating app""" + self.version = app["version"] + """Version of creating app""" + self.language = app["language"] + """Language of creating app""" # Speicherungszeitpunkt laden, wenn vorhanden self.savets = app.get("saveTS", None) + """Timestamp of configuraiton""" + if self.savets is not None: try: self.savets = strptime(self.savets, "%Y%m%d%H%M%S") diff --git a/revpimodio2/device.py b/revpimodio2/device.py index 291e9d8..a269d32 100644 --- a/revpimodio2/device.py +++ b/revpimodio2/device.py @@ -1,15 +1,15 @@ # -*- coding: utf-8 -*- """Modul fuer die Verwaltung der Devices.""" +from threading import Event, Lock, Thread + +from .helper import ProcimgWriter + __author__ = "Sven Sager" __copyright__ = "Copyright (C) 2018 Sven Sager" __license__ = "LGPLv3" -from threading import Thread, Event, Lock -from .helper import ProcimgWriter - class DeviceList(object): - """Basisklasse fuer direkten Zugriff auf Device Objekte.""" def __init__(self): @@ -17,9 +17,12 @@ class DeviceList(object): self.__dict_position = {} def __contains__(self, key): - """Prueft ob Device existiert. - @param key DeviceName / Positionsnummer - @return True, wenn Device vorhanden""" + """ + Prueft ob Device existiert. + + :param key: DeviceName / Positionsnummer + :return: True, wenn Device vorhanden + """ if type(key) == int: return key in self.__dict_position elif type(key) == str: @@ -28,9 +31,12 @@ class DeviceList(object): return key in self.__dict_position.values() def __delattr__(self, key, delcomplete=True): - """Entfernt angegebenes Device. - @param key Device zum entfernen - @param delcomplete Wenn True wird Device komplett entfernt""" + """ + Entfernt angegebenes Device. + + :param key: Device zum entfernen + :param delcomplete: Wenn True wird Device komplett entfernt + """ if delcomplete: # Device finden if type(key) == int: @@ -51,16 +57,22 @@ class DeviceList(object): object.__delattr__(self, key) def __delitem__(self, key): - """Entfernt Device an angegebener Position. - @param key Deviceposition zum entfernen""" + """ + Entfernt Device an angegebener Position. + + :param key: Deviceposition zum entfernen + """ if isinstance(key, Device): key = key._position self.__delattr__(key) def __getitem__(self, key): - """Gibt angegebenes Device zurueck. - @param key DeviceName / Positionsnummer - @return Gefundenes -Objekt""" + """ + Gibt angegebenes Device zurueck. + + :param key: DeviceName / Positionsnummer + :return: Gefundenes -Objekt + """ if type(key) == int: if key not in self.__dict_position: raise IndexError("no device on position {0}".format(key)) @@ -69,26 +81,33 @@ class DeviceList(object): return getattr(self, key) def __iter__(self): - """Gibt Iterator aller Devices zurueck. + """ + Gibt Iterator aller Devices zurueck. Die Reihenfolge ist nach Position im Prozessabbild sortiert und nicht nach Positionsnummer (Dies entspricht der Positionierung aus piCtory)! - @return aller Devices""" + :return: aller Devices + """ for dev in sorted( self.__dict_position, key=lambda key: self.__dict_position[key]._offset): yield self.__dict_position[dev] def __len__(self): - """Gibt Anzahl der Devices zurueck. - return Anzahl der Devices""" + """ + Gibt Anzahl der Devices zurueck. + + :return: Anzahl der Devices""" return len(self.__dict_position) def __setattr__(self, key, value): - """Setzt Attribute nur wenn Device. - @param key Attributname - @param value Attributobjekt""" + """ + Setzt Attribute nur wenn Device. + + :param key: Attributname + :param value: Attributobjekt + """ if isinstance(value, Device): object.__setattr__(self, key, value) self.__dict_position[value._position] = value @@ -97,29 +116,28 @@ class DeviceList(object): class Device(object): - - """Basisklasse fuer alle Device-Objekte. + """ + Basisklasse fuer alle Device-Objekte. Die Basisfunktionalitaet generiert bei Instantiierung alle IOs und erweitert den Prozessabbildpuffer um die benoetigten Bytes. Sie verwaltet ihren Prozessabbildpuffer und sorgt fuer die Aktualisierung der IO-Werte. - """ - __slots__ = "__my_io_list", "_ba_devdata", "_ba_datacp", \ - "_dict_events", "_filelock", "_length", "_modio", "_name", "_offset", \ - "_position", "_producttype", "_selfupdate", "_slc_devoff", \ - "_slc_inp", "_slc_inpoff", "_slc_mem", "_slc_memoff", \ - "_slc_out", "_slc_outoff", "bmk", "catalognr", "comment", "extend", \ - "guid", "id", "inpvariant", "outvariant", "type" + __slots__ = "__my_io_list", "_ba_devdata", "_ba_datacp", \ + "_dict_events", "_filelock", "_length", "_modio", "_name", "_offset", \ + "_position", "_producttype", "_selfupdate", "_slc_devoff", \ + "_slc_inp", "_slc_inpoff", "_slc_mem", "_slc_memoff", \ + "_slc_out", "_slc_outoff", "bmk", "catalognr", "comment", "extend", \ + "guid", "id", "inpvariant", "outvariant", "type" def __init__(self, parentmodio, dict_device, simulator=False): - """Instantiierung der Device-Klasse. - - @param parent RevpiModIO parent object - @param dict_device fuer dieses Device aus piCotry - @param simulator: Laedt das Modul als Simulator und vertauscht IOs + """ + Instantiierung der Device-Klasse. + :param parentmodio: RevpiModIO parent object + :param dict_device: fuer dieses Device aus piCotry + :param simulator: Laedt das Modul als Simulator und vertauscht IOs """ self._modio = parentmodio @@ -187,14 +205,20 @@ class Device(object): self._update_my_io_list() def __bytes__(self): - """Gibt alle Daten des Devices als zurueck. - @return Devicedaten als """ + """ + Gibt alle Daten des Devices als zurueck. + + :return: Devicedaten als + """ return bytes(self._ba_devdata) def __contains__(self, key): - """Prueft ob IO auf diesem Device liegt. - @param key IO-Name / IO-Bytenummer - @return True, wenn IO auf Device vorhanden""" + """ + Prueft ob IO auf diesem Device liegt. + + :param key: IO-Name / IO-Bytenummer + :return: True, wenn IO auf Device vorhanden + """ if isinstance(key, IOBase): # Umwandlung für key key = key._name @@ -207,54 +231,69 @@ class Device(object): return False else: return key in self._modio.io \ - and getattr(self._modio.io, key)._parentdevice == self + and getattr(self._modio.io, key)._parentdevice == self def __getitem__(self, key): - """Gibt IO an angegebener Stelle zurueck. - @param key Index des IOs auf dem device als - @return Gefundenes IO-Objekt""" + """ + Gibt IO an angegebener Stelle zurueck. + + :param key: Index des IOs auf dem device als + :return: Gefundenes IO-Objekt + """ return self.__my_io_list[key] def __int__(self): - """Gibt die Positon im RevPi Bus zurueck. - @return Positionsnummer""" + """ + Gibt die Positon im RevPi Bus zurueck. + + :return: Positionsnummer + """ return self._position def __iter__(self): - """Gibt Iterator aller IOs zurueck. - @return aller IOs""" + """ + Gibt Iterator aller IOs zurueck. + + :return: aller IOs + """ return self.__getioiter(self._slc_devoff, None) def __len__(self): - """Gibt Anzahl der Bytes zurueck, die dieses Device belegt. - @return """ + """ + Gibt Anzahl der Bytes zurueck, die dieses Device belegt. + + :return: + """ return self._length def __str__(self): - """Gibt den Namen des Devices zurueck. - @return Devicename""" + """ + Gibt den Namen des Devices zurueck. + + :return: Devicename + """ return self._name - def __getioiter(self, ioslc, export): - """Gibt mit allen IOs zurueck. - - @param ioslc IO Abschnitt - @param export Filter fuer 'Export' Flag in piCtory - @return IOs als Iterator + def __getioiter(self, ioslc: slice, export): + """ + Gibt mit allen IOs zurueck. + :param ioslc: IO Abschnitt + :param export: Filter fuer 'Export' Flag in piCtory + :return: IOs als Iterator """ for lst_io in self._modio.io[ioslc]: for io in lst_io: if io is not None and (export is None or io.export == export): yield io - def _buildio(self, dict_io, iotype): - """Erstellt aus der piCtory-Liste die IOs fuer dieses Device. - - @param dict_io -Objekt aus piCtory Konfiguration - @param iotype Wert - @return mit Start und Stop Position dieser IOs + def _buildio(self, dict_io: dict, iotype: int) -> slice: + """ + Erstellt aus der piCtory-Liste die IOs fuer dieses Device. + :param dict_io: -Objekt aus piCtory Konfiguration + :param iotype: Wert + :return: mit Start und Stop Position dieser IOs """ if len(dict_io) <= 0: return slice(0, 0) @@ -312,23 +351,32 @@ class Device(object): """Funktion zum ueberschreiben von abgeleiteten Klassen.""" pass - def _get_offset(self): - """Gibt den Deviceoffset im Prozessabbild zurueck. - @return Deviceoffset""" + def _get_offset(self) -> int: + """ + Gibt den Deviceoffset im Prozessabbild zurueck. + + :return: Deviceoffset + """ return self._offset - def _get_producttype(self): - """Gibt den Produkttypen des device zurueck. - @return Deviceprodukttyp""" + def _get_producttype(self) -> int: + """ + Gibt den Produkttypen des device zurueck. + + :return: Deviceprodukttyp + """ return self._producttype - def _update_my_io_list(self): + def _update_my_io_list(self) -> None: """Erzeugt eine neue IO Liste fuer schnellen Zugriff.""" self.__my_io_list = list(self.__iter__()) - def autorefresh(self, activate=True): - """Registriert dieses Device fuer die automatische Synchronisierung. - @param activate Default True fuegt Device zur Synchronisierung hinzu""" + def autorefresh(self, activate=True) -> None: + """ + Registriert dieses Device fuer die automatische Synchronisierung. + + :param activate: Default True fuegt Device zur Synchronisierung hinzu + """ if activate and self not in self._modio._lst_refresh: # Daten bei Aufnahme direkt einlesen! @@ -346,7 +394,6 @@ class Device(object): # Thread starten, wenn er noch nicht läuft if not self._modio._imgwriter.is_alive(): - # Alte Einstellungen speichern imgrefresh = self._modio._imgwriter.refresh @@ -369,98 +416,97 @@ class Device(object): if not self._modio._monitoring: self._modio.writeprocimg(self) - def get_allios(self, export=None): - """Gibt eine Liste aller Inputs und Outputs zurueck, keine MEMs. + def get_allios(self, export=None) -> list: + """ + Gibt eine Liste aller Inputs und Outputs zurueck, keine MEMs. Bleibt Parameter 'export' auf None werden alle Inputs und Outputs zurueckgegeben. Wird 'export' auf True/False gesetzt, werden nur Inputs und Outputs zurueckgegeben, bei denen der Wert 'Export' in piCtory uebereinstimmt. - @param export Nur In-/Outputs mit angegebenen 'Export' Wert in piCtory - @return Input und Output, keine MEMs - + :param export: Nur In-/Outputs mit angegebenen 'Export' Wert in piCtory + :return: Input und Output, keine MEMs """ return list(self.__getioiter( slice(self._slc_inpoff.start, self._slc_outoff.stop), export )) - def get_inputs(self, export=None): - """Gibt eine Liste aller Inputs zurueck. + def get_inputs(self, export=None) -> list: + """ + Gibt eine Liste aller Inputs zurueck. Bleibt Parameter 'export' auf None werden alle Inputs zurueckgegeben. Wird 'export' auf True/False gesetzt, werden nur Inputs zurueckgegeben, bei denen der Wert 'Export' in piCtory uebereinstimmt. - @param export Nur Inputs mit angegebenen 'Export' Wert in piCtory - @return Inputs - + :param export: Nur Inputs mit angegebenen 'Export' Wert in piCtory + :return: Inputs """ return list(self.__getioiter(self._slc_inpoff, export)) - def get_outputs(self, export=None): - """Gibt eine Liste aller Outputs zurueck. + def get_outputs(self, export=None) -> list: + """ + Gibt eine Liste aller Outputs zurueck. Bleibt Parameter 'export' auf None werden alle Outputs zurueckgegeben. Wird 'export' auf True/False gesetzt, werden nur Outputs zurueckgegeben, bei denen der Wert 'Export' in piCtory uebereinstimmt. - @param export Nur Outputs mit angegebenen 'Export' Wert in piCtory - @return Outputs - + :param export: Nur Outputs mit angegebenen 'Export' Wert in piCtory + :return: Outputs """ return list(self.__getioiter(self._slc_outoff, export)) - def get_memories(self, export=None): - """Gibt eine Liste aller Memoryobjekte zurueck. + def get_memories(self, export=None) -> list: + """ + Gibt eine Liste aller Memoryobjekte zurueck. Bleibt Parameter 'export' auf None werden alle Mems zurueckgegeben. Wird 'export' auf True/False gesetzt, werden nur Mems zurueckgegeben, bei denen der Wert 'Export' in piCtory uebereinstimmt. - @param export Nur Mems mit angegebenen 'Export' Wert in piCtory - @return Mems - + :param export: Nur Mems mit angegebenen 'Export' Wert in piCtory + :return: Mems """ return list(self.__getioiter(self._slc_memoff, export)) - def readprocimg(self): - """Alle Inputs fuer dieses Device vom Prozessabbild einlesen. + def readprocimg(self) -> bool: + """ + Alle Inputs fuer dieses Device vom Prozessabbild einlesen. - @return True, wenn erfolgreich ausgefuehrt - @see revpimodio2.modio#RevPiModIO.readprocimg - RevPiModIO.readprocimg() + Same see + + :return: True, wenn erfolgreich ausgefuehrt + :ref: :func:`revpimodio2.modio.RevPiModIO.readprocimg()` """ return self._modio.readprocimg(self) - def setdefaultvalues(self): - """Alle Outputbuffer fuer dieses Device auf default Werte setzen. - - @return True, wenn erfolgreich ausgefuehrt - @see revpimodio2.modio#RevPiModIO.setdefaultvalues - RevPiModIO.setdefaultvalues() + def setdefaultvalues(self) -> None: + """ + Alle Outputbuffer fuer dieses Device auf default Werte setzen. + :return: True, wenn erfolgreich ausgefuehrt + :ref: :func:`revpimodio2.modio.RevPiModIO.setdefaultvalues()` """ self._modio.setdefaultvalues(self) - def syncoutputs(self): - """Lesen aller Outputs im Prozessabbild fuer dieses Device. - - @return True, wenn erfolgreich ausgefuehrt - @see revpimodio2.modio#RevPiModIO.syncoutputs - RevPiModIO.syncoutputs() + def syncoutputs(self) -> bool: + """ + Lesen aller Outputs im Prozessabbild fuer dieses Device. + :return: True, wenn erfolgreich ausgefuehrt + :ref: :func:`revpimodio2.modio.RevPiModIO.syncoutputs()` """ return self._modio.syncoutputs(self) - def writeprocimg(self): - """Schreiben aller Outputs dieses Devices ins Prozessabbild. - - @return True, wenn erfolgreich ausgefuehrt - @see revpimodio2.modio#RevPiModIO.writeprocimg - RevPiModIO.writeprocimg() + def writeprocimg(self) -> bool: + """ + Schreiben aller Outputs dieses Devices ins Prozessabbild. + :return: True, wenn erfolgreich ausgefuehrt + :ref: :func:`revpimodio2.modio.RevPiModIO.writeprocimg()` """ return self._modio.writeprocimg(self) @@ -472,7 +518,6 @@ class Device(object): class Base(Device): - """Klasse fuer alle Base-Devices wie Core / Connect usw.""" __slots__ = () @@ -481,16 +526,15 @@ class Base(Device): class Core(Base): - - """Klasse fuer den RevPi Core. + """ + Klasse fuer den RevPi Core. Stellt Funktionen fuer die LEDs und den Status zur Verfuegung. - """ __slots__ = "_slc_cycle", "_slc_errorcnt", "_slc_statusbyte", \ - "_slc_temperature", "_slc_errorlimit1", "_slc_errorlimit2", \ - "_slc_frequency", "_slc_led", "a1green", "a1red", "a2green", "a2red" + "_slc_temperature", "_slc_errorlimit1", "_slc_errorlimit2", \ + "_slc_frequency", "_slc_led", "a1green", "a1red", "a2green", "a2red" def __setattr__(self, key, value): """Verhindert Ueberschreibung der LEDs.""" @@ -502,7 +546,7 @@ class Core(Base): else: object.__setattr__(self, key, value) - def _devconfigure(self): + def _devconfigure(self) -> None: """Core-Klasse vorbereiten.""" # Statische IO Verknüpfungen je nach Core-Variante @@ -564,10 +608,13 @@ class Core(Base): exp_a2red, None, "LED_A2_RED", "3" ], OUT, "little", False) - def __errorlimit(self, slc_io, errorlimit): - """Verwaltet das Schreiben der ErrorLimits. - @param slc_io Byte Slice vom ErrorLimit - @return Aktuellen ErrorLimit oder None wenn nicht verfuegbar""" + def __errorlimit(self, slc_io: slice, errorlimit: int) -> None: + """ + Verwaltet das Schreiben der ErrorLimits. + + :param slc_io: Byte Slice vom ErrorLimit + :return: Aktuellen ErrorLimit oder None wenn nicht verfuegbar + """ if 0 <= errorlimit <= 65535: self._ba_devdata[slc_io] = \ errorlimit.to_bytes(2, byteorder="little") @@ -576,16 +623,22 @@ class Core(Base): "errorlimit value must be between 0 and 65535" ) - def _get_status(self): - """Gibt den RevPi Core Status zurueck. - @return Status als """ + def _get_status(self) -> int: + """ + Gibt den RevPi Core Status zurueck. + + :return: Status als + """ return int.from_bytes( self._ba_devdata[self._slc_statusbyte], byteorder="little" ) - def _get_leda1(self): - """Gibt den Zustand der LED A1 vom Core zurueck. - @return 0=aus, 1=gruen, 2=rot""" + def _get_leda1(self) -> int: + """ + Gibt den Zustand der LED A1 vom Core zurueck. + + :return: 0=aus, 1=gruen, 2=rot + """ int_led = int.from_bytes( self._ba_devdata[self._slc_led], byteorder="little" ) @@ -593,9 +646,12 @@ class Core(Base): led += int_led & 2 return led - def _get_leda2(self): - """Gibt den Zustand der LED A2 vom Core zurueck. - @return 0=aus, 1=gruen, 2=rot""" + def _get_leda2(self) -> int: + """ + Gibt den Zustand der LED A2 vom Core zurueck. + + :return: 0=aus, 1=gruen, 2=rot + """ int_led = int.from_bytes( self._ba_devdata[self._slc_led], byteorder="little" ) >> 2 @@ -603,10 +659,14 @@ class Core(Base): led += int_led & 2 return led - def _set_calculatedled(self, addresslist, shifted_value): - """Berechnet und setzt neuen Bytewert fuer LED byte. - @param addresslist Liste der Vergleicher - @param shifed_value Bits vergleichen""" + def _set_calculatedled(self, addresslist, shifted_value) -> None: + """ + Berechnet und setzt neuen Bytewert fuer LED byte. + + :param addresslist: Liste der Vergleicher + :param shifted_value: Bits vergleichen + """ + # TODO: Docstring # Byte als int holen int_led = int.from_bytes( self._ba_devdata[self._slc_led], byteorder="little" @@ -625,17 +685,23 @@ class Core(Base): self._ba_devdata[self._slc_led] = \ int_led.to_bytes(length=1, byteorder="little") - def _set_leda1(self, value): - """Setzt den Zustand der LED A1 vom Core. - @param value 0=aus, 1=gruen, 2=rot""" + def _set_leda1(self, value: int) -> None: + """ + Setzt den Zustand der LED A1 vom Core. + + :param value: 0=aus, 1=gruen, 2=rot + """ if 0 <= value <= 3: self._set_calculatedled([1, 2], value) else: raise ValueError("led status must be between 0 and 3") - def _set_leda2(self, value): - """Setzt den Zustand der LED A2 vom Core. - @param value 0=aus, 1=gruen, 2=rot""" + def _set_leda2(self, value: int) -> None: + """ + Setzt den Zustand der LED A2 vom Core. + + :param value: 0=aus, 1=gruen, 2=rot + """ if 0 <= value <= 3: self._set_calculatedled([4, 8], value << 2) else: @@ -646,97 +712,133 @@ class Core(Base): status = property(_get_status) @property - def picontrolrunning(self): - """Statusbit fuer piControl-Treiber laeuft. - @return True, wenn Treiber laeuft""" + def picontrolrunning(self) -> bool: + """ + Statusbit fuer piControl-Treiber laeuft. + + :return: True, wenn Treiber laeuft + """ return bool(int.from_bytes( self._ba_devdata[self._slc_statusbyte], byteorder="little" ) & 1) @property - def unconfdevice(self): - """Statusbit fuer ein IO-Modul nicht mit PiCtory konfiguriert. - @return True, wenn IO Modul nicht konfiguriert""" + def unconfdevice(self) -> bool: + """ + Statusbit fuer ein IO-Modul nicht mit PiCtory konfiguriert. + + :return: True, wenn IO Modul nicht konfiguriert + """ return bool(int.from_bytes( self._ba_devdata[self._slc_statusbyte], byteorder="little" ) & 2) @property - def missingdeviceorgate(self): - """Statusbit fuer ein IO-Modul fehlt oder piGate konfiguriert. - @return True, wenn IO-Modul fehlt oder piGate konfiguriert""" + def missingdeviceorgate(self) -> bool: + """ + Statusbit fuer ein IO-Modul fehlt oder piGate konfiguriert. + + :return: True, wenn IO-Modul fehlt oder piGate konfiguriert + """ return bool(int.from_bytes( self._ba_devdata[self._slc_statusbyte], byteorder="little" ) & 4) @property - def overunderflow(self): - """Statusbit Modul belegt mehr oder weniger Speicher als konfiguriert. - @return True, wenn falscher Speicher belegt ist""" + def overunderflow(self) -> bool: + """ + Statusbit Modul belegt mehr oder weniger Speicher als konfiguriert. + + :return: True, wenn falscher Speicher belegt ist + """ return bool(int.from_bytes( self._ba_devdata[self._slc_statusbyte], byteorder="little" ) & 8) @property - def leftgate(self): - """Statusbit links vom RevPi ist ein piGate Modul angeschlossen. - @return True, wenn piGate links existiert""" + def leftgate(self) -> bool: + """ + Statusbit links vom RevPi ist ein piGate Modul angeschlossen. + + :return: True, wenn piGate links existiert + """ return bool(int.from_bytes( self._ba_devdata[self._slc_statusbyte], byteorder="little" ) & 16) @property - def rightgate(self): - """Statusbit rechts vom RevPi ist ein piGate Modul angeschlossen. - @return True, wenn piGate rechts existiert""" + def rightgate(self) -> bool: + """ + Statusbit rechts vom RevPi ist ein piGate Modul angeschlossen. + + :return: True, wenn piGate rechts existiert + """ return bool(int.from_bytes( self._ba_devdata[self._slc_statusbyte], byteorder="little" ) & 32) @property - def iocycle(self): - """Gibt Zykluszeit der Prozessabbildsynchronisierung zurueck. - @return Zykluszeit in ms""" - return None if self._slc_cycle is None else int.from_bytes( + def iocycle(self) -> int: + """ + Gibt Zykluszeit der Prozessabbildsynchronisierung zurueck. + + :return: Zykluszeit in ms ( -1 wenn nicht verfuegbar) + """ + return -1 if self._slc_cycle is None else int.from_bytes( self._ba_devdata[self._slc_cycle], byteorder="little" ) @property - def temperature(self): - """Gibt CPU-Temperatur zurueck. - @return CPU-Temperatur in Celsius""" - return None if self._slc_temperature is None else int.from_bytes( + def temperature(self) -> int: + """ + Gibt CPU-Temperatur zurueck. + + :return: CPU-Temperatur in Celsius (-273 wenn nich verfuegbar) + """ + return -273 if self._slc_temperature is None else int.from_bytes( self._ba_devdata[self._slc_temperature], byteorder="little" ) @property - def frequency(self): - """Gibt CPU Taktfrequenz zurueck. - @return CPU Taktfrequenz in MHz""" - return None if self._slc_frequency is None else int.from_bytes( + def frequency(self) -> int: + """ + Gibt CPU Taktfrequenz zurueck. + + :return: CPU Taktfrequenz in MHz (-1 wenn nicht verfuegbar) + """ + return -1 if self._slc_frequency is None else int.from_bytes( self._ba_devdata[self._slc_frequency], byteorder="little" ) * 10 @property - def ioerrorcount(self): - """Gibt Fehleranzahl auf RS485 piBridge Bus zurueck. - @return Fehleranzahl der piBridge""" - return None if self._slc_errorcnt is None else int.from_bytes( + def ioerrorcount(self) -> int: + """ + Gibt Fehleranzahl auf RS485 piBridge Bus zurueck. + + :return: Fehleranzahl der piBridge (-1 wenn nicht verfuegbar) + """ + return -1 if self._slc_errorcnt is None else int.from_bytes( self._ba_devdata[self._slc_errorcnt], byteorder="little" ) @property - def errorlimit1(self): - """Gibt RS485 ErrorLimit1 Wert zurueck. - @return Aktueller Wert fuer ErrorLimit1""" - return None if self._slc_errorlimit1 is None else int.from_bytes( + def errorlimit1(self) -> int: + """ + Gibt RS485 ErrorLimit1 Wert zurueck. + + :return: Aktueller Wert fuer ErrorLimit1 (-1 wenn nicht verfuegbar) + """ + return -1 if self._slc_errorlimit1 is None else int.from_bytes( self._ba_devdata[self._slc_errorlimit1], byteorder="little" ) @errorlimit1.setter - def errorlimit1(self, value): - """Setzt RS485 ErrorLimit1 auf neuen Wert. - @param value Neuer ErrorLimit1 Wert""" + def errorlimit1(self, value: int) -> None: + """ + Setzt RS485 ErrorLimit1 auf neuen Wert. + + :param value: Neuer ErrorLimit1 Wert + """ if self._slc_errorlimit1 is None: raise RuntimeError( "selected core item in piCtory does not support errorlimit1" @@ -745,17 +847,23 @@ class Core(Base): self.__errorlimit(self._slc_errorlimit1, value) @property - def errorlimit2(self): - """Gibt RS485 ErrorLimit2 Wert zurueck. - @return Aktueller Wert fuer ErrorLimit2""" - return None if self._slc_errorlimit2 is None else int.from_bytes( + def errorlimit2(self) -> int: + """ + Gibt RS485 ErrorLimit2 Wert zurueck. + + :return: Aktueller Wert fuer ErrorLimit2 (-1 wenn nicht verfuegbar) + """ + return -1 if self._slc_errorlimit2 is None else int.from_bytes( self._ba_devdata[self._slc_errorlimit2], byteorder="little" ) @errorlimit2.setter - def errorlimit2(self, value): - """Setzt RS485 ErrorLimit2 auf neuen Wert. - @param value Neuer ErrorLimit2 Wert""" + def errorlimit2(self, value: int) -> None: + """ + Setzt RS485 ErrorLimit2 auf neuen Wert. + + :param value: Neuer ErrorLimit2 Wert + """ if self._slc_errorlimit2 is None: raise RuntimeError( "selected core item in piCtory does not support errorlimit2" @@ -765,15 +873,13 @@ class Core(Base): class Connect(Core): - """Klasse fuer den RevPi Connect. Stellt Funktionen fuer die LEDs, Watchdog und den Status zur Verfuegung. - """ __slots__ = "__evt_wdtoggle", "__th_wdtoggle", "a3green", "a3red", "wd", \ - "x2in", "x2out" + "x2in", "x2out" def __setattr__(self, key, value): """Verhindert Ueberschreibung der LEDs.""" @@ -786,12 +892,12 @@ class Connect(Core): else: object.__setattr__(self, key, value) - def __wdtoggle(self): + def __wdtoggle(self) -> None: """WD Ausgang alle 10 Sekunden automatisch toggeln.""" while not self.__evt_wdtoggle.wait(10): self.wd.value = not self.wd.value - def _devconfigure(self): + def _devconfigure(self) -> None: """Connect-Klasse vorbereiten.""" super()._devconfigure() @@ -841,9 +947,12 @@ class Connect(Core): exp_x2out, None, "Connect_X2_OUT", "6" ], OUT, "little", False) - def _get_leda3(self): - """Gibt den Zustand der LED A3 vom Connect zurueck. - @return 0=aus, 1=gruen, 2=rot""" + def _get_leda3(self) -> int: + """ + Gibt den Zustand der LED A3 vom Connect zurueck. + + :return: 0=aus, 1=gruen, 2=rot + """ int_led = int.from_bytes( self._ba_devdata[self._slc_led], byteorder="little" ) >> 4 @@ -851,22 +960,28 @@ class Connect(Core): led += int_led & 2 return led - def _get_wdtoggle(self): - """Ruft den Wert fuer Autowatchdog ab. - @return True, wenn Autowatchdog aktiv ist""" - return self.__th_wdtoggle is not None \ - and self.__th_wdtoggle.is_alive() + def _get_wdtoggle(self) -> bool: + """ + Ruft den Wert fuer Autowatchdog ab. - def _set_leda3(self, value): - """Setzt den Zustand der LED A3 vom Connect. - @param value 0=aus, 1=gruen, 2=rot""" + :return: True, wenn Autowatchdog aktiv ist + """ + return self.__th_wdtoggle is not None and self.__th_wdtoggle.is_alive() + + def _set_leda3(self, value: int) -> None: + """ + Setzt den Zustand der LED A3 vom Connect. + + :param: value 0=aus, 1=gruen, 2=rot + """ if 0 <= value <= 3: self._set_calculatedled([16, 32], value << 4) else: raise ValueError("led status must be between 0 and 3") - def _set_wdtoggle(self, value): - """Setzt den Wert fuer Autowatchdog. + def _set_wdtoggle(self, value: bool) -> None: + """ + Setzt den Wert fuer Autowatchdog. Wird dieser Wert auf True gesetzt, wechselt im Hintergrund das noetige Bit zum toggeln des Watchdogs alle 10 Sekunden zwichen True und False. @@ -877,7 +992,8 @@ class Connect(Core): .writeprocimg() aufgerufen werden, um den Wert in das Prozessabbild zu schreiben!!! - @param value True zum aktivieren, Fals zum beenden""" + :param value: True zum aktivieren, Fals zum beenden + """ if self._modio._monitoring: raise RuntimeError( "can not toggle watchdog, while system is in monitoring mode" @@ -901,15 +1017,16 @@ class Connect(Core): class DioModule(Device): - """Stellt ein DIO / DI / DO Modul dar.""" - __slots__ = ("_lst_counter") + __slots__ = "_lst_counter" def __init__(self, parentmodio, dict_device, simulator=False): - """Erweitert Device-Klasse zum Erkennen von IntIOCounter. - @see #Device.__init__ Device.__init__(...)""" + """ + Erweitert Device-Klasse zum Erkennen von IntIOCounter. + :rev: :func:`Device.__init__()` + """ # Stringliste der Byteadressen (alle Module sind gleich) self._lst_counter = list(map(str, range(6, 70, 4))) @@ -918,23 +1035,26 @@ class DioModule(Device): class Gateway(Device): - - """Klasse fuer die RevPi Gateway-Devices. + """ + Klasse fuer die RevPi Gateway-Devices. Stellt neben den Funktionen von RevPiDevice weitere Funktionen fuer die Gateways bereit. IOs auf diesem Device stellen die replace_io Funktion zur verfuegung, ueber die eigene IOs definiert werden, die ein RevPiStructIO-Objekt abbilden. Dieser IO-Typ kann Werte ueber mehrere Bytes verarbeiten und zurueckgeben. - @see revpimodio2.io#IntIOReplaceable.replace_io replace_io(...) + :ref: :func:`revpimodio2.io.IntIOReplaceable.replace_io()` """ __slots__ = "_dict_slc" def __init__(self, parent, dict_device, simulator=False): - """Erweitert Device-Klasse um get_rawbytes-Funktionen. - @see #Device.__init__ Device.__init__(...)""" + """ + Erweitert Device-Klasse um get_rawbytes-Funktionen. + + :ref: :func:`Device.__init__()` + """ super().__init__(parent, dict_device, simulator) self._dict_slc = { @@ -943,28 +1063,32 @@ class Gateway(Device): MEM: self._slc_mem } - def get_rawbytes(self): - """Gibt die Bytes aus, die dieses Device verwendet. - @return des Devices""" + def get_rawbytes(self) -> bytes: + """ + Gibt die Bytes aus, die dieses Device verwendet. + + :return: des Devices + """ return bytes(self._ba_devdata) class Virtual(Gateway): - - """Klasse fuer die RevPi Virtual-Devices. + """ + Klasse fuer die RevPi Virtual-Devices. Stellt die selben Funktionen wie Gateway zur Verfuegung. Es koennen ueber die reg_*-Funktionen eigene IOs definiert werden, die ein RevPiStructIO-Objekt abbilden. Dieser IO-Typ kann Werte ueber mehrere Bytes verarbeiten und zurueckgeben. - @see #Gateway Gateway + :ref: :func:`Gateway` """ __slots__ = () def writeinputdefaults(self): - """Schreibt fuer ein virtuelles Device piCtory Defaultinputwerte. + """ + Schreibt fuer ein virtuelles Device piCtory Defaultinputwerte. Sollten in piCtory Defaultwerte fuer Inputs eines virtuellen Devices angegeben sein, werden diese nur beim Systemstart oder einem piControl @@ -972,8 +1096,7 @@ class Virtual(Gateway): gehen diese Werte verloren. Diese Funktion kann nur auf virtuelle Devices angewendet werden! - @return True, wenn Arbeiten am virtuellen Device erfolgreich waren - + :return: True, wenn Arbeiten am virtuellen Device erfolgreich waren """ if self._modio._monitoring: raise RuntimeError( diff --git a/revpimodio2/helper.py b/revpimodio2/helper.py index 8c88e4b..77b9e88 100644 --- a/revpimodio2/helper.py +++ b/revpimodio2/helper.py @@ -1,19 +1,19 @@ # -*- coding: utf-8 -*- """RevPiModIO Helperklassen und Tools.""" -__author__ = "Sven Sager" -__copyright__ = "Copyright (C) 2018 Sven Sager" -__license__ = "LGPLv3" - import queue import warnings from math import ceil from threading import Event, Lock, Thread from timeit import default_timer -from revpimodio2 import RISING, FALLING, BOTH + +from revpimodio2 import BOTH, FALLING, RISING + +__author__ = "Sven Sager" +__copyright__ = "Copyright (C) 2018 Sven Sager" +__license__ = "LGPLv3" class EventCallback(Thread): - """Thread fuer das interne Aufrufen von Event-Funktionen. Der Eventfunktion, welche dieser Thread aufruft, wird der Thread selber @@ -34,18 +34,17 @@ class EventCallback(Thread): while not th.exit.is_set(): # IO-Arbeiten th.exit.wait(0.5) - """ __slots__ = "daemon", "exit", "func", "ioname", "iovalue" - def __init__(self, func, name, value): - """Init EventCallback class. - - @param func Funktion die beim Start aufgerufen werden soll - @param name IO-Name - @param value IO-Value zum Zeitpunkt des Events + def __init__(self, func, name: str, value): + """ + Init EventCallback class. + :param func: Funktion die beim Start aufgerufen werden soll + :param name: IO-Name + :param value: IO-Value zum Zeitpunkt des Events """ super().__init__() self.daemon = True @@ -63,9 +62,9 @@ class EventCallback(Thread): self.exit.set() -class Cycletools(): - - """Werkzeugkasten fuer Cycleloop-Funktion. +class Cycletools: + """ + Werkzeugkasten fuer Cycleloop-Funktion. Diese Klasse enthaelt Werkzeuge fuer Zyklusfunktionen, wie Taktmerker und Flankenmerker. @@ -84,13 +83,12 @@ class Cycletools(): Diese Merker koennen z.B. verwendet werden um, an Outputs angeschlossene, Lampen synchron blinken zu lassen. - """ __slots__ = "__cycle", "__cycletime", "__ucycle", \ - "__dict_ton", "__dict_tof", "__dict_tp", "first", \ - "flag1c", "flag5c", "flag10c", "flag15c", "flag20c", \ - "flank5c", "flank10c", "flank15c", "flank20c", "var" + "__dict_ton", "__dict_tof", "__dict_tp", "first", \ + "flag1c", "flag5c", "flag10c", "flag15c", "flag20c", \ + "flank5c", "flank10c", "flank15c", "flank20c", "var" def __init__(self, cycletime): """Init Cycletools class.""" @@ -117,10 +115,13 @@ class Cycletools(): # Benutzerdaten class Var: + """Hier remanente Variablen anfuegen.""" + pass + self.var = Var() - def _docycle(self): + def _docycle(self) -> None: """Zyklusarbeiten.""" # Einschaltverzoegerung for tof in self.__dict_tof: @@ -174,54 +175,66 @@ class Cycletools(): self.flag5c = not self.flag5c self.__cycle = 0 - def get_tof(self, name): - """Wert der Ausschaltverzoegerung. - @param name Eindeutiger Name des Timers - @return Wert der Ausschaltverzoegerung""" + def get_tof(self, name: str) -> bool: + """ + Wert der Ausschaltverzoegerung. + + :param name: Eindeutiger Name des Timers + :return: Wert der Ausschaltverzoegerung + """ return self.__dict_tof.get(name, 0) > 0 - def get_tofc(self, name): - """Wert der Ausschaltverzoegerung. - @param name Eindeutiger Name des Timers - @return Wert der Ausschaltverzoegerung""" + def get_tofc(self, name: str) -> bool: + """ + Wert der Ausschaltverzoegerung. + + :param name: Eindeutiger Name des Timers + :return: Wert der Ausschaltverzoegerung + """ return self.__dict_tof.get(name, 0) > 0 - def set_tof(self, name, milliseconds): - """Startet bei Aufruf einen ausschaltverzoegerten Timer. - - @param name Eindeutiger Name fuer Zugriff auf Timer - @param milliseconds Verzoegerung in Millisekunden + def set_tof(self, name: str, milliseconds: int) -> None: + """ + Startet bei Aufruf einen ausschaltverzoegerten Timer. + :param name: Eindeutiger Name fuer Zugriff auf Timer + :param milliseconds: Verzoegerung in Millisekunden """ self.__dict_tof[name] = ceil(milliseconds / self.__cycletime) - def set_tofc(self, name, cycles): - """Startet bei Aufruf einen ausschaltverzoegerten Timer. - - @param name Eindeutiger Name fuer Zugriff auf Timer - @param cycles Zyklusanzahl, der Verzoegerung wenn nicht neu gestartet + def set_tofc(self, name: str, cycles: int) -> None: + """ + Startet bei Aufruf einen ausschaltverzoegerten Timer. + :param name: Eindeutiger Name fuer Zugriff auf Timer + :param cycles: Zyklusanzahl, der Verzoegerung wenn nicht neu gestartet """ self.__dict_tof[name] = cycles - def get_ton(self, name): - """Einschaltverzoegerung. - @param name Eindeutiger Name des Timers - @return Wert der Einschaltverzoegerung""" + def get_ton(self, name: str) -> bool: + """ + Einschaltverzoegerung. + + :param name: Eindeutiger Name des Timers + :return: Wert der Einschaltverzoegerung + """ return self.__dict_ton.get(name, [-1])[0] == 0 - def get_tonc(self, name): - """Einschaltverzoegerung. - @param name Eindeutiger Name des Timers - @return Wert der Einschaltverzoegerung""" + def get_tonc(self, name: str) -> bool: + """ + Einschaltverzoegerung. + + :param name: Eindeutiger Name des Timers + :return: Wert der Einschaltverzoegerung + """ return self.__dict_ton.get(name, [-1])[0] == 0 - def set_ton(self, name, milliseconds): - """Startet einen einschaltverzoegerten Timer. - - @param name Eindeutiger Name fuer Zugriff auf Timer - @param milliseconds Millisekunden, der Verzoegerung wenn neu gestartet + def set_ton(self, name: str, milliseconds: int) -> None: + """ + Startet einen einschaltverzoegerten Timer. + :param name: Eindeutiger Name fuer Zugriff auf Timer + :param milliseconds: Millisekunden, der Verzoegerung wenn neu gestartet """ if self.__dict_ton.get(name, [-1])[0] == -1: self.__dict_ton[name] = \ @@ -229,36 +242,42 @@ class Cycletools(): else: self.__dict_ton[name][1] = True - def set_tonc(self, name, cycles): - """Startet einen einschaltverzoegerten Timer. - - @param name Eindeutiger Name fuer Zugriff auf Timer - @param cycles Zyklusanzahl, der Verzoegerung wenn neu gestartet + def set_tonc(self, name: str, cycles: int) -> None: + """ + Startet einen einschaltverzoegerten Timer. + :param name: Eindeutiger Name fuer Zugriff auf Timer + :param cycles: Zyklusanzahl, der Verzoegerung wenn neu gestartet """ if self.__dict_ton.get(name, [-1])[0] == -1: self.__dict_ton[name] = [cycles, True] else: self.__dict_ton[name][1] = True - def get_tp(self, name): - """Impulstimer. - @param name Eindeutiger Name des Timers - @return Wert des Impulses""" + def get_tp(self, name: str) -> bool: + """ + Impulstimer. + + :param name: Eindeutiger Name des Timers + :return: Wert des Impulses + """ return self.__dict_tp.get(name, [-1])[0] > 0 - def get_tpc(self, name): - """Impulstimer. - @param name Eindeutiger Name des Timers - @return Wert des Impulses""" + def get_tpc(self, name: str) -> bool: + """ + Impulstimer. + + :param name: Eindeutiger Name des Timers + :return: Wert des Impulses + """ return self.__dict_tp.get(name, [-1])[0] > 0 - def set_tp(self, name, milliseconds): - """Startet einen Impuls Timer. - - @param name Eindeutiger Name fuer Zugriff auf Timer - @param milliseconds Millisekunden, die der Impuls anstehen soll + def set_tp(self, name: str, milliseconds: int) -> None: + """ + Startet einen Impuls Timer. + :param name: Eindeutiger Name fuer Zugriff auf Timer + :param milliseconds: Millisekunden, die der Impuls anstehen soll """ if self.__dict_tp.get(name, [-1])[0] == -1: self.__dict_tp[name] = \ @@ -266,12 +285,12 @@ class Cycletools(): else: self.__dict_tp[name][1] = True - def set_tpc(self, name, cycles): - """Startet einen Impuls Timer. - - @param name Eindeutiger Name fuer Zugriff auf Timer - @param cycles Zyklusanzahl, die der Impuls anstehen soll + def set_tpc(self, name: str, cycles: int) -> None: + """ + Startet einen Impuls Timer. + :param name: Eindeutiger Name fuer Zugriff auf Timer + :param cycles: Zyklusanzahl, die der Impuls anstehen soll """ if self.__dict_tp.get(name, [-1])[0] == -1: self.__dict_tp[name] = [cycles, True] @@ -280,22 +299,20 @@ class Cycletools(): class ProcimgWriter(Thread): - - """Klasse fuer Synchroniseriungs-Thread. + """ + Klasse fuer Synchroniseriungs-Thread. Diese Klasse wird als Thread gestartet, wenn das Prozessabbild zyklisch synchronisiert werden soll. Diese Funktion wird hauptsaechlich fuer das Event-Handling verwendet. - """ __slots__ = "__dict_delay", "__eventth", "_eventqth", "__eventwork", \ - "_adjwait", "_eventq", "_modio", \ - "_refresh", "_work", "daemon", "lck_refresh", "newdata" + "_adjwait", "_eventq", "_modio", \ + "_refresh", "_work", "daemon", "lck_refresh", "newdata" def __init__(self, parentmodio): - """Init ProcimgWriter class. - @param parentmodio Parent Object""" + """Init ProcimgWriter class.""" super().__init__() self.__dict_delay = {} self.__eventth = Thread(target=self.__exec_th) @@ -311,7 +328,7 @@ class ProcimgWriter(Thread): self.lck_refresh = Lock() self.newdata = Event() - def __check_change(self, dev): + def __check_change(self, dev) -> None: """Findet Aenderungen fuer die Eventueberwachung.""" for io_event in dev._dict_events: @@ -386,7 +403,7 @@ class ProcimgWriter(Thread): # Nach Verarbeitung aller IOs die Bytes kopieren (Lock ist noch drauf) dev._ba_datacp = dev._ba_devdata[:] - def __exec_th(self): + def __exec_th(self) -> None: """Laeuft als Thread, der Events als Thread startet.""" while self.__eventwork: try: @@ -398,10 +415,13 @@ class ProcimgWriter(Thread): except queue.Empty: pass - def _collect_events(self, value): - """Aktiviert oder Deaktiviert die Eventueberwachung. - @param value True aktiviert / False deaktiviert - @return True, wenn Anforderung erfolgreich war""" + def _collect_events(self, value: bool) -> bool: + """ + Aktiviert oder Deaktiviert die Eventueberwachung. + + :param value: True aktiviert / False deaktiviert + :return: True, wenn Anforderung erfolgreich war + """ if type(value) != bool: raise TypeError("value must be ") @@ -427,9 +447,12 @@ class ProcimgWriter(Thread): return True - def get_refresh(self): - """Gibt Zykluszeit zurueck. - @return Zykluszeit in Millisekunden""" + def get_refresh(self) -> int: + """ + Gibt Zykluszeit zurueck. + + :return: Zykluszeit in Millisekunden + """ return int(self._refresh * 1000) def run(self): @@ -472,7 +495,7 @@ class ProcimgWriter(Thread): with dev._filelock: dev._ba_devdata[dev._slc_inp] = \ bytesbuff[dev._slc_inpoff] - if self.__eventwork\ + if self.__eventwork \ and len(dev._dict_events) > 0 \ and dev._ba_datacp != dev._ba_devdata: self.__check_change(dev) diff --git a/revpimodio2/io.py b/revpimodio2/io.py index b5e766d..f0bcadc 100644 --- a/revpimodio2/io.py +++ b/revpimodio2/io.py @@ -1,13 +1,15 @@ # -*- coding: utf-8 -*- """RevPiModIO Modul fuer die Verwaltung der IOs.""" +import struct +from re import match as rematch +from threading import Event + +from revpimodio2 import BOTH, FALLING, INP, MEM, RISING, consttostr + __author__ = "Sven Sager" __copyright__ = "Copyright (C) 2018 Sven Sager" __license__ = "LGPLv3" -import struct -from re import match as rematch -from threading import Event -from revpimodio2 import RISING, FALLING, BOTH, INP, MEM, consttostr try: # Funktioniert nur auf Unix from fcntl import ioctl @@ -16,7 +18,6 @@ except Exception: class IOEvent(object): - """Basisklasse fuer IO-Events.""" __slots__ = "as_thread", "delay", "edge", "func", "overwrite", "prefire" @@ -32,7 +33,6 @@ class IOEvent(object): class IOList(object): - """Basisklasse fuer direkten Zugriff auf IO Objekte.""" def __init__(self): @@ -41,17 +41,23 @@ class IOList(object): self.__dict_iorefname = {} def __contains__(self, key): - """Prueft ob IO existiert. - @param key IO-Name oder Bytenummer - @return True, wenn IO vorhanden / Byte belegt""" + """ + Prueft ob IO existiert. + + :param key: IO-Name oder Bytenummer + :return: True, wenn IO vorhanden / Byte belegt + """ if type(key) == int: return len(self.__dict_iobyte.get(key, [])) > 0 else: return hasattr(self, key) and type(getattr(self, key)) != DeadIO def __delattr__(self, key): - """Entfernt angegebenen IO. - @param key IO zum entfernen""" + """ + Entfernt angegebenen IO. + + :param key: IO zum entfernen + """ io_del = object.__getattribute__(self, key) # Alte Events vom Device löschen @@ -70,16 +76,20 @@ class IOList(object): io_del._parentdevice._update_my_io_list() def __getattr__(self, key): - """Verwaltet geloeschte IOs (Attribute, die nicht existieren). - @param key Name oder Byte eines alten IOs - @return Alten IO, wenn in Ref-Listen""" + """ + Verwaltet geloeschte IOs (Attribute, die nicht existieren). + + :param key: Name oder Byte eines alten IOs + :return: Alten IO, wenn in Ref-Listen + """ if key in self.__dict_iorefname: return self.__dict_iorefname[key] else: raise AttributeError("can not find io '{0}'".format(key)) def __getitem__(self, key): - """Ruft angegebenen IO ab. + """ + Ruft angegebenen IO ab. Wenn der Key ist, wird ein einzelner IO geliefert. Wird der Key als uebergeben, wird eine @@ -87,9 +97,8 @@ class IOList(object): Wird als Key gegeben, werden die Listen in einer Liste zurueckgegeben. - @param key IO Name als oder Byte als . - @return IO Objekt oder Liste der IOs - + :param key: IO Name als oder Byte als . + :return: IO Objekt oder Liste der IOs """ if type(key) == int: if key not in self.__dict_iobyte: @@ -106,16 +115,22 @@ class IOList(object): return getattr(self, key) def __iter__(self): - """Gibt Iterator aller IOs zurueck. - @return Iterator aller IOs""" + """ + Gibt Iterator aller IOs zurueck. + + :return: Iterator aller IOs + """ for int_io in sorted(self.__dict_iobyte): for io in self.__dict_iobyte[int_io]: if io is not None: yield io def __len__(self): - """Gibt die Anzahl aller IOs zurueck. - @return Anzahl aller IOs""" + """ + Gibt die Anzahl aller IOs zurueck. + + :return: Anzahl aller IOs + """ int_ios = 0 for int_io in self.__dict_iobyte: for io in self.__dict_iobyte[int_io]: @@ -128,17 +143,19 @@ class IOList(object): if key in ( "_IOList__dict_iobyte", "_IOList__dict_iorefname" - ): + ): object.__setattr__(self, key, value) else: raise AttributeError( "direct assignment is not supported - use .value Attribute" ) - def __private_replace_oldio_with_newio(self, io): - """Ersetzt bestehende IOs durch den neu Registrierten. - @param io Neuer IO der eingefuegt werden soll""" + def __private_replace_oldio_with_newio(self, io) -> None: + """ + Ersetzt bestehende IOs durch den neu Registrierten. + :param io: Neuer IO der eingefuegt werden soll + """ # Scanbereich festlegen if io._bitaddress < 0: scan_start = io.address @@ -192,12 +209,15 @@ class IOList(object): io._defaultvalue = calc_defaultvalue else: io._defaultvalue = bool(io._parentio_defaultvalue[ - io._parentio_address - io.address - ] & (1 << io._bitaddress)) + io._parentio_address - io.address + ] & (1 << io._bitaddress)) - def _private_register_new_io_object(self, new_io): - """Registriert neues IO Objekt unabhaenging von __setattr__. - @param new_io Neues IO Objekt""" + def _private_register_new_io_object(self, new_io) -> None: + """ + Registriert neues IO Objekt unabhaenging von __setattr__. + + :param new_io: Neues IO Objekt + """ if isinstance(new_io, IOBase): if hasattr(self, new_io._name): raise AttributeError( @@ -229,27 +249,32 @@ class IOList(object): class DeadIO(object): - """Klasse, mit der ersetzte IOs verwaltet werden.""" __slots__ = "__deadio" def __init__(self, deadio): - """Instantiierung der DeadIO-Klasse. - @param deadio IO, der ersetzt wurde""" + """ + Instantiierung der DeadIO-Klasse. + + :param deadio: IO, der ersetzt wurde + """ self.__deadio = deadio - def replace_io(self, name, frm, **kwargs): - """Stellt Funktion fuer weiter Bit-Ersetzungen bereit. - @see #IntIOReplaceable.replace_io replace_io(...)""" + def replace_io(self, name: str, frm: str, **kwargs) -> None: + """ + Stellt Funktion fuer weiter Bit-Ersetzungen bereit. + + :ref: :func:IntIOReplaceable.replace_io() + """ self.__deadio.replace_io(name, frm, **kwargs) _parentdevice = property(lambda self: None) class IOBase(object): - - """Basisklasse fuer alle IO-Objekte. + """ + Basisklasse fuer alle IO-Objekte. Die Basisfunktionalitaet ermoeglicht das Lesen und Schreiben der Werte als oder . Dies entscheidet sich bei der @@ -259,24 +284,23 @@ class IOBase(object): Diese Klasse dient als Basis fuer andere IO-Klassen mit denen die Werte auch als verwendet werden koennen. - """ __slots__ = "__bit_ioctl_off", "__bit_ioctl_on", \ - "_bitaddress", "_bitlength", "_byteorder", "_defaultvalue", \ - "_iotype", "_length", "_name", "_parentdevice", \ - "_signed", "_slc_address", "bmk", "export" + "_bitaddress", "_bitlength", "_byteorder", "_defaultvalue", \ + "_iotype", "_length", "_name", "_parentdevice", \ + "_signed", "_slc_address", "bmk", "export" - def __init__(self, parentdevice, valuelist, iotype, byteorder, signed): - """Instantiierung der IOBase-Klasse. + def __init__(self, parentdevice, valuelist: list, iotype: int, byteorder: str, signed: bool): + """ + Instantiierung der IOBase-Klasse. - @param parentdevice Parentdevice auf dem der IO liegt - @param valuelist Datenliste fuer Instantiierung + :param parentdevice: Parentdevice auf dem der IO liegt + :param valuelist: Datenliste fuer Instantiierung ["name","defval","bitlen","startaddrdev",exp,"idx","bmk","bitaddr"] - @param iotype Wert - @param byteorder Byteorder 'little'/'big' fuer Berechnung - @param sigend Intberechnung mit Vorzeichen durchfuehren - + :param iotype: Wert + :param byteorder: Byteorder 'little'/'big' fuer Berechnung + :param signed: Intberechnung mit Vorzeichen durchfuehren """ # ["name","defval","bitlen","startaddrdev",exp,"idx","bmk","bitaddr"] # [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 ] @@ -358,8 +382,11 @@ class IOBase(object): 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""" + """ + -Wert der Klasse. + + :return: Nur False wenn False oder 0 sonst True + """ if self._bitaddress >= 0: int_byte = int.from_bytes( self._parentdevice._ba_devdata[self._slc_address], @@ -368,28 +395,34 @@ class IOBase(object): return bool(int_byte & 1 << self._bitaddress) else: return self._parentdevice._ba_devdata[self._slc_address] != \ - bytearray(self._length) + bytearray(self._length) def __len__(self): - """Gibt die Bytelaenge des IO zurueck. - @return Bytelaenge des IO - 0 bei BITs""" + """ + Gibt die Bytelaenge des IO zurueck. + + :return: Bytelaenge des IO - 0 bei BITs + """ return 0 if self._bitaddress > 0 else self._length def __str__(self): - """-Wert der Klasse. - @return Namen des IOs""" + """ + -Wert der Klasse. + + :return: Namen des IOs + """ return self._name - def __reg_xevent(self, func, delay, edge, as_thread, overwrite, prefire): - """Verwaltet reg_event und reg_timerevent. - - @param func Funktion die bei Aenderung aufgerufen werden soll - @param delay Verzoegerung in ms zum Ausloesen - auch bei Wertaenderung - @param edge Ausfuehren bei RISING, FALLING or BOTH Wertaenderung - @param as_thread Bei True, Funktion als EventCallback-Thread ausfuehren - @param overwrite Wenn True, wird Event bei ueberschrieben - @param prefire Ausloesen mit aktuellem Wert, wenn mainloop startet + def __reg_xevent(self, func, delay: int, edge: int, as_thread: bool, overwrite: bool, prefire: bool) -> None: + """ + Verwaltet reg_event und reg_timerevent. + :param func: Funktion die bei Aenderung aufgerufen werden soll + :param delay: Verzoegerung in ms zum Ausloesen - auch bei Wertaenderung + :param edge: Ausfuehren bei RISING, FALLING or BOTH Wertaenderung + :param as_thread: Bei True, Funktion als EventCallback-Thread ausfuehren + :param overwrite: Wenn True, wird Event bei ueberschrieben + :param prefire: Ausloesen mit aktuellem Wert, wenn mainloop startet """ # Prüfen ob Funktion callable ist if not callable(func): @@ -449,29 +482,44 @@ class IOBase(object): IOEvent(func, edge, as_thread, delay, overwrite, prefire) ) - def _get_address(self): - """Gibt die absolute Byteadresse im Prozessabbild zurueck. - @return Absolute Byteadresse""" + def _get_address(self) -> int: + """ + Gibt die absolute Byteadresse im Prozessabbild zurueck. + + :return: Absolute Byteadresse + """ return self._parentdevice._offset + self._slc_address.start - def _get_byteorder(self): - """Gibt konfigurierte Byteorder zurueck. - @return Byteorder""" + def _get_byteorder(self) -> str: + """ + Gibt konfigurierte Byteorder zurueck. + + :return: Byteorder + """ return self._byteorder - def _get_iotype(self): - """Gibt io type zurueck. - @return io type""" + def _get_iotype(self) -> int: + """ + Gibt io type zurueck. + + :return: io type + """ return self._iotype def get_defaultvalue(self): - """Gibt die Defaultvalue von piCtory zurueck. - @return Defaultvalue als oder """ + """ + Gibt die Defaultvalue von piCtory zurueck. + + :return: Defaultvalue als oder + """ return self._defaultvalue def get_value(self): - """Gibt den Wert des IOs zurueck. - @return IO-Wert als oder """ + """ + Gibt den Wert des IOs zurueck. + + :return: IO-Wert als oder + """ if self._bitaddress >= 0: int_byte = int.from_bytes( self._parentdevice._ba_devdata[self._slc_address], @@ -483,7 +531,8 @@ class IOBase(object): def reg_event( self, func, delay=0, edge=BOTH, as_thread=False, prefire=False): - """Registriert fuer IO ein Event bei der Eventueberwachung. + """ + Registriert fuer IO ein Event bei der Eventueberwachung. Die uebergebene Funktion wird ausgefuehrt, wenn sich der IO Wert aendert. Mit Angabe von optionalen Parametern kann das @@ -492,17 +541,17 @@ class IOBase(object): HINWEIS: Die delay-Zeit muss in die .cycletime passen, ist dies nicht der Fall, wird IMMER aufgerundet! - @param func Funktion die bei Aenderung aufgerufen werden soll - @param delay Verzoegerung in ms zum Ausloesen wenn Wert gleich bleibt - @param edge Ausfuehren bei RISING, FALLING or BOTH Wertaenderung - @param as_thread Bei True, Funktion als EventCallback-Thread ausfuehren - @param prefire Ausloesen mit aktuellem Wert, wenn mainloop startet - + :param func: Funktion die bei Aenderung aufgerufen werden soll + :param delay; Verzoegerung in ms zum Ausloesen wenn Wert gleich bleibt + :param edge: Ausfuehren bei RISING, FALLING or BOTH Wertaenderung + :param as_thread: Bei True, Funktion als EventCallback-Thread ausfuehren + :param prefire: Ausloesen mit aktuellem Wert, wenn mainloop startet """ self.__reg_xevent(func, delay, edge, as_thread, True, prefire) def reg_timerevent(self, func, delay, edge=BOTH, as_thread=False): - """Registriert fuer IO einen Timer, welcher nach delay func ausfuehrt. + """ + Registriert fuer IO einen Timer, welcher nach delay func ausfuehrt. Der Timer wird gestartet, wenn sich der IO Wert aendert und fuehrt die uebergebene Funktion aus - auch wenn sich der IO Wert in der @@ -514,17 +563,19 @@ class IOBase(object): HINWEIS: Die delay-Zeit muss in die .cycletime passen, ist dies nicht der Fall, wird IMMER aufgerundet! - @param func Funktion die bei Aenderung aufgerufen werden soll - @param delay Verzoegerung in ms zum Ausloesen - auch bei Wertaenderung - @param edge Ausfuehren bei RISING, FALLING or BOTH Wertaenderung - @param as_thread Bei True, Funktion als EventCallback-Thread ausfuehren - + :param func: Funktion die bei Aenderung aufgerufen werden soll + :param delay: Verzoegerung in ms zum Ausloesen - auch bei Wertaenderung + :param edge: Ausfuehren bei RISING, FALLING or BOTH Wertaenderung + :param as_thread: Bei True, Funktion als EventCallback-Thread ausfuehren """ self.__reg_xevent(func, delay, edge, as_thread, False, False) - def set_value(self, value): - """Setzt den Wert des IOs. - @param value IO-Wert als oder """ + def set_value(self, value) -> None: + """ + Setzt den Wert des IOs. + + :param value: IO-Wert als oder + """ if self._iotype == INP: if self._parentdevice._modio._simulator: raise RuntimeError( @@ -643,12 +694,12 @@ class IOBase(object): else: self._parentdevice._ba_devdata[self._slc_address] = value - def unreg_event(self, func=None, edge=None): - """Entfernt ein Event aus der Eventueberwachung. - - @param func Nur Events mit angegebener Funktion - @param edge Nur Events mit angegebener Funktion und angegebener Edge + def unreg_event(self, func=None, edge=None) -> None: + """ + Entfernt ein Event aus der Eventueberwachung. + :param func: Nur Events mit angegebener Funktion + :param edge: Nur Events mit angegebener Funktion und angegebener Edge """ if self in self._parentdevice._dict_events: if func is None: @@ -659,7 +710,6 @@ class IOBase(object): for regfunc in self._parentdevice._dict_events[self]: if regfunc.func != func or edge is not None \ and regfunc.edge != edge: - newlist.append(regfunc) # Wenn Funktionen übrig bleiben, diese übernehmen @@ -669,8 +719,9 @@ class IOBase(object): else: del self._parentdevice._dict_events[self] - def wait(self, edge=BOTH, exitevent=None, okvalue=None, timeout=0): - """Wartet auf Wertaenderung eines IOs. + def wait(self, edge=BOTH, exitevent=None, okvalue=None, timeout=0) -> int: + """ + Wartet auf Wertaenderung eines IOs. Die Wertaenderung wird immer uerberprueft, wenn fuer Devices mit aktiviertem autorefresh neue Daten gelesen wurden. @@ -696,19 +747,18 @@ class IOBase(object): der autorefresh Funktion berechnet, entspricht also nicht exakt den angegeben Millisekunden! Es wird immer nach oben gerundet!) - @param edge Flanke RISING, FALLING, BOTH die eintreten muss - @param exitevent fuer vorzeitiges Beenden - @param okvalue IO-Wert, bei dem das Warten sofort beendet wird - @param timeout Zeit in ms nach der abgebrochen wird - @return erfolgreich Werte <= 0 - - Erfolgreich gewartet - Wert 0: IO hat den Wert gewechselt - Wert -1: okvalue stimmte mit IO ueberein - - Fehlerhaft gewartet - Wert 1: exitevent wurde gesetzt - Wert 2: timeout abgelaufen - Wert 100: Devicelist.exit() wurde aufgerufen - + :param edge: Flanke RISING, FALLING, BOTH die eintreten muss + :param exitevent: fuer vorzeitiges Beenden + :param okvalue: IO-Wert, bei dem das Warten sofort beendet wird + :param timeout: Zeit in ms nach der abgebrochen wird + :return: erfolgreich Werte <= 0 + * Erfolgreich gewartet + ** Wert 0: IO hat den Wert gewechselt + ** Wert -1: okvalue stimmte mit IO ueberein + * Fehlerhaft gewartet + ** Wert 1: exitevent wurde gesetzt + ** Wert 2: timeout abgelaufen + ** Wert 100: Devicelist.exit() wurde aufgerufen """ # Prüfen ob Device in autorefresh ist if not self._parentdevice._selfupdate: @@ -791,68 +841,89 @@ class IOBase(object): class IntIO(IOBase): - - """Klasse fuer den Zugriff auf die Daten mit Konvertierung in int. + """ + Klasse fuer den Zugriff auf die Daten mit Konvertierung in int. Diese Klasse erweitert die Funktion von um Funktionen, ueber die mit Werten gearbeitet werden kann. Fuer die Umwandlung koennen 'Byteorder' (Default 'little') und 'signed' (Default False) als Parameter gesetzt werden. - @see #IOBase IOBase + :ref:`IOBase` """ __slots__ = () def __int__(self): - """Gibt IO-Wert zurueck mit Beachtung byteorder/signed. - @return IO-Wert als """ + """ + Gibt IO-Wert zurueck mit Beachtung byteorder/signed. + + :return: IO-Wert als + """ return int.from_bytes( self._parentdevice._ba_devdata[self._slc_address], byteorder=self._byteorder, signed=self._signed ) - def _get_signed(self): - """Ruft ab, ob der Wert Vorzeichenbehaftet behandelt werden soll. - @return True, wenn Vorzeichenbehaftet""" + def _get_signed(self) -> bool: + """ + Ruft ab, ob der Wert Vorzeichenbehaftet behandelt werden soll. + + :return: True, wenn Vorzeichenbehaftet + """ return self._signed - def _set_byteorder(self, value): - """Setzt Byteorder fuer Umwandlung. - @param value 'little' or 'big'""" + def _set_byteorder(self, value: str) -> None: + """ + Setzt Byteorder fuer Umwandlung. + + :param value: 'little' or 'big' + """ if not (value == "little" or value == "big"): raise ValueError("byteorder must be 'little' or 'big'") if self._byteorder != value: self._byteorder = value self._defaultvalue = self._defaultvalue[::-1] - def _set_signed(self, value): - """Left fest, ob der Wert Vorzeichenbehaftet behandelt werden soll. - @param value True, wenn mit Vorzeichen behandel""" + def _set_signed(self, value: bool) -> None: + """ + Left fest, ob der Wert Vorzeichenbehaftet behandelt werden soll. + + :param value: True, wenn mit Vorzeichen behandel + """ if type(value) != bool: raise TypeError("signed must be True or False") self._signed = value - def get_intdefaultvalue(self): - """Gibt die Defaultvalue als zurueck. - @return Defaultvalue""" + def get_intdefaultvalue(self) -> int: + """ + Gibt die Defaultvalue als zurueck. + + :return: Defaultvalue + """ return int.from_bytes( self._defaultvalue, byteorder=self._byteorder, signed=self._signed ) - def get_intvalue(self): - """Gibt IO-Wert zurueck mit Beachtung byteorder/signed. - @return IO-Wert als """ + def get_intvalue(self) -> int: + """ + Gibt IO-Wert zurueck mit Beachtung byteorder/signed. + + :return: IO-Wert als + """ return int.from_bytes( self._parentdevice._ba_devdata[self._slc_address], byteorder=self._byteorder, signed=self._signed ) - def set_intvalue(self, value): - """Setzt IO mit Beachtung byteorder/signed. - @param value Wert""" + def set_intvalue(self, value: int) -> None: + """ + Setzt IO mit Beachtung byteorder/signed. + + :param value: Wert + """ if type(value) == int: self.set_value(value.to_bytes( self._length, @@ -872,19 +943,18 @@ class IntIO(IOBase): class IntIOCounter(IntIO): - """Erweitert die IntIO-Klasse um die .reset() Funktion fuer Counter.""" - __slots__ = ("__ioctl_arg") + __slots__ = ("__ioctl_arg", ) def __init__( self, counter_id, parentdevice, valuelist, iotype, byteorder, signed): - """Instantiierung der IntIOCounter-Klasse. - - @param counter_id ID fuer den Counter, zu dem der IO gehoert (0-15) - @see #IOBase.__init__ IOBase.__init__(...) + """ + Instantiierung der IntIOCounter-Klasse. + :param counter_id: ID fuer den Counter, zu dem der IO gehoert (0-15) + :ref: :func:`IOBase.__init__(...)` """ if not isinstance(counter_id, int): raise TypeError("counter_id must be ") @@ -912,7 +982,7 @@ class IntIOCounter(IntIO): # Basisklasse laden super().__init__(parentdevice, valuelist, iotype, byteorder, signed) - def reset(self): + def reset(self) -> None: """Setzt den Counter des Inputs zurueck.""" if self._parentdevice._modio._monitoring: raise RuntimeError( @@ -957,13 +1027,13 @@ class IntIOCounter(IntIO): class IntIOReplaceable(IntIO): - """Erweitert die IntIO-Klasse um die .replace_io Funktion.""" __slots__ = () - def replace_io(self, name, frm, **kwargs): - """Ersetzt bestehenden IO mit Neuem. + def replace_io(self, name: str, frm: str, **kwargs) -> None: + """ + Ersetzt bestehenden IO mit Neuem. Wenn die kwargs fuer byteorder und defaultvalue nicht angegeben werden, uebernimmt das System die Daten aus dem ersetzten IO. @@ -983,9 +1053,9 @@ class IntIOReplaceable(IntIO): der urspruenglige IO hat, werden die nachfolgenden IOs ebenfalls verwendet und entfernt. - @param name Name des neuen Inputs - @param frm struct formatierung (1 Zeichen) oder 'ANZAHLs' z.B. '8s' - @param kwargs Weitere Parameter: + :param name: Name des neuen Inputs + :param frm: struct formatierung (1 Zeichen) oder 'ANZAHLs' z.B. '8s' + :param kwargs: Weitere Parameter: - bmk: interne Bezeichnung fuer IO - bit: Registriert IO als am angegebenen Bit im Byte - byteorder: Byteorder fuer den IO, Standardwert=little @@ -995,10 +1065,7 @@ class IntIOReplaceable(IntIO): - edge: Event ausfuehren bei RISING, FALLING or BOTH Wertaenderung - as_thread: Fuehrt die event-Funktion als RevPiCallback-Thread aus - prefire: Ausloesen mit aktuellem Wert, wenn mainloop startet - @see Python3 struct - + `https://docs.python.org/3/library/struct.html#format-characters` """ # StructIO erzeugen io_new = StructIO( @@ -1023,30 +1090,29 @@ class IntIOReplaceable(IntIO): class StructIO(IOBase): - - """Klasse fuer den Zugriff auf Daten ueber ein definierten struct. + """ + Klasse fuer den Zugriff auf Daten ueber ein definierten struct. Sie stellt ueber struct die Werte in der gewuenschten Formatierung bereit. Der struct-Formatwert wird bei der Instantiierung festgelegt. - @see #IOBase IOBase - + :ref:`IOBase` """ __slots__ = "__frm", "_parentio_address", "_parentio_defaultvalue", \ - "_parentio_length", "_parentio_name" + "_parentio_length", "_parentio_name" - def __init__(self, parentio, name, frm, **kwargs): - """Erstellt einen IO mit struct-Formatierung. + def __init__(self, parentio, name: str, frm: str, **kwargs): + """ + Erstellt einen IO mit struct-Formatierung. - @param parentio ParentIO Objekt, welches ersetzt wird - @param name Name des neuen IO - @param frm struct formatierung (1 Zeichen) oder 'ANZAHLs' z.B. '8s' - @param kwargs Weitere Parameter: + :param parentio: ParentIO Objekt, welches ersetzt wird + :param name: Name des neuen IO + :param frm: struct formatierung (1 Zeichen) oder 'ANZAHLs' z.B. '8s' + :param kwargs: Weitere Parameter: - bmk: Bezeichnung fuer IO - bit: Registriert IO als am angegebenen Bit im Byte - byteorder: Byteorder fuer IO, Standardwert vom ersetzten IO - defaultvalue: Standardwert fuer IO, Standard vom ersetzten IO - """ # Structformatierung prüfen regex = rematch("^([0-9]*s|[cbB?hHiIlLqQefd])$", frm) @@ -1118,40 +1184,54 @@ class StructIO(IOBase): parentio._parentdevice._dict_slc[parentio._iotype].start and self._slc_address.stop <= parentio._parentdevice._dict_slc[parentio._iotype].stop): - raise BufferError( "registered value does not fit process image scope" ) - def _get_frm(self): - """Ruft die struct Formatierung ab. - @return struct Formatierung""" + def _get_frm(self) -> str: + """ + Ruft die struct Formatierung ab. + + :return: struct Formatierung + """ return self.__frm[1:] - def _get_signed(self): - """Ruft ab, ob der Wert Vorzeichenbehaftet behandelt werden soll. - @return True, wenn Vorzeichenbehaftet""" + def _get_signed(self) -> bool: + """ + Ruft ab, ob der Wert Vorzeichenbehaftet behandelt werden soll. + + :return: True, wenn Vorzeichenbehaftet + """ return self._signed def get_structdefaultvalue(self): - """Gibt die Defaultvalue mit struct Formatierung zurueck. - @return Defaultvalue vom Typ der struct-Formatierung""" + """ + Gibt die Defaultvalue mit struct Formatierung zurueck. + + :return: Defaultvalue vom Typ der struct-Formatierung + """ if self._bitaddress >= 0: return self._defaultvalue else: return struct.unpack(self.__frm, self._defaultvalue)[0] def get_structvalue(self): - """Gibt den Wert mit struct Formatierung zurueck. - @return Wert vom Typ der struct-Formatierung""" + """ + Gibt den Wert mit struct Formatierung zurueck. + + :return: Wert vom Typ der struct-Formatierung + """ if self._bitaddress >= 0: return self.get_value() else: return struct.unpack(self.__frm, self.get_value())[0] def set_structvalue(self, value): - """Setzt den Wert mit struct Formatierung. - @param value Wert vom Typ der struct-Formatierung""" + """ + Setzt den Wert mit struct Formatierung. + + :param value: Wert vom Typ der struct-Formatierung + """ if self._bitaddress >= 0: self.set_value(value) else: