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")

File diff suppressed because it is too large Load Diff

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,13 +83,12 @@ 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", \
"__dict_ton", "__dict_tof", "__dict_tp", "first", \ "__dict_ton", "__dict_tof", "__dict_tp", "first", \
"flag1c", "flag5c", "flag10c", "flag15c", "flag20c", \ "flag1c", "flag5c", "flag10c", "flag15c", "flag20c", \
"flank5c", "flank10c", "flank15c", "flank20c", "var" "flank5c", "flank10c", "flank15c", "flank20c", "var"
def __init__(self, cycletime): def __init__(self, cycletime):
"""Init Cycletools class.""" """Init Cycletools class."""
@@ -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,22 +299,20 @@ 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", \
"_adjwait", "_eventq", "_modio", \ "_adjwait", "_eventq", "_modio", \
"_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):
@@ -472,7 +495,7 @@ class ProcimgWriter(Thread):
with dev._filelock: with dev._filelock:
dev._ba_devdata[dev._slc_inp] = \ dev._ba_devdata[dev._slc_inp] = \
bytesbuff[dev._slc_inpoff] bytesbuff[dev._slc_inpoff]
if self.__eventwork\ if self.__eventwork \
and len(dev._dict_events) > 0 \ and len(dev._dict_events) > 0 \
and dev._ba_datacp != dev._ba_devdata: and dev._ba_datacp != dev._ba_devdata:
self.__check_change(dev) self.__check_change(dev)

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]:
@@ -128,17 +143,19 @@ class IOList(object):
if key in ( if key in (
"_IOList__dict_iobyte", "_IOList__dict_iobyte",
"_IOList__dict_iorefname" "_IOList__dict_iorefname"
): ):
object.__setattr__(self, key, value) object.__setattr__(self, key, value)
else: else:
raise AttributeError( raise AttributeError(
"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
@@ -192,12 +209,15 @@ class IOList(object):
io._defaultvalue = calc_defaultvalue io._defaultvalue = calc_defaultvalue
else: else:
io._defaultvalue = bool(io._parentio_defaultvalue[ io._defaultvalue = bool(io._parentio_defaultvalue[
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,24 +284,23 @@ 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", \
"_bitaddress", "_bitlength", "_byteorder", "_defaultvalue", \ "_bitaddress", "_bitlength", "_byteorder", "_defaultvalue", \
"_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],
@@ -368,28 +395,34 @@ class IOBase(object):
return bool(int_byte & 1 << self._bitaddress) return bool(int_byte & 1 << self._bitaddress)
else: else:
return self._parentdevice._ba_devdata[self._slc_address] != \ return self._parentdevice._ba_devdata[self._slc_address] != \
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: