Docstrings optimieren 1

This commit is contained in:
2019-10-20 22:36:09 +02:00
parent 56da8e4cf6
commit 10af9a01d5
16 changed files with 828 additions and 587 deletions

3
.idea/dictionaries/akira.xml generated Normal file
View File

@@ -0,0 +1,3 @@
<component name="ProjectDictionaryState">
<dictionary name="akira" />
</component>

View File

@@ -1,5 +1,6 @@
<component name="InspectionProjectProfileManager"> <component name="InspectionProjectProfileManager">
<settings> <settings>
<option name="PROJECT_PROFILE" value="Default" />
<option name="USE_PROJECT_PROFILE" value="false" /> <option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" /> <version value="1.0" />
</settings> </settings>

4
.idea/revpimodio2.iml generated
View File

@@ -1,7 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4"> <module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager"> <component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" /> <content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/revpimodio2" isTestSource="false" />
</content>
<orderEntry type="jdk" jdkName="Python 3.6" jdkType="Python SDK" /> <orderEntry type="jdk" jdkName="Python 3.6" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
</component> </component>

7
docs/revpimodio2.app.rst Normal file
View File

@@ -0,0 +1,7 @@
revpimodio2\.app module
=======================
.. automodule:: revpimodio2.app
:members:
:undoc-members:
:show-inheritance:

View File

@@ -0,0 +1,7 @@
revpimodio2\.device module
==========================
.. automodule:: revpimodio2.device
:members:
:undoc-members:
:show-inheritance:

View File

@@ -0,0 +1,7 @@
revpimodio2\.helper module
==========================
.. automodule:: revpimodio2.helper
:members:
:undoc-members:
:show-inheritance:

7
docs/revpimodio2.io.rst Normal file
View File

@@ -0,0 +1,7 @@
revpimodio2\.io module
======================
.. automodule:: revpimodio2.io
:members:
:undoc-members:
:show-inheritance:

View File

@@ -0,0 +1,7 @@
revpimodio2\.modio module
=========================
.. automodule:: revpimodio2.modio
:members:
:undoc-members:
:show-inheritance:

View File

@@ -0,0 +1,7 @@
revpimodio2\.netio module
=========================
.. automodule:: revpimodio2.netio
:members:
:undoc-members:
:show-inheritance:

View File

@@ -4,62 +4,15 @@ revpimodio2 package
Submodules Submodules
---------- ----------
revpimodio2\.app module .. toctree::
-----------------------
.. 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:
revpimodio2.app
revpimodio2.device
revpimodio2.helper
revpimodio2.io
revpimodio2.modio
revpimodio2.netio
revpimodio2.summary
Module contents Module contents
--------------- ---------------

View File

@@ -0,0 +1,7 @@
revpimodio2\.summary module
===========================
.. automodule:: revpimodio2.summary
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""Stellt alle Klassen fuer den RevolutionPi zur Verfuegung. """
Stellt alle Klassen fuer den RevolutionPi zur Verfuegung.
Webpage: https://revpimodio.org/ 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. Mit den definierten Namen greift man direkt auf die gewuenschten Daten zu.
Auf alle IOs kann der Benutzer Funktionen als Events registrieren. Diese Auf alle IOs kann der Benutzer Funktionen als Events registrieren. Diese
fuehrt das Modul bei Datenaenderung aus. fuehrt das Modul bei Datenaenderung aus.
""" """
__all__ = [ __all__ = [
"RevPiModIO", "RevPiModIOSelected", "RevPiModIODriver", "RevPiModIO", "RevPiModIODriver", "RevPiModIOSelected",
"RevPiNetIO", "RevPiNetIOSelected", "RevPiNetIODriver", "RevPiNetIO", "RevPiNetIODriver", "RevPiNetIOSelected",
"Cycletools", "Cycletools",
] ]
__author__ = "Sven Sager <akira@revpimodio.org>" __author__ = "Sven Sager <akira@revpimodio.org>"
@@ -36,27 +36,25 @@ MEM = 302
class DeviceNotFoundError(Exception): class DeviceNotFoundError(Exception):
"""Fehler wenn ein Device nicht gefunden wird.""" """Fehler wenn ein Device nicht gefunden wird."""
pass pass
def acheck(check_type, **kwargs): def acheck(check_type, **kwargs) -> None:
"""Check type of given arguments. """
Check type of given arguments.
Use the argument name as keyword and the argument itself as value. Use the argument name as keyword and the argument itself as value.
@param check_type Type to check :param check_type: Type to check
@param kwargs Arguments to check :param kwargs: Arguments to check
""" """
for var_name in kwargs: for var_name in kwargs:
none_okay = var_name.endswith("_noneok") none_okay = var_name.endswith("_noneok")
if not (isinstance(kwargs[var_name], check_type) or if not (isinstance(kwargs[var_name], check_type) or
none_okay and kwargs[var_name] is None): none_okay and kwargs[var_name] is None):
msg = "Argument '{0}' must be {1}{2}".format( msg = "Argument '{0}' must be {1}{2}".format(
var_name.rstrip("_noneok"), str(check_type), var_name.rstrip("_noneok"), str(check_type),
" or <class 'NoneType'>" if none_okay else "" " or <class 'NoneType'>" if none_okay else ""
@@ -64,14 +62,14 @@ def acheck(check_type, **kwargs):
raise TypeError(msg) raise TypeError(msg)
def consttostr(value): def consttostr(value) -> str:
"""Gibt <class 'str'> fuer Konstanten zurueck. """
Gibt <class 'str'> fuer Konstanten zurueck.
Diese Funktion ist erforderlich, da enum in Python 3.2 nicht existiert. Diese Funktion ist erforderlich, da enum in Python 3.2 nicht existiert.
@param value Konstantenwert :param value: Konstantenwert
@return <class 'str'> Name der Konstanten :return: <class 'str'> Name der Konstanten
""" """
if value == 0: if value == 0:
return "OFF" return "OFF"
@@ -97,5 +95,5 @@ def consttostr(value):
# Benötigte Klassen importieren # Benötigte Klassen importieren
from .helper import Cycletools from .helper import Cycletools
from .modio import RevPiModIO, RevPiModIOSelected, RevPiModIODriver from .modio import RevPiModIO, RevPiModIODriver, RevPiModIOSelected
from .netio import RevPiNetIO, RevPiNetIOSelected, RevPiNetIODriver from .netio import RevPiNetIO, RevPiNetIODriver, RevPiNetIOSelected

View File

@@ -1,27 +1,36 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""Bildet die App Sektion von piCtory ab.""" """Bildet die App Sektion von piCtory ab."""
from time import strptime
__author__ = "Sven Sager" __author__ = "Sven Sager"
__copyright__ = "Copyright (C) 2018 Sven Sager" __copyright__ = "Copyright (C) 2018 Sven Sager"
__license__ = "LGPLv3" __license__ = "LGPLv3"
from time import strptime
class App(object): class App(object):
"""Bildet die App Sektion der config.rsc ab.""" """Bildet die App Sektion der config.rsc ab."""
__slots__ = "name", "version", "language", "layout", "savets" __slots__ = "name", "version", "language", "layout", "savets"
def __init__(self, app): def __init__(self, app):
"""Instantiiert die App-Klasse. """
@param app piCtory Appinformationen""" Instantiiert die App-Klasse.
:param app: piCtory Appinformationen
"""
self.name = app["name"] self.name = app["name"]
"""Name of creating app"""
self.version = app["version"] self.version = app["version"]
"""Version of creating app"""
self.language = app["language"] self.language = app["language"]
"""Language of creating app"""
# Speicherungszeitpunkt laden, wenn vorhanden # Speicherungszeitpunkt laden, wenn vorhanden
self.savets = app.get("saveTS", None) self.savets = app.get("saveTS", None)
"""Timestamp of configuraiton"""
if self.savets is not None: if self.savets is not None:
try: try:
self.savets = strptime(self.savets, "%Y%m%d%H%M%S") self.savets = strptime(self.savets, "%Y%m%d%H%M%S")

View File

@@ -1,15 +1,15 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""Modul fuer die Verwaltung der Devices.""" """Modul fuer die Verwaltung der Devices."""
from threading import Event, Lock, Thread
from .helper import ProcimgWriter
__author__ = "Sven Sager" __author__ = "Sven Sager"
__copyright__ = "Copyright (C) 2018 Sven Sager" __copyright__ = "Copyright (C) 2018 Sven Sager"
__license__ = "LGPLv3" __license__ = "LGPLv3"
from threading import Thread, Event, Lock
from .helper import ProcimgWriter
class DeviceList(object): class DeviceList(object):
"""Basisklasse fuer direkten Zugriff auf Device Objekte.""" """Basisklasse fuer direkten Zugriff auf Device Objekte."""
def __init__(self): def __init__(self):
@@ -17,9 +17,12 @@ class DeviceList(object):
self.__dict_position = {} self.__dict_position = {}
def __contains__(self, key): def __contains__(self, key):
"""Prueft ob Device existiert. """
@param key DeviceName <class 'str'> / Positionsnummer <class 'int'> Prueft ob Device existiert.
@return True, wenn Device vorhanden"""
:param key: DeviceName <class 'str'> / Positionsnummer <class 'int'>
:return: True, wenn Device vorhanden
"""
if type(key) == int: if type(key) == int:
return key in self.__dict_position return key in self.__dict_position
elif type(key) == str: elif type(key) == str:
@@ -28,9 +31,12 @@ class DeviceList(object):
return key in self.__dict_position.values() return key in self.__dict_position.values()
def __delattr__(self, key, delcomplete=True): def __delattr__(self, key, delcomplete=True):
"""Entfernt angegebenes Device. """
@param key Device zum entfernen Entfernt angegebenes Device.
@param delcomplete Wenn True wird Device komplett entfernt"""
:param key: Device zum entfernen
:param delcomplete: Wenn True wird Device komplett entfernt
"""
if delcomplete: if delcomplete:
# Device finden # Device finden
if type(key) == int: if type(key) == int:
@@ -51,16 +57,22 @@ class DeviceList(object):
object.__delattr__(self, key) object.__delattr__(self, key)
def __delitem__(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): if isinstance(key, Device):
key = key._position key = key._position
self.__delattr__(key) self.__delattr__(key)
def __getitem__(self, key): def __getitem__(self, key):
"""Gibt angegebenes Device zurueck. """
@param key DeviceName <class 'str'> / Positionsnummer <class 'int'> Gibt angegebenes Device zurueck.
@return Gefundenes <class 'Device'>-Objekt"""
:param key: DeviceName <class 'str'> / Positionsnummer <class 'int'>
:return: Gefundenes <class 'Device'>-Objekt
"""
if type(key) == int: if type(key) == int:
if key not in self.__dict_position: if key not in self.__dict_position:
raise IndexError("no device on position {0}".format(key)) raise IndexError("no device on position {0}".format(key))
@@ -69,26 +81,33 @@ class DeviceList(object):
return getattr(self, key) return getattr(self, key)
def __iter__(self): def __iter__(self):
"""Gibt Iterator aller Devices zurueck. """
Gibt Iterator aller Devices zurueck.
Die Reihenfolge ist nach Position im Prozessabbild sortiert und nicht Die Reihenfolge ist nach Position im Prozessabbild sortiert und nicht
nach Positionsnummer (Dies entspricht der Positionierung aus piCtory)! nach Positionsnummer (Dies entspricht der Positionierung aus piCtory)!
@return <class 'iter'> aller Devices""" :return: <class 'iter'> aller Devices
"""
for dev in sorted( for dev in sorted(
self.__dict_position, self.__dict_position,
key=lambda key: self.__dict_position[key]._offset): key=lambda key: self.__dict_position[key]._offset):
yield self.__dict_position[dev] yield self.__dict_position[dev]
def __len__(self): 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) return len(self.__dict_position)
def __setattr__(self, key, value): def __setattr__(self, key, value):
"""Setzt Attribute nur wenn Device. """
@param key Attributname Setzt Attribute nur wenn Device.
@param value Attributobjekt"""
:param key: Attributname
:param value: Attributobjekt
"""
if isinstance(value, Device): if isinstance(value, Device):
object.__setattr__(self, key, value) object.__setattr__(self, key, value)
self.__dict_position[value._position] = value self.__dict_position[value._position] = value
@@ -97,13 +116,12 @@ class DeviceList(object):
class Device(object): class Device(object):
"""
"""Basisklasse fuer alle Device-Objekte. Basisklasse fuer alle Device-Objekte.
Die Basisfunktionalitaet generiert bei Instantiierung alle IOs und Die Basisfunktionalitaet generiert bei Instantiierung alle IOs und
erweitert den Prozessabbildpuffer um die benoetigten Bytes. Sie verwaltet erweitert den Prozessabbildpuffer um die benoetigten Bytes. Sie verwaltet
ihren Prozessabbildpuffer und sorgt fuer die Aktualisierung der IO-Werte. ihren Prozessabbildpuffer und sorgt fuer die Aktualisierung der IO-Werte.
""" """
__slots__ = "__my_io_list", "_ba_devdata", "_ba_datacp", \ __slots__ = "__my_io_list", "_ba_devdata", "_ba_datacp", \
@@ -114,12 +132,12 @@ class Device(object):
"guid", "id", "inpvariant", "outvariant", "type" "guid", "id", "inpvariant", "outvariant", "type"
def __init__(self, parentmodio, dict_device, simulator=False): def __init__(self, parentmodio, dict_device, simulator=False):
"""Instantiierung der Device-Klasse. """
Instantiierung der Device-Klasse.
@param parent RevpiModIO parent object
@param dict_device <class 'dict'> fuer dieses Device aus piCotry
@param simulator: Laedt das Modul als Simulator und vertauscht IOs
:param parentmodio: RevpiModIO parent object
:param dict_device: <class 'dict'> fuer dieses Device aus piCotry
:param simulator: Laedt das Modul als Simulator und vertauscht IOs
""" """
self._modio = parentmodio self._modio = parentmodio
@@ -187,14 +205,20 @@ class Device(object):
self._update_my_io_list() self._update_my_io_list()
def __bytes__(self): def __bytes__(self):
"""Gibt alle Daten des Devices als <class 'bytes'> zurueck. """
@return Devicedaten als <class 'bytes'>""" Gibt alle Daten des Devices als <class 'bytes'> zurueck.
:return: Devicedaten als <class 'bytes'>
"""
return bytes(self._ba_devdata) return bytes(self._ba_devdata)
def __contains__(self, key): def __contains__(self, key):
"""Prueft ob IO auf diesem Device liegt. """
@param key IO-Name <class 'str'> / IO-Bytenummer <class 'int'> Prueft ob IO auf diesem Device liegt.
@return True, wenn IO auf Device vorhanden"""
:param key: IO-Name <class 'str'> / IO-Bytenummer <class 'int'>
:return: True, wenn IO auf Device vorhanden
"""
if isinstance(key, IOBase): if isinstance(key, IOBase):
# Umwandlung für key # Umwandlung für key
key = key._name key = key._name
@@ -210,51 +234,66 @@ class Device(object):
and getattr(self._modio.io, key)._parentdevice == self and getattr(self._modio.io, key)._parentdevice == self
def __getitem__(self, key): def __getitem__(self, key):
"""Gibt IO an angegebener Stelle zurueck. """
@param key Index des IOs auf dem device als <class 'int'> Gibt IO an angegebener Stelle zurueck.
@return Gefundenes IO-Objekt"""
:param key: Index des IOs auf dem device als <class 'int'>
:return: Gefundenes IO-Objekt
"""
return self.__my_io_list[key] return self.__my_io_list[key]
def __int__(self): def __int__(self):
"""Gibt die Positon im RevPi Bus zurueck. """
@return Positionsnummer""" Gibt die Positon im RevPi Bus zurueck.
:return: Positionsnummer
"""
return self._position return self._position
def __iter__(self): def __iter__(self):
"""Gibt Iterator aller IOs zurueck. """
@return <class 'iter'> aller IOs""" Gibt Iterator aller IOs zurueck.
:return: <class 'iter'> aller IOs
"""
return self.__getioiter(self._slc_devoff, None) return self.__getioiter(self._slc_devoff, None)
def __len__(self): def __len__(self):
"""Gibt Anzahl der Bytes zurueck, die dieses Device belegt. """
@return <class 'int'>""" Gibt Anzahl der Bytes zurueck, die dieses Device belegt.
:return: <class 'int'>
"""
return self._length return self._length
def __str__(self): def __str__(self):
"""Gibt den Namen des Devices zurueck. """
@return Devicename""" Gibt den Namen des Devices zurueck.
:return: Devicename
"""
return self._name return self._name
def __getioiter(self, ioslc, export): def __getioiter(self, ioslc: slice, export):
"""Gibt <class 'iter'> mit allen IOs zurueck. """
Gibt <class 'iter'> mit allen IOs zurueck.
@param ioslc IO Abschnitt <class 'slice'>
@param export Filter fuer 'Export' Flag in piCtory
@return IOs als Iterator
:param ioslc: IO Abschnitt <class 'slice'>
:param export: Filter fuer 'Export' Flag in piCtory
:return: IOs als Iterator
""" """
for lst_io in self._modio.io[ioslc]: for lst_io in self._modio.io[ioslc]:
for io in lst_io: for io in lst_io:
if io is not None and (export is None or io.export == export): if io is not None and (export is None or io.export == export):
yield io yield io
def _buildio(self, dict_io, iotype): def _buildio(self, dict_io: dict, iotype: int) -> slice:
"""Erstellt aus der piCtory-Liste die IOs fuer dieses Device. """
Erstellt aus der piCtory-Liste die IOs fuer dieses Device.
@param dict_io <class 'dict'>-Objekt aus piCtory Konfiguration
@param iotype <class 'int'> Wert
@return <class 'slice'> mit Start und Stop Position dieser IOs
:param dict_io: <class 'dict'>-Objekt aus piCtory Konfiguration
:param iotype: <class 'int'> Wert
:return: <class 'slice'> mit Start und Stop Position dieser IOs
""" """
if len(dict_io) <= 0: if len(dict_io) <= 0:
return slice(0, 0) return slice(0, 0)
@@ -312,23 +351,32 @@ class Device(object):
"""Funktion zum ueberschreiben von abgeleiteten Klassen.""" """Funktion zum ueberschreiben von abgeleiteten Klassen."""
pass pass
def _get_offset(self): def _get_offset(self) -> int:
"""Gibt den Deviceoffset im Prozessabbild zurueck. """
@return Deviceoffset""" Gibt den Deviceoffset im Prozessabbild zurueck.
:return: Deviceoffset
"""
return self._offset return self._offset
def _get_producttype(self): def _get_producttype(self) -> int:
"""Gibt den Produkttypen des device zurueck. """
@return Deviceprodukttyp""" Gibt den Produkttypen des device zurueck.
:return: Deviceprodukttyp
"""
return self._producttype return self._producttype
def _update_my_io_list(self): def _update_my_io_list(self) -> None:
"""Erzeugt eine neue IO Liste fuer schnellen Zugriff.""" """Erzeugt eine neue IO Liste fuer schnellen Zugriff."""
self.__my_io_list = list(self.__iter__()) self.__my_io_list = list(self.__iter__())
def autorefresh(self, activate=True): def autorefresh(self, activate=True) -> None:
"""Registriert dieses Device fuer die automatische Synchronisierung. """
@param activate Default True fuegt Device zur Synchronisierung hinzu""" 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: if activate and self not in self._modio._lst_refresh:
# Daten bei Aufnahme direkt einlesen! # Daten bei Aufnahme direkt einlesen!
@@ -346,7 +394,6 @@ class Device(object):
# Thread starten, wenn er noch nicht läuft # Thread starten, wenn er noch nicht läuft
if not self._modio._imgwriter.is_alive(): if not self._modio._imgwriter.is_alive():
# Alte Einstellungen speichern # Alte Einstellungen speichern
imgrefresh = self._modio._imgwriter.refresh imgrefresh = self._modio._imgwriter.refresh
@@ -369,98 +416,97 @@ class Device(object):
if not self._modio._monitoring: if not self._modio._monitoring:
self._modio.writeprocimg(self) self._modio.writeprocimg(self)
def get_allios(self, export=None): def get_allios(self, export=None) -> list:
"""Gibt eine Liste aller Inputs und Outputs zurueck, keine MEMs. """
Gibt eine Liste aller Inputs und Outputs zurueck, keine MEMs.
Bleibt Parameter 'export' auf None werden alle Inputs und Outputs Bleibt Parameter 'export' auf None werden alle Inputs und Outputs
zurueckgegeben. Wird 'export' auf True/False gesetzt, werden nur Inputs zurueckgegeben. Wird 'export' auf True/False gesetzt, werden nur Inputs
und Outputs zurueckgegeben, bei denen der Wert 'Export' in piCtory und Outputs zurueckgegeben, bei denen der Wert 'Export' in piCtory
uebereinstimmt. uebereinstimmt.
@param export Nur In-/Outputs mit angegebenen 'Export' Wert in piCtory :param export: Nur In-/Outputs mit angegebenen 'Export' Wert in piCtory
@return <class 'list'> Input und Output, keine MEMs :return: <class 'list'> Input und Output, keine MEMs
""" """
return list(self.__getioiter( return list(self.__getioiter(
slice(self._slc_inpoff.start, self._slc_outoff.stop), export slice(self._slc_inpoff.start, self._slc_outoff.stop), export
)) ))
def get_inputs(self, export=None): def get_inputs(self, export=None) -> list:
"""Gibt eine Liste aller Inputs zurueck. """
Gibt eine Liste aller Inputs zurueck.
Bleibt Parameter 'export' auf None werden alle Inputs zurueckgegeben. Bleibt Parameter 'export' auf None werden alle Inputs zurueckgegeben.
Wird 'export' auf True/False gesetzt, werden nur Inputs zurueckgegeben, Wird 'export' auf True/False gesetzt, werden nur Inputs zurueckgegeben,
bei denen der Wert 'Export' in piCtory uebereinstimmt. bei denen der Wert 'Export' in piCtory uebereinstimmt.
@param export Nur Inputs mit angegebenen 'Export' Wert in piCtory :param export: Nur Inputs mit angegebenen 'Export' Wert in piCtory
@return <class 'list'> Inputs :return: <class 'list'> Inputs
""" """
return list(self.__getioiter(self._slc_inpoff, export)) return list(self.__getioiter(self._slc_inpoff, export))
def get_outputs(self, export=None): def get_outputs(self, export=None) -> list:
"""Gibt eine Liste aller Outputs zurueck. """
Gibt eine Liste aller Outputs zurueck.
Bleibt Parameter 'export' auf None werden alle Outputs zurueckgegeben. Bleibt Parameter 'export' auf None werden alle Outputs zurueckgegeben.
Wird 'export' auf True/False gesetzt, werden nur Outputs Wird 'export' auf True/False gesetzt, werden nur Outputs
zurueckgegeben, bei denen der Wert 'Export' in piCtory uebereinstimmt. zurueckgegeben, bei denen der Wert 'Export' in piCtory uebereinstimmt.
@param export Nur Outputs mit angegebenen 'Export' Wert in piCtory :param export: Nur Outputs mit angegebenen 'Export' Wert in piCtory
@return <class 'list'> Outputs :return: <class 'list'> Outputs
""" """
return list(self.__getioiter(self._slc_outoff, export)) return list(self.__getioiter(self._slc_outoff, export))
def get_memories(self, export=None): def get_memories(self, export=None) -> list:
"""Gibt eine Liste aller Memoryobjekte zurueck. """
Gibt eine Liste aller Memoryobjekte zurueck.
Bleibt Parameter 'export' auf None werden alle Mems zurueckgegeben. Bleibt Parameter 'export' auf None werden alle Mems zurueckgegeben.
Wird 'export' auf True/False gesetzt, werden nur Mems zurueckgegeben, Wird 'export' auf True/False gesetzt, werden nur Mems zurueckgegeben,
bei denen der Wert 'Export' in piCtory uebereinstimmt. bei denen der Wert 'Export' in piCtory uebereinstimmt.
@param export Nur Mems mit angegebenen 'Export' Wert in piCtory :param export: Nur Mems mit angegebenen 'Export' Wert in piCtory
@return <class 'list'> Mems :return: <class 'list'> Mems
""" """
return list(self.__getioiter(self._slc_memoff, export)) return list(self.__getioiter(self._slc_memoff, export))
def readprocimg(self): def readprocimg(self) -> bool:
"""Alle Inputs fuer dieses Device vom Prozessabbild einlesen. """
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) return self._modio.readprocimg(self)
def setdefaultvalues(self): def setdefaultvalues(self) -> None:
"""Alle Outputbuffer fuer dieses Device auf default Werte setzen. """
Alle Outputbuffer fuer dieses Device auf default Werte setzen.
@return True, wenn erfolgreich ausgefuehrt
@see revpimodio2.modio#RevPiModIO.setdefaultvalues
RevPiModIO.setdefaultvalues()
:return: True, wenn erfolgreich ausgefuehrt
:ref: :func:`revpimodio2.modio.RevPiModIO.setdefaultvalues()`
""" """
self._modio.setdefaultvalues(self) self._modio.setdefaultvalues(self)
def syncoutputs(self): def syncoutputs(self) -> bool:
"""Lesen aller Outputs im Prozessabbild fuer dieses Device. """
Lesen aller Outputs im Prozessabbild fuer dieses Device.
@return True, wenn erfolgreich ausgefuehrt
@see revpimodio2.modio#RevPiModIO.syncoutputs
RevPiModIO.syncoutputs()
:return: True, wenn erfolgreich ausgefuehrt
:ref: :func:`revpimodio2.modio.RevPiModIO.syncoutputs()`
""" """
return self._modio.syncoutputs(self) return self._modio.syncoutputs(self)
def writeprocimg(self): def writeprocimg(self) -> bool:
"""Schreiben aller Outputs dieses Devices ins Prozessabbild. """
Schreiben aller Outputs dieses Devices ins Prozessabbild.
@return True, wenn erfolgreich ausgefuehrt
@see revpimodio2.modio#RevPiModIO.writeprocimg
RevPiModIO.writeprocimg()
:return: True, wenn erfolgreich ausgefuehrt
:ref: :func:`revpimodio2.modio.RevPiModIO.writeprocimg()`
""" """
return self._modio.writeprocimg(self) return self._modio.writeprocimg(self)
@@ -472,7 +518,6 @@ class Device(object):
class Base(Device): class Base(Device):
"""Klasse fuer alle Base-Devices wie Core / Connect usw.""" """Klasse fuer alle Base-Devices wie Core / Connect usw."""
__slots__ = () __slots__ = ()
@@ -481,11 +526,10 @@ class Base(Device):
class Core(Base): class Core(Base):
"""
"""Klasse fuer den RevPi Core. Klasse fuer den RevPi Core.
Stellt Funktionen fuer die LEDs und den Status zur Verfuegung. Stellt Funktionen fuer die LEDs und den Status zur Verfuegung.
""" """
__slots__ = "_slc_cycle", "_slc_errorcnt", "_slc_statusbyte", \ __slots__ = "_slc_cycle", "_slc_errorcnt", "_slc_statusbyte", \
@@ -502,7 +546,7 @@ class Core(Base):
else: else:
object.__setattr__(self, key, value) object.__setattr__(self, key, value)
def _devconfigure(self): def _devconfigure(self) -> None:
"""Core-Klasse vorbereiten.""" """Core-Klasse vorbereiten."""
# Statische IO Verknüpfungen je nach Core-Variante # Statische IO Verknüpfungen je nach Core-Variante
@@ -564,10 +608,13 @@ class Core(Base):
exp_a2red, None, "LED_A2_RED", "3" exp_a2red, None, "LED_A2_RED", "3"
], OUT, "little", False) ], OUT, "little", False)
def __errorlimit(self, slc_io, errorlimit): def __errorlimit(self, slc_io: slice, errorlimit: int) -> None:
"""Verwaltet das Schreiben der ErrorLimits. """
@param slc_io Byte Slice vom ErrorLimit Verwaltet das Schreiben der ErrorLimits.
@return Aktuellen ErrorLimit oder None wenn nicht verfuegbar"""
:param slc_io: Byte Slice vom ErrorLimit
:return: Aktuellen ErrorLimit oder None wenn nicht verfuegbar
"""
if 0 <= errorlimit <= 65535: if 0 <= errorlimit <= 65535:
self._ba_devdata[slc_io] = \ self._ba_devdata[slc_io] = \
errorlimit.to_bytes(2, byteorder="little") errorlimit.to_bytes(2, byteorder="little")
@@ -576,16 +623,22 @@ class Core(Base):
"errorlimit value must be between 0 and 65535" "errorlimit value must be between 0 and 65535"
) )
def _get_status(self): def _get_status(self) -> int:
"""Gibt den RevPi Core Status zurueck. """
@return Status als <class 'int'>""" Gibt den RevPi Core Status zurueck.
:return: Status als <class 'int'>
"""
return int.from_bytes( return int.from_bytes(
self._ba_devdata[self._slc_statusbyte], byteorder="little" self._ba_devdata[self._slc_statusbyte], byteorder="little"
) )
def _get_leda1(self): def _get_leda1(self) -> int:
"""Gibt den Zustand der LED A1 vom Core zurueck. """
@return 0=aus, 1=gruen, 2=rot""" Gibt den Zustand der LED A1 vom Core zurueck.
:return: 0=aus, 1=gruen, 2=rot
"""
int_led = int.from_bytes( int_led = int.from_bytes(
self._ba_devdata[self._slc_led], byteorder="little" self._ba_devdata[self._slc_led], byteorder="little"
) )
@@ -593,9 +646,12 @@ class Core(Base):
led += int_led & 2 led += int_led & 2
return led return led
def _get_leda2(self): def _get_leda2(self) -> int:
"""Gibt den Zustand der LED A2 vom Core zurueck. """
@return 0=aus, 1=gruen, 2=rot""" Gibt den Zustand der LED A2 vom Core zurueck.
:return: 0=aus, 1=gruen, 2=rot
"""
int_led = int.from_bytes( int_led = int.from_bytes(
self._ba_devdata[self._slc_led], byteorder="little" self._ba_devdata[self._slc_led], byteorder="little"
) >> 2 ) >> 2
@@ -603,10 +659,14 @@ class Core(Base):
led += int_led & 2 led += int_led & 2
return led return led
def _set_calculatedled(self, addresslist, shifted_value): def _set_calculatedled(self, addresslist, shifted_value) -> None:
"""Berechnet und setzt neuen Bytewert fuer LED byte. """
@param addresslist Liste der Vergleicher Berechnet und setzt neuen Bytewert fuer LED byte.
@param shifed_value Bits vergleichen"""
:param addresslist: Liste der Vergleicher
:param shifted_value: Bits vergleichen
"""
# TODO: Docstring
# Byte als int holen # Byte als int holen
int_led = int.from_bytes( int_led = int.from_bytes(
self._ba_devdata[self._slc_led], byteorder="little" self._ba_devdata[self._slc_led], byteorder="little"
@@ -625,17 +685,23 @@ class Core(Base):
self._ba_devdata[self._slc_led] = \ self._ba_devdata[self._slc_led] = \
int_led.to_bytes(length=1, byteorder="little") int_led.to_bytes(length=1, byteorder="little")
def _set_leda1(self, value): def _set_leda1(self, value: int) -> None:
"""Setzt den Zustand der LED A1 vom Core. """
@param value 0=aus, 1=gruen, 2=rot""" Setzt den Zustand der LED A1 vom Core.
:param value: 0=aus, 1=gruen, 2=rot
"""
if 0 <= value <= 3: if 0 <= value <= 3:
self._set_calculatedled([1, 2], value) self._set_calculatedled([1, 2], value)
else: else:
raise ValueError("led status must be between 0 and 3") raise ValueError("led status must be between 0 and 3")
def _set_leda2(self, value): def _set_leda2(self, value: int) -> None:
"""Setzt den Zustand der LED A2 vom Core. """
@param value 0=aus, 1=gruen, 2=rot""" Setzt den Zustand der LED A2 vom Core.
:param value: 0=aus, 1=gruen, 2=rot
"""
if 0 <= value <= 3: if 0 <= value <= 3:
self._set_calculatedled([4, 8], value << 2) self._set_calculatedled([4, 8], value << 2)
else: else:
@@ -646,97 +712,133 @@ class Core(Base):
status = property(_get_status) status = property(_get_status)
@property @property
def picontrolrunning(self): def picontrolrunning(self) -> bool:
"""Statusbit fuer piControl-Treiber laeuft. """
@return True, wenn Treiber laeuft""" Statusbit fuer piControl-Treiber laeuft.
:return: True, wenn Treiber laeuft
"""
return bool(int.from_bytes( return bool(int.from_bytes(
self._ba_devdata[self._slc_statusbyte], byteorder="little" self._ba_devdata[self._slc_statusbyte], byteorder="little"
) & 1) ) & 1)
@property @property
def unconfdevice(self): def unconfdevice(self) -> bool:
"""Statusbit fuer ein IO-Modul nicht mit PiCtory konfiguriert. """
@return True, wenn IO Modul nicht konfiguriert""" Statusbit fuer ein IO-Modul nicht mit PiCtory konfiguriert.
:return: True, wenn IO Modul nicht konfiguriert
"""
return bool(int.from_bytes( return bool(int.from_bytes(
self._ba_devdata[self._slc_statusbyte], byteorder="little" self._ba_devdata[self._slc_statusbyte], byteorder="little"
) & 2) ) & 2)
@property @property
def missingdeviceorgate(self): def missingdeviceorgate(self) -> bool:
"""Statusbit fuer ein IO-Modul fehlt oder piGate konfiguriert. """
@return True, wenn IO-Modul fehlt oder piGate konfiguriert""" Statusbit fuer ein IO-Modul fehlt oder piGate konfiguriert.
:return: True, wenn IO-Modul fehlt oder piGate konfiguriert
"""
return bool(int.from_bytes( return bool(int.from_bytes(
self._ba_devdata[self._slc_statusbyte], byteorder="little" self._ba_devdata[self._slc_statusbyte], byteorder="little"
) & 4) ) & 4)
@property @property
def overunderflow(self): def overunderflow(self) -> bool:
"""Statusbit Modul belegt mehr oder weniger Speicher als konfiguriert. """
@return True, wenn falscher Speicher belegt ist""" Statusbit Modul belegt mehr oder weniger Speicher als konfiguriert.
:return: True, wenn falscher Speicher belegt ist
"""
return bool(int.from_bytes( return bool(int.from_bytes(
self._ba_devdata[self._slc_statusbyte], byteorder="little" self._ba_devdata[self._slc_statusbyte], byteorder="little"
) & 8) ) & 8)
@property @property
def leftgate(self): def leftgate(self) -> bool:
"""Statusbit links vom RevPi ist ein piGate Modul angeschlossen. """
@return True, wenn piGate links existiert""" Statusbit links vom RevPi ist ein piGate Modul angeschlossen.
:return: True, wenn piGate links existiert
"""
return bool(int.from_bytes( return bool(int.from_bytes(
self._ba_devdata[self._slc_statusbyte], byteorder="little" self._ba_devdata[self._slc_statusbyte], byteorder="little"
) & 16) ) & 16)
@property @property
def rightgate(self): def rightgate(self) -> bool:
"""Statusbit rechts vom RevPi ist ein piGate Modul angeschlossen. """
@return True, wenn piGate rechts existiert""" Statusbit rechts vom RevPi ist ein piGate Modul angeschlossen.
:return: True, wenn piGate rechts existiert
"""
return bool(int.from_bytes( return bool(int.from_bytes(
self._ba_devdata[self._slc_statusbyte], byteorder="little" self._ba_devdata[self._slc_statusbyte], byteorder="little"
) & 32) ) & 32)
@property @property
def iocycle(self): def iocycle(self) -> int:
"""Gibt Zykluszeit der Prozessabbildsynchronisierung zurueck. """
@return Zykluszeit in ms""" Gibt Zykluszeit der Prozessabbildsynchronisierung zurueck.
return None if self._slc_cycle is None else int.from_bytes(
: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" self._ba_devdata[self._slc_cycle], byteorder="little"
) )
@property @property
def temperature(self): def temperature(self) -> int:
"""Gibt CPU-Temperatur zurueck. """
@return CPU-Temperatur in Celsius""" Gibt CPU-Temperatur zurueck.
return None if self._slc_temperature is None else int.from_bytes(
: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" self._ba_devdata[self._slc_temperature], byteorder="little"
) )
@property @property
def frequency(self): def frequency(self) -> int:
"""Gibt CPU Taktfrequenz zurueck. """
@return CPU Taktfrequenz in MHz""" Gibt CPU Taktfrequenz zurueck.
return None if self._slc_frequency is None else int.from_bytes(
: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" self._ba_devdata[self._slc_frequency], byteorder="little"
) * 10 ) * 10
@property @property
def ioerrorcount(self): def ioerrorcount(self) -> int:
"""Gibt Fehleranzahl auf RS485 piBridge Bus zurueck. """
@return Fehleranzahl der piBridge""" Gibt Fehleranzahl auf RS485 piBridge Bus zurueck.
return None if self._slc_errorcnt is None else int.from_bytes(
: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" self._ba_devdata[self._slc_errorcnt], byteorder="little"
) )
@property @property
def errorlimit1(self): def errorlimit1(self) -> int:
"""Gibt RS485 ErrorLimit1 Wert zurueck. """
@return Aktueller Wert fuer ErrorLimit1""" Gibt RS485 ErrorLimit1 Wert zurueck.
return None if self._slc_errorlimit1 is None else int.from_bytes(
: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" self._ba_devdata[self._slc_errorlimit1], byteorder="little"
) )
@errorlimit1.setter @errorlimit1.setter
def errorlimit1(self, value): def errorlimit1(self, value: int) -> None:
"""Setzt RS485 ErrorLimit1 auf neuen Wert. """
@param value Neuer ErrorLimit1 Wert""" Setzt RS485 ErrorLimit1 auf neuen Wert.
:param value: Neuer ErrorLimit1 Wert
"""
if self._slc_errorlimit1 is None: if self._slc_errorlimit1 is None:
raise RuntimeError( raise RuntimeError(
"selected core item in piCtory does not support errorlimit1" "selected core item in piCtory does not support errorlimit1"
@@ -745,17 +847,23 @@ class Core(Base):
self.__errorlimit(self._slc_errorlimit1, value) self.__errorlimit(self._slc_errorlimit1, value)
@property @property
def errorlimit2(self): def errorlimit2(self) -> int:
"""Gibt RS485 ErrorLimit2 Wert zurueck. """
@return Aktueller Wert fuer ErrorLimit2""" Gibt RS485 ErrorLimit2 Wert zurueck.
return None if self._slc_errorlimit2 is None else int.from_bytes(
: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" self._ba_devdata[self._slc_errorlimit2], byteorder="little"
) )
@errorlimit2.setter @errorlimit2.setter
def errorlimit2(self, value): def errorlimit2(self, value: int) -> None:
"""Setzt RS485 ErrorLimit2 auf neuen Wert. """
@param value Neuer ErrorLimit2 Wert""" Setzt RS485 ErrorLimit2 auf neuen Wert.
:param value: Neuer ErrorLimit2 Wert
"""
if self._slc_errorlimit2 is None: if self._slc_errorlimit2 is None:
raise RuntimeError( raise RuntimeError(
"selected core item in piCtory does not support errorlimit2" "selected core item in piCtory does not support errorlimit2"
@@ -765,11 +873,9 @@ class Core(Base):
class Connect(Core): class Connect(Core):
"""Klasse fuer den RevPi Connect. """Klasse fuer den RevPi Connect.
Stellt Funktionen fuer die LEDs, Watchdog und den Status zur Verfuegung. Stellt Funktionen fuer die LEDs, Watchdog und den Status zur Verfuegung.
""" """
__slots__ = "__evt_wdtoggle", "__th_wdtoggle", "a3green", "a3red", "wd", \ __slots__ = "__evt_wdtoggle", "__th_wdtoggle", "a3green", "a3red", "wd", \
@@ -786,12 +892,12 @@ class Connect(Core):
else: else:
object.__setattr__(self, key, value) object.__setattr__(self, key, value)
def __wdtoggle(self): def __wdtoggle(self) -> None:
"""WD Ausgang alle 10 Sekunden automatisch toggeln.""" """WD Ausgang alle 10 Sekunden automatisch toggeln."""
while not self.__evt_wdtoggle.wait(10): while not self.__evt_wdtoggle.wait(10):
self.wd.value = not self.wd.value self.wd.value = not self.wd.value
def _devconfigure(self): def _devconfigure(self) -> None:
"""Connect-Klasse vorbereiten.""" """Connect-Klasse vorbereiten."""
super()._devconfigure() super()._devconfigure()
@@ -841,9 +947,12 @@ class Connect(Core):
exp_x2out, None, "Connect_X2_OUT", "6" exp_x2out, None, "Connect_X2_OUT", "6"
], OUT, "little", False) ], OUT, "little", False)
def _get_leda3(self): def _get_leda3(self) -> int:
"""Gibt den Zustand der LED A3 vom Connect zurueck. """
@return 0=aus, 1=gruen, 2=rot""" Gibt den Zustand der LED A3 vom Connect zurueck.
:return: 0=aus, 1=gruen, 2=rot
"""
int_led = int.from_bytes( int_led = int.from_bytes(
self._ba_devdata[self._slc_led], byteorder="little" self._ba_devdata[self._slc_led], byteorder="little"
) >> 4 ) >> 4
@@ -851,22 +960,28 @@ class Connect(Core):
led += int_led & 2 led += int_led & 2
return led return led
def _get_wdtoggle(self): def _get_wdtoggle(self) -> bool:
"""Ruft den Wert fuer Autowatchdog ab. """
@return True, wenn Autowatchdog aktiv ist""" Ruft den Wert fuer Autowatchdog ab.
return self.__th_wdtoggle is not None \
and self.__th_wdtoggle.is_alive()
def _set_leda3(self, value): :return: True, wenn Autowatchdog aktiv ist
"""Setzt den Zustand der LED A3 vom Connect. """
@param value 0=aus, 1=gruen, 2=rot""" 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: if 0 <= value <= 3:
self._set_calculatedled([16, 32], value << 4) self._set_calculatedled([16, 32], value << 4)
else: else:
raise ValueError("led status must be between 0 and 3") raise ValueError("led status must be between 0 and 3")
def _set_wdtoggle(self, value): def _set_wdtoggle(self, value: bool) -> None:
"""Setzt den Wert fuer Autowatchdog. """
Setzt den Wert fuer Autowatchdog.
Wird dieser Wert auf True gesetzt, wechselt im Hintergrund das noetige Wird dieser Wert auf True gesetzt, wechselt im Hintergrund das noetige
Bit zum toggeln des Watchdogs alle 10 Sekunden zwichen True und False. 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 .writeprocimg() aufgerufen werden, um den Wert in das
Prozessabbild zu schreiben!!! Prozessabbild zu schreiben!!!
@param value True zum aktivieren, Fals zum beenden""" :param value: True zum aktivieren, Fals zum beenden
"""
if self._modio._monitoring: if self._modio._monitoring:
raise RuntimeError( raise RuntimeError(
"can not toggle watchdog, while system is in monitoring mode" "can not toggle watchdog, while system is in monitoring mode"
@@ -901,15 +1017,16 @@ class Connect(Core):
class DioModule(Device): class DioModule(Device):
"""Stellt ein DIO / DI / DO Modul dar.""" """Stellt ein DIO / DI / DO Modul dar."""
__slots__ = ("_lst_counter") __slots__ = "_lst_counter"
def __init__(self, parentmodio, dict_device, simulator=False): 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) # Stringliste der Byteadressen (alle Module sind gleich)
self._lst_counter = list(map(str, range(6, 70, 4))) self._lst_counter = list(map(str, range(6, 70, 4)))
@@ -918,23 +1035,26 @@ class DioModule(Device):
class Gateway(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 Stellt neben den Funktionen von RevPiDevice weitere Funktionen fuer die
Gateways bereit. IOs auf diesem Device stellen die replace_io Funktion Gateways bereit. IOs auf diesem Device stellen die replace_io Funktion
zur verfuegung, ueber die eigene IOs definiert werden, die ein zur verfuegung, ueber die eigene IOs definiert werden, die ein
RevPiStructIO-Objekt abbilden. RevPiStructIO-Objekt abbilden.
Dieser IO-Typ kann Werte ueber mehrere Bytes verarbeiten und zurueckgeben. 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" __slots__ = "_dict_slc"
def __init__(self, parent, dict_device, simulator=False): 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) super().__init__(parent, dict_device, simulator)
self._dict_slc = { self._dict_slc = {
@@ -943,28 +1063,32 @@ class Gateway(Device):
MEM: self._slc_mem MEM: self._slc_mem
} }
def get_rawbytes(self): def get_rawbytes(self) -> bytes:
"""Gibt die Bytes aus, die dieses Device verwendet. """
@return <class 'bytes'> des Devices""" Gibt die Bytes aus, die dieses Device verwendet.
:return: <class 'bytes'> des Devices
"""
return bytes(self._ba_devdata) return bytes(self._ba_devdata)
class Virtual(Gateway): 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 Stellt die selben Funktionen wie Gateway zur Verfuegung. Es koennen
ueber die reg_*-Funktionen eigene IOs definiert werden, die ein ueber die reg_*-Funktionen eigene IOs definiert werden, die ein
RevPiStructIO-Objekt abbilden. RevPiStructIO-Objekt abbilden.
Dieser IO-Typ kann Werte ueber mehrere Bytes verarbeiten und zurueckgeben. Dieser IO-Typ kann Werte ueber mehrere Bytes verarbeiten und zurueckgeben.
@see #Gateway Gateway
:ref: :func:`Gateway`
""" """
__slots__ = () __slots__ = ()
def writeinputdefaults(self): 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 Sollten in piCtory Defaultwerte fuer Inputs eines virtuellen Devices
angegeben sein, werden diese nur beim Systemstart oder einem piControl angegeben sein, werden diese nur beim Systemstart oder einem piControl
@@ -972,8 +1096,7 @@ class Virtual(Gateway):
gehen diese Werte verloren. gehen diese Werte verloren.
Diese Funktion kann nur auf virtuelle Devices angewendet werden! 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: if self._modio._monitoring:
raise RuntimeError( raise RuntimeError(

View File

@@ -1,19 +1,19 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""RevPiModIO Helperklassen und Tools.""" """RevPiModIO Helperklassen und Tools."""
__author__ = "Sven Sager"
__copyright__ = "Copyright (C) 2018 Sven Sager"
__license__ = "LGPLv3"
import queue import queue
import warnings import warnings
from math import ceil from math import ceil
from threading import Event, Lock, Thread from threading import Event, Lock, Thread
from timeit import default_timer 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): class EventCallback(Thread):
"""Thread fuer das interne Aufrufen von Event-Funktionen. """Thread fuer das interne Aufrufen von Event-Funktionen.
Der Eventfunktion, welche dieser Thread aufruft, wird der Thread selber Der Eventfunktion, welche dieser Thread aufruft, wird der Thread selber
@@ -34,18 +34,17 @@ class EventCallback(Thread):
while not th.exit.is_set(): while not th.exit.is_set():
# IO-Arbeiten # IO-Arbeiten
th.exit.wait(0.5) th.exit.wait(0.5)
""" """
__slots__ = "daemon", "exit", "func", "ioname", "iovalue" __slots__ = "daemon", "exit", "func", "ioname", "iovalue"
def __init__(self, func, name, value): def __init__(self, func, name: str, value):
"""Init EventCallback class. """
Init EventCallback class.
@param func Funktion die beim Start aufgerufen werden soll
@param name IO-Name
@param value IO-Value zum Zeitpunkt des Events
:param func: Funktion die beim Start aufgerufen werden soll
:param name: IO-Name
:param value: IO-Value zum Zeitpunkt des Events
""" """
super().__init__() super().__init__()
self.daemon = True self.daemon = True
@@ -63,9 +62,9 @@ class EventCallback(Thread):
self.exit.set() self.exit.set()
class Cycletools(): class Cycletools:
"""
"""Werkzeugkasten fuer Cycleloop-Funktion. Werkzeugkasten fuer Cycleloop-Funktion.
Diese Klasse enthaelt Werkzeuge fuer Zyklusfunktionen, wie Taktmerker Diese Klasse enthaelt Werkzeuge fuer Zyklusfunktionen, wie Taktmerker
und Flankenmerker. und Flankenmerker.
@@ -84,7 +83,6 @@ class Cycletools():
Diese Merker koennen z.B. verwendet werden um, an Outputs angeschlossene, Diese Merker koennen z.B. verwendet werden um, an Outputs angeschlossene,
Lampen synchron blinken zu lassen. Lampen synchron blinken zu lassen.
""" """
__slots__ = "__cycle", "__cycletime", "__ucycle", \ __slots__ = "__cycle", "__cycletime", "__ucycle", \
@@ -117,10 +115,13 @@ class Cycletools():
# Benutzerdaten # Benutzerdaten
class Var: class Var:
"""Hier remanente Variablen anfuegen."""
pass pass
self.var = Var() self.var = Var()
def _docycle(self): def _docycle(self) -> None:
"""Zyklusarbeiten.""" """Zyklusarbeiten."""
# Einschaltverzoegerung # Einschaltverzoegerung
for tof in self.__dict_tof: for tof in self.__dict_tof:
@@ -174,54 +175,66 @@ class Cycletools():
self.flag5c = not self.flag5c self.flag5c = not self.flag5c
self.__cycle = 0 self.__cycle = 0
def get_tof(self, name): def get_tof(self, name: str) -> bool:
"""Wert der Ausschaltverzoegerung. """
@param name Eindeutiger Name des Timers Wert der Ausschaltverzoegerung.
@return Wert <class 'bool'> der Ausschaltverzoegerung"""
:param name: Eindeutiger Name des Timers
:return: Wert <class 'bool'> der Ausschaltverzoegerung
"""
return self.__dict_tof.get(name, 0) > 0 return self.__dict_tof.get(name, 0) > 0
def get_tofc(self, name): def get_tofc(self, name: str) -> bool:
"""Wert der Ausschaltverzoegerung. """
@param name Eindeutiger Name des Timers Wert der Ausschaltverzoegerung.
@return Wert <class 'bool'> der Ausschaltverzoegerung"""
:param name: Eindeutiger Name des Timers
:return: Wert <class 'bool'> der Ausschaltverzoegerung
"""
return self.__dict_tof.get(name, 0) > 0 return self.__dict_tof.get(name, 0) > 0
def set_tof(self, name, milliseconds): def set_tof(self, name: str, milliseconds: int) -> None:
"""Startet bei Aufruf einen ausschaltverzoegerten Timer. """
Startet bei Aufruf einen ausschaltverzoegerten Timer.
@param name Eindeutiger Name fuer Zugriff auf Timer
@param milliseconds Verzoegerung in Millisekunden
:param name: Eindeutiger Name fuer Zugriff auf Timer
:param milliseconds: Verzoegerung in Millisekunden
""" """
self.__dict_tof[name] = ceil(milliseconds / self.__cycletime) self.__dict_tof[name] = ceil(milliseconds / self.__cycletime)
def set_tofc(self, name, cycles): def set_tofc(self, name: str, cycles: int) -> None:
"""Startet bei Aufruf einen ausschaltverzoegerten Timer. """
Startet bei Aufruf einen ausschaltverzoegerten Timer.
@param name Eindeutiger Name fuer Zugriff auf Timer
@param cycles Zyklusanzahl, der Verzoegerung wenn nicht neu gestartet
:param name: Eindeutiger Name fuer Zugriff auf Timer
:param cycles: Zyklusanzahl, der Verzoegerung wenn nicht neu gestartet
""" """
self.__dict_tof[name] = cycles self.__dict_tof[name] = cycles
def get_ton(self, name): def get_ton(self, name: str) -> bool:
"""Einschaltverzoegerung. """
@param name Eindeutiger Name des Timers Einschaltverzoegerung.
@return Wert <class 'bool'> der Einschaltverzoegerung"""
:param name: Eindeutiger Name des Timers
:return: Wert <class 'bool'> der Einschaltverzoegerung
"""
return self.__dict_ton.get(name, [-1])[0] == 0 return self.__dict_ton.get(name, [-1])[0] == 0
def get_tonc(self, name): def get_tonc(self, name: str) -> bool:
"""Einschaltverzoegerung. """
@param name Eindeutiger Name des Timers Einschaltverzoegerung.
@return Wert <class 'bool'> der Einschaltverzoegerung"""
:param name: Eindeutiger Name des Timers
:return: Wert <class 'bool'> der Einschaltverzoegerung
"""
return self.__dict_ton.get(name, [-1])[0] == 0 return self.__dict_ton.get(name, [-1])[0] == 0
def set_ton(self, name, milliseconds): def set_ton(self, name: str, milliseconds: int) -> None:
"""Startet einen einschaltverzoegerten Timer. """
Startet einen einschaltverzoegerten Timer.
@param name Eindeutiger Name fuer Zugriff auf Timer
@param milliseconds Millisekunden, der Verzoegerung wenn neu gestartet
: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: if self.__dict_ton.get(name, [-1])[0] == -1:
self.__dict_ton[name] = \ self.__dict_ton[name] = \
@@ -229,36 +242,42 @@ class Cycletools():
else: else:
self.__dict_ton[name][1] = True self.__dict_ton[name][1] = True
def set_tonc(self, name, cycles): def set_tonc(self, name: str, cycles: int) -> None:
"""Startet einen einschaltverzoegerten Timer. """
Startet einen einschaltverzoegerten Timer.
@param name Eindeutiger Name fuer Zugriff auf Timer
@param cycles Zyklusanzahl, der Verzoegerung wenn neu gestartet
: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: if self.__dict_ton.get(name, [-1])[0] == -1:
self.__dict_ton[name] = [cycles, True] self.__dict_ton[name] = [cycles, True]
else: else:
self.__dict_ton[name][1] = True self.__dict_ton[name][1] = True
def get_tp(self, name): def get_tp(self, name: str) -> bool:
"""Impulstimer. """
@param name Eindeutiger Name des Timers Impulstimer.
@return Wert <class 'bool'> des Impulses"""
:param name: Eindeutiger Name des Timers
:return: Wert <class 'bool'> des Impulses
"""
return self.__dict_tp.get(name, [-1])[0] > 0 return self.__dict_tp.get(name, [-1])[0] > 0
def get_tpc(self, name): def get_tpc(self, name: str) -> bool:
"""Impulstimer. """
@param name Eindeutiger Name des Timers Impulstimer.
@return Wert <class 'bool'> des Impulses"""
:param name: Eindeutiger Name des Timers
:return: Wert <class 'bool'> des Impulses
"""
return self.__dict_tp.get(name, [-1])[0] > 0 return self.__dict_tp.get(name, [-1])[0] > 0
def set_tp(self, name, milliseconds): def set_tp(self, name: str, milliseconds: int) -> None:
"""Startet einen Impuls Timer. """
Startet einen Impuls Timer.
@param name Eindeutiger Name fuer Zugriff auf Timer
@param milliseconds Millisekunden, die der Impuls anstehen soll
: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: if self.__dict_tp.get(name, [-1])[0] == -1:
self.__dict_tp[name] = \ self.__dict_tp[name] = \
@@ -266,12 +285,12 @@ class Cycletools():
else: else:
self.__dict_tp[name][1] = True self.__dict_tp[name][1] = True
def set_tpc(self, name, cycles): def set_tpc(self, name: str, cycles: int) -> None:
"""Startet einen Impuls Timer. """
Startet einen Impuls Timer.
@param name Eindeutiger Name fuer Zugriff auf Timer
@param cycles Zyklusanzahl, die der Impuls anstehen soll
: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: if self.__dict_tp.get(name, [-1])[0] == -1:
self.__dict_tp[name] = [cycles, True] self.__dict_tp[name] = [cycles, True]
@@ -280,13 +299,12 @@ class Cycletools():
class ProcimgWriter(Thread): class ProcimgWriter(Thread):
"""
"""Klasse fuer Synchroniseriungs-Thread. Klasse fuer Synchroniseriungs-Thread.
Diese Klasse wird als Thread gestartet, wenn das Prozessabbild zyklisch Diese Klasse wird als Thread gestartet, wenn das Prozessabbild zyklisch
synchronisiert werden soll. Diese Funktion wird hauptsaechlich fuer das synchronisiert werden soll. Diese Funktion wird hauptsaechlich fuer das
Event-Handling verwendet. Event-Handling verwendet.
""" """
__slots__ = "__dict_delay", "__eventth", "_eventqth", "__eventwork", \ __slots__ = "__dict_delay", "__eventth", "_eventqth", "__eventwork", \
@@ -294,8 +312,7 @@ class ProcimgWriter(Thread):
"_refresh", "_work", "daemon", "lck_refresh", "newdata" "_refresh", "_work", "daemon", "lck_refresh", "newdata"
def __init__(self, parentmodio): def __init__(self, parentmodio):
"""Init ProcimgWriter class. """Init ProcimgWriter class."""
@param parentmodio Parent Object"""
super().__init__() super().__init__()
self.__dict_delay = {} self.__dict_delay = {}
self.__eventth = Thread(target=self.__exec_th) self.__eventth = Thread(target=self.__exec_th)
@@ -311,7 +328,7 @@ class ProcimgWriter(Thread):
self.lck_refresh = Lock() self.lck_refresh = Lock()
self.newdata = Event() self.newdata = Event()
def __check_change(self, dev): def __check_change(self, dev) -> None:
"""Findet Aenderungen fuer die Eventueberwachung.""" """Findet Aenderungen fuer die Eventueberwachung."""
for io_event in dev._dict_events: 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) # Nach Verarbeitung aller IOs die Bytes kopieren (Lock ist noch drauf)
dev._ba_datacp = dev._ba_devdata[:] dev._ba_datacp = dev._ba_devdata[:]
def __exec_th(self): def __exec_th(self) -> None:
"""Laeuft als Thread, der Events als Thread startet.""" """Laeuft als Thread, der Events als Thread startet."""
while self.__eventwork: while self.__eventwork:
try: try:
@@ -398,10 +415,13 @@ class ProcimgWriter(Thread):
except queue.Empty: except queue.Empty:
pass pass
def _collect_events(self, value): def _collect_events(self, value: bool) -> bool:
"""Aktiviert oder Deaktiviert die Eventueberwachung. """
@param value True aktiviert / False deaktiviert Aktiviert oder Deaktiviert die Eventueberwachung.
@return True, wenn Anforderung erfolgreich war"""
:param value: True aktiviert / False deaktiviert
:return: True, wenn Anforderung erfolgreich war
"""
if type(value) != bool: if type(value) != bool:
raise TypeError("value must be <class 'bool'>") raise TypeError("value must be <class 'bool'>")
@@ -427,9 +447,12 @@ class ProcimgWriter(Thread):
return True return True
def get_refresh(self): def get_refresh(self) -> int:
"""Gibt Zykluszeit zurueck. """
@return <class 'int'> Zykluszeit in Millisekunden""" Gibt Zykluszeit zurueck.
:return: <class 'int'> Zykluszeit in Millisekunden
"""
return int(self._refresh * 1000) return int(self._refresh * 1000)
def run(self): def run(self):

View File

@@ -1,13 +1,15 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""RevPiModIO Modul fuer die Verwaltung der IOs.""" """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" __author__ = "Sven Sager"
__copyright__ = "Copyright (C) 2018 Sven Sager" __copyright__ = "Copyright (C) 2018 Sven Sager"
__license__ = "LGPLv3" __license__ = "LGPLv3"
import struct
from re import match as rematch
from threading import Event
from revpimodio2 import RISING, FALLING, BOTH, INP, MEM, consttostr
try: try:
# Funktioniert nur auf Unix # Funktioniert nur auf Unix
from fcntl import ioctl from fcntl import ioctl
@@ -16,7 +18,6 @@ except Exception:
class IOEvent(object): class IOEvent(object):
"""Basisklasse fuer IO-Events.""" """Basisklasse fuer IO-Events."""
__slots__ = "as_thread", "delay", "edge", "func", "overwrite", "prefire" __slots__ = "as_thread", "delay", "edge", "func", "overwrite", "prefire"
@@ -32,7 +33,6 @@ class IOEvent(object):
class IOList(object): class IOList(object):
"""Basisklasse fuer direkten Zugriff auf IO Objekte.""" """Basisklasse fuer direkten Zugriff auf IO Objekte."""
def __init__(self): def __init__(self):
@@ -41,17 +41,23 @@ class IOList(object):
self.__dict_iorefname = {} self.__dict_iorefname = {}
def __contains__(self, key): def __contains__(self, key):
"""Prueft ob IO existiert. """
@param key IO-Name <class 'str'> oder Bytenummer <class 'int'> Prueft ob IO existiert.
@return True, wenn IO vorhanden / Byte belegt"""
:param key: IO-Name <class 'str'> oder Bytenummer <class 'int'>
:return: True, wenn IO vorhanden / Byte belegt
"""
if type(key) == int: if type(key) == int:
return len(self.__dict_iobyte.get(key, [])) > 0 return len(self.__dict_iobyte.get(key, [])) > 0
else: else:
return hasattr(self, key) and type(getattr(self, key)) != DeadIO return hasattr(self, key) and type(getattr(self, key)) != DeadIO
def __delattr__(self, key): 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) io_del = object.__getattribute__(self, key)
# Alte Events vom Device löschen # Alte Events vom Device löschen
@@ -70,16 +76,20 @@ class IOList(object):
io_del._parentdevice._update_my_io_list() io_del._parentdevice._update_my_io_list()
def __getattr__(self, key): def __getattr__(self, key):
"""Verwaltet geloeschte IOs (Attribute, die nicht existieren). """
@param key Name oder Byte eines alten IOs Verwaltet geloeschte IOs (Attribute, die nicht existieren).
@return Alten IO, wenn in Ref-Listen"""
:param key: Name oder Byte eines alten IOs
:return: Alten IO, wenn in Ref-Listen
"""
if key in self.__dict_iorefname: if key in self.__dict_iorefname:
return self.__dict_iorefname[key] return self.__dict_iorefname[key]
else: else:
raise AttributeError("can not find io '{0}'".format(key)) raise AttributeError("can not find io '{0}'".format(key))
def __getitem__(self, key): def __getitem__(self, key):
"""Ruft angegebenen IO ab. """
Ruft angegebenen IO ab.
Wenn der Key <class 'str'> ist, wird ein einzelner IO geliefert. Wird Wenn der Key <class 'str'> ist, wird ein einzelner IO geliefert. Wird
der Key als <class 'int'> uebergeben, wird eine <class 'list'> der Key als <class 'int'> uebergeben, wird eine <class 'list'>
@@ -87,9 +97,8 @@ class IOList(object):
Wird als Key <class 'slice'> gegeben, werden die Listen in einer Liste Wird als Key <class 'slice'> gegeben, werden die Listen in einer Liste
zurueckgegeben. zurueckgegeben.
@param key IO Name als <class 'str> oder Byte als <class 'int'>. :param key: IO Name als <class 'str> oder Byte als <class 'int'>.
@return IO Objekt oder Liste der IOs :return: IO Objekt oder Liste der IOs
""" """
if type(key) == int: if type(key) == int:
if key not in self.__dict_iobyte: if key not in self.__dict_iobyte:
@@ -106,16 +115,22 @@ class IOList(object):
return getattr(self, key) return getattr(self, key)
def __iter__(self): 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 int_io in sorted(self.__dict_iobyte):
for io in self.__dict_iobyte[int_io]: for io in self.__dict_iobyte[int_io]:
if io is not None: if io is not None:
yield io yield io
def __len__(self): 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 int_ios = 0
for int_io in self.__dict_iobyte: for int_io in self.__dict_iobyte:
for io in self.__dict_iobyte[int_io]: for io in self.__dict_iobyte[int_io]:
@@ -135,10 +150,12 @@ class IOList(object):
"direct assignment is not supported - use .value Attribute" "direct assignment is not supported - use .value Attribute"
) )
def __private_replace_oldio_with_newio(self, io): def __private_replace_oldio_with_newio(self, io) -> None:
"""Ersetzt bestehende IOs durch den neu Registrierten. """
@param io Neuer IO der eingefuegt werden soll""" Ersetzt bestehende IOs durch den neu Registrierten.
:param io: Neuer IO der eingefuegt werden soll
"""
# Scanbereich festlegen # Scanbereich festlegen
if io._bitaddress < 0: if io._bitaddress < 0:
scan_start = io.address scan_start = io.address
@@ -195,9 +212,12 @@ class IOList(object):
io._parentio_address - io.address io._parentio_address - io.address
] & (1 << io._bitaddress)) ] & (1 << io._bitaddress))
def _private_register_new_io_object(self, new_io): def _private_register_new_io_object(self, new_io) -> None:
"""Registriert neues IO Objekt unabhaenging von __setattr__. """
@param new_io Neues IO Objekt""" Registriert neues IO Objekt unabhaenging von __setattr__.
:param new_io: Neues IO Objekt
"""
if isinstance(new_io, IOBase): if isinstance(new_io, IOBase):
if hasattr(self, new_io._name): if hasattr(self, new_io._name):
raise AttributeError( raise AttributeError(
@@ -229,27 +249,32 @@ class IOList(object):
class DeadIO(object): class DeadIO(object):
"""Klasse, mit der ersetzte IOs verwaltet werden.""" """Klasse, mit der ersetzte IOs verwaltet werden."""
__slots__ = "__deadio" __slots__ = "__deadio"
def __init__(self, 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 self.__deadio = deadio
def replace_io(self, name, frm, **kwargs): def replace_io(self, name: str, frm: str, **kwargs) -> None:
"""Stellt Funktion fuer weiter Bit-Ersetzungen bereit. """
@see #IntIOReplaceable.replace_io replace_io(...)""" Stellt Funktion fuer weiter Bit-Ersetzungen bereit.
:ref: :func:IntIOReplaceable.replace_io()
"""
self.__deadio.replace_io(name, frm, **kwargs) self.__deadio.replace_io(name, frm, **kwargs)
_parentdevice = property(lambda self: None) _parentdevice = property(lambda self: None)
class IOBase(object): class IOBase(object):
"""
"""Basisklasse fuer alle IO-Objekte. Basisklasse fuer alle IO-Objekte.
Die Basisfunktionalitaet ermoeglicht das Lesen und Schreiben der Werte Die Basisfunktionalitaet ermoeglicht das Lesen und Schreiben der Werte
als <class bytes'> oder <class 'bool'>. Dies entscheidet sich bei der als <class bytes'> oder <class 'bool'>. Dies entscheidet sich bei der
@@ -259,7 +284,6 @@ class IOBase(object):
Diese Klasse dient als Basis fuer andere IO-Klassen mit denen die Werte Diese Klasse dient als Basis fuer andere IO-Klassen mit denen die Werte
auch als <class 'int'> verwendet werden koennen. auch als <class 'int'> verwendet werden koennen.
""" """
__slots__ = "__bit_ioctl_off", "__bit_ioctl_on", \ __slots__ = "__bit_ioctl_off", "__bit_ioctl_on", \
@@ -267,16 +291,16 @@ class IOBase(object):
"_iotype", "_length", "_name", "_parentdevice", \ "_iotype", "_length", "_name", "_parentdevice", \
"_signed", "_slc_address", "bmk", "export" "_signed", "_slc_address", "bmk", "export"
def __init__(self, parentdevice, valuelist, iotype, byteorder, signed): def __init__(self, parentdevice, valuelist: list, iotype: int, byteorder: str, signed: bool):
"""Instantiierung der IOBase-Klasse. """
Instantiierung der IOBase-Klasse.
@param parentdevice Parentdevice auf dem der IO liegt :param parentdevice: Parentdevice auf dem der IO liegt
@param valuelist Datenliste fuer Instantiierung :param valuelist: Datenliste fuer Instantiierung
["name","defval","bitlen","startaddrdev",exp,"idx","bmk","bitaddr"] ["name","defval","bitlen","startaddrdev",exp,"idx","bmk","bitaddr"]
@param iotype <class 'int'> Wert :param iotype: <class 'int'> Wert
@param byteorder Byteorder 'little'/'big' fuer <class 'int'> Berechnung :param byteorder: Byteorder 'little'/'big' fuer <class 'int'> Berechnung
@param sigend Intberechnung mit Vorzeichen durchfuehren :param signed: Intberechnung mit Vorzeichen durchfuehren
""" """
# ["name","defval","bitlen","startaddrdev",exp,"idx","bmk","bitaddr"] # ["name","defval","bitlen","startaddrdev",exp,"idx","bmk","bitaddr"]
# [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 ] # [ 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' self.__bit_ioctl_on = self.__bit_ioctl_off + b'\x01'
def __bool__(self): def __bool__(self):
"""<class 'bool'>-Wert der Klasse. """
@return <class 'bool'> Nur False wenn False oder 0 sonst True""" <class 'bool'>-Wert der Klasse.
:return: <class 'bool'> Nur False wenn False oder 0 sonst True
"""
if self._bitaddress >= 0: if self._bitaddress >= 0:
int_byte = int.from_bytes( int_byte = int.from_bytes(
self._parentdevice._ba_devdata[self._slc_address], self._parentdevice._ba_devdata[self._slc_address],
@@ -371,25 +398,31 @@ class IOBase(object):
bytearray(self._length) bytearray(self._length)
def __len__(self): 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 return 0 if self._bitaddress > 0 else self._length
def __str__(self): def __str__(self):
"""<class 'str'>-Wert der Klasse. """
@return Namen des IOs""" <class 'str'>-Wert der Klasse.
:return: Namen des IOs
"""
return self._name return self._name
def __reg_xevent(self, func, delay, edge, as_thread, overwrite, prefire): def __reg_xevent(self, func, delay: int, edge: int, as_thread: bool, overwrite: bool, prefire: bool) -> None:
"""Verwaltet reg_event und reg_timerevent. """
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
: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 # Prüfen ob Funktion callable ist
if not callable(func): if not callable(func):
@@ -449,29 +482,44 @@ class IOBase(object):
IOEvent(func, edge, as_thread, delay, overwrite, prefire) IOEvent(func, edge, as_thread, delay, overwrite, prefire)
) )
def _get_address(self): def _get_address(self) -> int:
"""Gibt die absolute Byteadresse im Prozessabbild zurueck. """
@return Absolute Byteadresse""" Gibt die absolute Byteadresse im Prozessabbild zurueck.
:return: Absolute Byteadresse
"""
return self._parentdevice._offset + self._slc_address.start return self._parentdevice._offset + self._slc_address.start
def _get_byteorder(self): def _get_byteorder(self) -> str:
"""Gibt konfigurierte Byteorder zurueck. """
@return <class 'str'> Byteorder""" Gibt konfigurierte Byteorder zurueck.
:return: <class 'str'> Byteorder
"""
return self._byteorder return self._byteorder
def _get_iotype(self): def _get_iotype(self) -> int:
"""Gibt io type zurueck. """
@return <class 'int'> io type""" Gibt io type zurueck.
:return: <class 'int'> io type
"""
return self._iotype return self._iotype
def get_defaultvalue(self): def get_defaultvalue(self):
"""Gibt die Defaultvalue von piCtory zurueck. """
@return Defaultvalue als <class 'byte'> oder <class 'bool'>""" Gibt die Defaultvalue von piCtory zurueck.
:return: Defaultvalue als <class 'byte'> oder <class 'bool'>
"""
return self._defaultvalue return self._defaultvalue
def get_value(self): def get_value(self):
"""Gibt den Wert des IOs zurueck. """
@return IO-Wert als <class 'bytes'> oder <class 'bool'>""" Gibt den Wert des IOs zurueck.
:return: IO-Wert als <class 'bytes'> oder <class 'bool'>
"""
if self._bitaddress >= 0: if self._bitaddress >= 0:
int_byte = int.from_bytes( int_byte = int.from_bytes(
self._parentdevice._ba_devdata[self._slc_address], self._parentdevice._ba_devdata[self._slc_address],
@@ -483,7 +531,8 @@ class IOBase(object):
def reg_event( def reg_event(
self, func, delay=0, edge=BOTH, as_thread=False, prefire=False): 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 Die uebergebene Funktion wird ausgefuehrt, wenn sich der IO Wert
aendert. Mit Angabe von optionalen Parametern kann das 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 HINWEIS: Die delay-Zeit muss in die .cycletime passen, ist dies nicht
der Fall, wird IMMER aufgerundet! der Fall, wird IMMER aufgerundet!
@param func Funktion die bei Aenderung aufgerufen werden soll :param func: Funktion die bei Aenderung aufgerufen werden soll
@param delay Verzoegerung in ms zum Ausloesen wenn Wert gleich bleibt :param delay; Verzoegerung in ms zum Ausloesen wenn Wert gleich bleibt
@param edge Ausfuehren bei RISING, FALLING or BOTH Wertaenderung :param edge: Ausfuehren bei RISING, FALLING or BOTH Wertaenderung
@param as_thread Bei True, Funktion als EventCallback-Thread ausfuehren :param as_thread: Bei True, Funktion als EventCallback-Thread ausfuehren
@param prefire Ausloesen mit aktuellem Wert, wenn mainloop startet :param prefire: Ausloesen mit aktuellem Wert, wenn mainloop startet
""" """
self.__reg_xevent(func, delay, edge, as_thread, True, prefire) self.__reg_xevent(func, delay, edge, as_thread, True, prefire)
def reg_timerevent(self, func, delay, edge=BOTH, as_thread=False): 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 Der Timer wird gestartet, wenn sich der IO Wert aendert und fuehrt die
uebergebene Funktion aus - auch wenn sich der IO Wert in der 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 HINWEIS: Die delay-Zeit muss in die .cycletime passen, ist dies nicht
der Fall, wird IMMER aufgerundet! der Fall, wird IMMER aufgerundet!
@param func Funktion die bei Aenderung aufgerufen werden soll :param func: Funktion die bei Aenderung aufgerufen werden soll
@param delay Verzoegerung in ms zum Ausloesen - auch bei Wertaenderung :param delay: Verzoegerung in ms zum Ausloesen - auch bei Wertaenderung
@param edge Ausfuehren bei RISING, FALLING or BOTH Wertaenderung :param edge: Ausfuehren bei RISING, FALLING or BOTH Wertaenderung
@param as_thread Bei True, Funktion als EventCallback-Thread ausfuehren :param as_thread: Bei True, Funktion als EventCallback-Thread ausfuehren
""" """
self.__reg_xevent(func, delay, edge, as_thread, False, False) self.__reg_xevent(func, delay, edge, as_thread, False, False)
def set_value(self, value): def set_value(self, value) -> None:
"""Setzt den Wert des IOs. """
@param value IO-Wert als <class bytes'> oder <class 'bool'>""" Setzt den Wert des IOs.
:param value: IO-Wert als <class bytes'> oder <class 'bool'>
"""
if self._iotype == INP: if self._iotype == INP:
if self._parentdevice._modio._simulator: if self._parentdevice._modio._simulator:
raise RuntimeError( raise RuntimeError(
@@ -643,12 +694,12 @@ class IOBase(object):
else: else:
self._parentdevice._ba_devdata[self._slc_address] = value self._parentdevice._ba_devdata[self._slc_address] = value
def unreg_event(self, func=None, edge=None): def unreg_event(self, func=None, edge=None) -> None:
"""Entfernt ein Event aus der Eventueberwachung. """
Entfernt ein Event aus der Eventueberwachung.
@param func Nur Events mit angegebener Funktion
@param edge Nur Events mit angegebener Funktion und angegebener Edge
: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 self in self._parentdevice._dict_events:
if func is None: if func is None:
@@ -659,7 +710,6 @@ class IOBase(object):
for regfunc in self._parentdevice._dict_events[self]: for regfunc in self._parentdevice._dict_events[self]:
if regfunc.func != func or edge is not None \ if regfunc.func != func or edge is not None \
and regfunc.edge != edge: and regfunc.edge != edge:
newlist.append(regfunc) newlist.append(regfunc)
# Wenn Funktionen übrig bleiben, diese übernehmen # Wenn Funktionen übrig bleiben, diese übernehmen
@@ -669,8 +719,9 @@ class IOBase(object):
else: else:
del self._parentdevice._dict_events[self] del self._parentdevice._dict_events[self]
def wait(self, edge=BOTH, exitevent=None, okvalue=None, timeout=0): def wait(self, edge=BOTH, exitevent=None, okvalue=None, timeout=0) -> int:
"""Wartet auf Wertaenderung eines IOs. """
Wartet auf Wertaenderung eines IOs.
Die Wertaenderung wird immer uerberprueft, wenn fuer Devices Die Wertaenderung wird immer uerberprueft, wenn fuer Devices
mit aktiviertem autorefresh neue Daten gelesen wurden. mit aktiviertem autorefresh neue Daten gelesen wurden.
@@ -696,19 +747,18 @@ class IOBase(object):
der autorefresh Funktion berechnet, entspricht also nicht exakt den der autorefresh Funktion berechnet, entspricht also nicht exakt den
angegeben Millisekunden! Es wird immer nach oben gerundet!) angegeben Millisekunden! Es wird immer nach oben gerundet!)
@param edge Flanke RISING, FALLING, BOTH die eintreten muss :param edge: Flanke RISING, FALLING, BOTH die eintreten muss
@param exitevent <class 'thrading.Event'> fuer vorzeitiges Beenden :param exitevent: <class 'thrading.Event'> fuer vorzeitiges Beenden
@param okvalue IO-Wert, bei dem das Warten sofort beendet wird :param okvalue: IO-Wert, bei dem das Warten sofort beendet wird
@param timeout Zeit in ms nach der abgebrochen wird :param timeout: Zeit in ms nach der abgebrochen wird
@return <class 'int'> erfolgreich Werte <= 0 :return: <class 'int'> erfolgreich Werte <= 0
- Erfolgreich gewartet * Erfolgreich gewartet
Wert 0: IO hat den Wert gewechselt ** Wert 0: IO hat den Wert gewechselt
Wert -1: okvalue stimmte mit IO ueberein ** Wert -1: okvalue stimmte mit IO ueberein
- Fehlerhaft gewartet * Fehlerhaft gewartet
Wert 1: exitevent wurde gesetzt ** Wert 1: exitevent wurde gesetzt
Wert 2: timeout abgelaufen ** Wert 2: timeout abgelaufen
Wert 100: Devicelist.exit() wurde aufgerufen ** Wert 100: Devicelist.exit() wurde aufgerufen
""" """
# Prüfen ob Device in autorefresh ist # Prüfen ob Device in autorefresh ist
if not self._parentdevice._selfupdate: if not self._parentdevice._selfupdate:
@@ -791,68 +841,89 @@ class IOBase(object):
class IntIO(IOBase): 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 <class 'IOBase'> um Funktionen, Diese Klasse erweitert die Funktion von <class 'IOBase'> um Funktionen,
ueber die mit <class 'int'> Werten gearbeitet werden kann. Fuer die ueber die mit <class 'int'> Werten gearbeitet werden kann. Fuer die
Umwandlung koennen 'Byteorder' (Default 'little') und 'signed' (Default Umwandlung koennen 'Byteorder' (Default 'little') und 'signed' (Default
False) als Parameter gesetzt werden. False) als Parameter gesetzt werden.
@see #IOBase IOBase
:ref:`IOBase`
""" """
__slots__ = () __slots__ = ()
def __int__(self): def __int__(self):
"""Gibt IO-Wert zurueck mit Beachtung byteorder/signed. """
@return IO-Wert als <class 'int'>""" Gibt IO-Wert zurueck mit Beachtung byteorder/signed.
:return: IO-Wert als <class 'int'>
"""
return int.from_bytes( return int.from_bytes(
self._parentdevice._ba_devdata[self._slc_address], self._parentdevice._ba_devdata[self._slc_address],
byteorder=self._byteorder, byteorder=self._byteorder,
signed=self._signed signed=self._signed
) )
def _get_signed(self): def _get_signed(self) -> bool:
"""Ruft ab, ob der Wert Vorzeichenbehaftet behandelt werden soll. """
@return True, wenn Vorzeichenbehaftet""" Ruft ab, ob der Wert Vorzeichenbehaftet behandelt werden soll.
:return: True, wenn Vorzeichenbehaftet
"""
return self._signed return self._signed
def _set_byteorder(self, value): def _set_byteorder(self, value: str) -> None:
"""Setzt Byteorder fuer <class 'int'> Umwandlung. """
@param value <class 'str'> 'little' or 'big'""" Setzt Byteorder fuer <class 'int'> Umwandlung.
:param value: <class 'str'> 'little' or 'big'
"""
if not (value == "little" or value == "big"): if not (value == "little" or value == "big"):
raise ValueError("byteorder must be 'little' or 'big'") raise ValueError("byteorder must be 'little' or 'big'")
if self._byteorder != value: if self._byteorder != value:
self._byteorder = value self._byteorder = value
self._defaultvalue = self._defaultvalue[::-1] self._defaultvalue = self._defaultvalue[::-1]
def _set_signed(self, value): def _set_signed(self, value: bool) -> None:
"""Left fest, ob der Wert Vorzeichenbehaftet behandelt werden soll. """
@param value True, wenn mit Vorzeichen behandel""" Left fest, ob der Wert Vorzeichenbehaftet behandelt werden soll.
:param value: True, wenn mit Vorzeichen behandel
"""
if type(value) != bool: if type(value) != bool:
raise TypeError("signed must be <class 'bool'> True or False") raise TypeError("signed must be <class 'bool'> True or False")
self._signed = value self._signed = value
def get_intdefaultvalue(self): def get_intdefaultvalue(self) -> int:
"""Gibt die Defaultvalue als <class 'int'> zurueck. """
@return <class 'int'> Defaultvalue""" Gibt die Defaultvalue als <class 'int'> zurueck.
:return: <class 'int'> Defaultvalue
"""
return int.from_bytes( return int.from_bytes(
self._defaultvalue, byteorder=self._byteorder, signed=self._signed self._defaultvalue, byteorder=self._byteorder, signed=self._signed
) )
def get_intvalue(self): def get_intvalue(self) -> int:
"""Gibt IO-Wert zurueck mit Beachtung byteorder/signed. """
@return IO-Wert als <class 'int'>""" Gibt IO-Wert zurueck mit Beachtung byteorder/signed.
:return: IO-Wert als <class 'int'>
"""
return int.from_bytes( return int.from_bytes(
self._parentdevice._ba_devdata[self._slc_address], self._parentdevice._ba_devdata[self._slc_address],
byteorder=self._byteorder, byteorder=self._byteorder,
signed=self._signed signed=self._signed
) )
def set_intvalue(self, value): def set_intvalue(self, value: int) -> None:
"""Setzt IO mit Beachtung byteorder/signed. """
@param value <class 'int'> Wert""" Setzt IO mit Beachtung byteorder/signed.
:param value: <class 'int'> Wert
"""
if type(value) == int: if type(value) == int:
self.set_value(value.to_bytes( self.set_value(value.to_bytes(
self._length, self._length,
@@ -872,19 +943,18 @@ class IntIO(IOBase):
class IntIOCounter(IntIO): class IntIOCounter(IntIO):
"""Erweitert die IntIO-Klasse um die .reset() Funktion fuer Counter.""" """Erweitert die IntIO-Klasse um die .reset() Funktion fuer Counter."""
__slots__ = ("__ioctl_arg") __slots__ = ("__ioctl_arg", )
def __init__( def __init__(
self, counter_id, self, counter_id,
parentdevice, valuelist, iotype, byteorder, signed): parentdevice, valuelist, iotype, byteorder, signed):
"""Instantiierung der IntIOCounter-Klasse. """
Instantiierung der IntIOCounter-Klasse.
@param counter_id ID fuer den Counter, zu dem der IO gehoert (0-15)
@see #IOBase.__init__ IOBase.__init__(...)
:param counter_id: ID fuer den Counter, zu dem der IO gehoert (0-15)
:ref: :func:`IOBase.__init__(...)`
""" """
if not isinstance(counter_id, int): if not isinstance(counter_id, int):
raise TypeError("counter_id must be <class 'int'>") raise TypeError("counter_id must be <class 'int'>")
@@ -912,7 +982,7 @@ class IntIOCounter(IntIO):
# Basisklasse laden # Basisklasse laden
super().__init__(parentdevice, valuelist, iotype, byteorder, signed) super().__init__(parentdevice, valuelist, iotype, byteorder, signed)
def reset(self): def reset(self) -> None:
"""Setzt den Counter des Inputs zurueck.""" """Setzt den Counter des Inputs zurueck."""
if self._parentdevice._modio._monitoring: if self._parentdevice._modio._monitoring:
raise RuntimeError( raise RuntimeError(
@@ -957,13 +1027,13 @@ class IntIOCounter(IntIO):
class IntIOReplaceable(IntIO): class IntIOReplaceable(IntIO):
"""Erweitert die IntIO-Klasse um die .replace_io Funktion.""" """Erweitert die IntIO-Klasse um die .replace_io Funktion."""
__slots__ = () __slots__ = ()
def replace_io(self, name, frm, **kwargs): def replace_io(self, name: str, frm: str, **kwargs) -> None:
"""Ersetzt bestehenden IO mit Neuem. """
Ersetzt bestehenden IO mit Neuem.
Wenn die kwargs fuer byteorder und defaultvalue nicht angegeben werden, Wenn die kwargs fuer byteorder und defaultvalue nicht angegeben werden,
uebernimmt das System die Daten aus dem ersetzten IO. 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 der urspruenglige IO hat, werden die nachfolgenden IOs ebenfalls
verwendet und entfernt. verwendet und entfernt.
@param name Name des neuen Inputs :param name: Name des neuen Inputs
@param frm struct formatierung (1 Zeichen) oder 'ANZAHLs' z.B. '8s' :param frm: struct formatierung (1 Zeichen) oder 'ANZAHLs' z.B. '8s'
@param kwargs Weitere Parameter: :param kwargs: Weitere Parameter:
- bmk: interne Bezeichnung fuer IO - bmk: interne Bezeichnung fuer IO
- bit: Registriert IO als <class 'bool'> am angegebenen Bit im Byte - bit: Registriert IO als <class 'bool'> am angegebenen Bit im Byte
- byteorder: Byteorder fuer den IO, Standardwert=little - byteorder: Byteorder fuer den IO, Standardwert=little
@@ -995,10 +1065,7 @@ class IntIOReplaceable(IntIO):
- edge: Event ausfuehren bei RISING, FALLING or BOTH Wertaenderung - edge: Event ausfuehren bei RISING, FALLING or BOTH Wertaenderung
- as_thread: Fuehrt die event-Funktion als RevPiCallback-Thread aus - as_thread: Fuehrt die event-Funktion als RevPiCallback-Thread aus
- prefire: Ausloesen mit aktuellem Wert, wenn mainloop startet - prefire: Ausloesen mit aktuellem Wert, wenn mainloop startet
@see <a target="_blank" `https://docs.python.org/3/library/struct.html#format-characters`
href="https://docs.python.org/3/library/struct.html#format-characters"
>Python3 struct</a>
""" """
# StructIO erzeugen # StructIO erzeugen
io_new = StructIO( io_new = StructIO(
@@ -1023,30 +1090,29 @@ class IntIOReplaceable(IntIO):
class StructIO(IOBase): 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 Sie stellt ueber struct die Werte in der gewuenschten Formatierung
bereit. Der struct-Formatwert wird bei der Instantiierung festgelegt. bereit. Der struct-Formatwert wird bei der Instantiierung festgelegt.
@see #IOBase IOBase :ref:`IOBase`
""" """
__slots__ = "__frm", "_parentio_address", "_parentio_defaultvalue", \ __slots__ = "__frm", "_parentio_address", "_parentio_defaultvalue", \
"_parentio_length", "_parentio_name" "_parentio_length", "_parentio_name"
def __init__(self, parentio, name, frm, **kwargs): def __init__(self, parentio, name: str, frm: str, **kwargs):
"""Erstellt einen IO mit struct-Formatierung. """
Erstellt einen IO mit struct-Formatierung.
@param parentio ParentIO Objekt, welches ersetzt wird :param parentio: ParentIO Objekt, welches ersetzt wird
@param name Name des neuen IO :param name: Name des neuen IO
@param frm struct formatierung (1 Zeichen) oder 'ANZAHLs' z.B. '8s' :param frm: struct formatierung (1 Zeichen) oder 'ANZAHLs' z.B. '8s'
@param kwargs Weitere Parameter: :param kwargs: Weitere Parameter:
- bmk: Bezeichnung fuer IO - bmk: Bezeichnung fuer IO
- bit: Registriert IO als <class 'bool'> am angegebenen Bit im Byte - bit: Registriert IO als <class 'bool'> am angegebenen Bit im Byte
- byteorder: Byteorder fuer IO, Standardwert vom ersetzten IO - byteorder: Byteorder fuer IO, Standardwert vom ersetzten IO
- defaultvalue: Standardwert fuer IO, Standard vom ersetzten IO - defaultvalue: Standardwert fuer IO, Standard vom ersetzten IO
""" """
# Structformatierung prüfen # Structformatierung prüfen
regex = rematch("^([0-9]*s|[cbB?hHiIlLqQefd])$", frm) regex = rematch("^([0-9]*s|[cbB?hHiIlLqQefd])$", frm)
@@ -1118,40 +1184,54 @@ class StructIO(IOBase):
parentio._parentdevice._dict_slc[parentio._iotype].start and parentio._parentdevice._dict_slc[parentio._iotype].start and
self._slc_address.stop <= self._slc_address.stop <=
parentio._parentdevice._dict_slc[parentio._iotype].stop): parentio._parentdevice._dict_slc[parentio._iotype].stop):
raise BufferError( raise BufferError(
"registered value does not fit process image scope" "registered value does not fit process image scope"
) )
def _get_frm(self): def _get_frm(self) -> str:
"""Ruft die struct Formatierung ab. """
@return struct Formatierung""" Ruft die struct Formatierung ab.
:return: struct Formatierung
"""
return self.__frm[1:] return self.__frm[1:]
def _get_signed(self): def _get_signed(self) -> bool:
"""Ruft ab, ob der Wert Vorzeichenbehaftet behandelt werden soll. """
@return True, wenn Vorzeichenbehaftet""" Ruft ab, ob der Wert Vorzeichenbehaftet behandelt werden soll.
:return: True, wenn Vorzeichenbehaftet
"""
return self._signed return self._signed
def get_structdefaultvalue(self): 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: if self._bitaddress >= 0:
return self._defaultvalue return self._defaultvalue
else: else:
return struct.unpack(self.__frm, self._defaultvalue)[0] return struct.unpack(self.__frm, self._defaultvalue)[0]
def get_structvalue(self): 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: if self._bitaddress >= 0:
return self.get_value() return self.get_value()
else: else:
return struct.unpack(self.__frm, self.get_value())[0] return struct.unpack(self.__frm, self.get_value())[0]
def set_structvalue(self, value): 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: if self._bitaddress >= 0:
self.set_value(value) self.set_value(value)
else: else: