mirror of
https://github.com/naruxde/revpimodio2.git
synced 2025-11-08 22:03:53 +01:00
reg_inp reg_out in IOList Klasse verschoben
This commit is contained in:
@@ -17,10 +17,13 @@ fuehrt das Modul bei Datenaenderung aus.
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
from .modio import *
|
from .modio import *
|
||||||
|
|
||||||
__all__ = ["RevPiModIO", "RevPiModIOSelected", "RevPiModIODriver"]
|
__all__ = ["RevPiModIO", "RevPiModIOSelected", "RevPiModIODriver"]
|
||||||
__author__ = "Sven Sager <akira@revpimodio.org>"
|
__author__ = "Sven Sager <akira@revpimodio.org>"
|
||||||
|
__name__ = "revpimodio2"
|
||||||
|
__package__ = "revpimodio2"
|
||||||
__version__ = "2.0.0"
|
__version__ = "2.0.0"
|
||||||
|
|
||||||
# Global package values
|
# Global package values
|
||||||
@@ -32,3 +35,11 @@ FALLING = 32
|
|||||||
BOTH = 33
|
BOTH = 33
|
||||||
|
|
||||||
warnings.simplefilter(action="always")
|
warnings.simplefilter(action="always")
|
||||||
|
|
||||||
|
class IOType(object):
|
||||||
|
|
||||||
|
"""IO Typen."""
|
||||||
|
|
||||||
|
INP = 300
|
||||||
|
OUT = 301
|
||||||
|
MEM = 302
|
||||||
|
|||||||
@@ -6,11 +6,12 @@
|
|||||||
#
|
#
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import struct
|
import struct
|
||||||
from .helper import ProcimgWriter
|
|
||||||
from .io import IOBase, IOType, IntIO, StructIO
|
|
||||||
from .__init__ import BOTH
|
|
||||||
from threading import Lock
|
from threading import Lock
|
||||||
|
|
||||||
|
from . import io as iomodule
|
||||||
|
from .__init__ import IOType
|
||||||
|
from .helper import ProcimgWriter
|
||||||
|
|
||||||
|
|
||||||
class DeviceList(object):
|
class DeviceList(object):
|
||||||
|
|
||||||
@@ -38,6 +39,11 @@ class DeviceList(object):
|
|||||||
else:
|
else:
|
||||||
return getattr(self, key)
|
return getattr(self, key)
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
"""Gibt Iterator aller Devices zurueck.
|
||||||
|
@return iter() aller Devices"""
|
||||||
|
return iter(self.__dict_position.values())
|
||||||
|
|
||||||
def __setattr__(self, key, value):
|
def __setattr__(self, key, value):
|
||||||
"""Setzt Attribute nur wenn Device.
|
"""Setzt Attribute nur wenn Device.
|
||||||
@param key Attributname
|
@param key Attributname
|
||||||
@@ -49,281 +55,6 @@ class DeviceList(object):
|
|||||||
object.__setattr__(self, key, value)
|
object.__setattr__(self, key, value)
|
||||||
|
|
||||||
|
|
||||||
class Devicelist():
|
|
||||||
|
|
||||||
"""Enthaelt alle Devices des RevolutionPi Buses."""
|
|
||||||
|
|
||||||
def __init__(self, parentmodio):
|
|
||||||
"""Instantiiert die einzelnen Bus-Devices.
|
|
||||||
|
|
||||||
@param procimg Dateiname des piControl Devices
|
|
||||||
|
|
||||||
"""
|
|
||||||
self._modio = parentmodio
|
|
||||||
self.core = self._modio.core
|
|
||||||
|
|
||||||
def __contains__(self, key):
|
|
||||||
"""Prueft ob Device existiert.
|
|
||||||
@param key DeviceName str() / Positionsnummer int()
|
|
||||||
@return True, wenn device vorhanden"""
|
|
||||||
return key in self._modio.device
|
|
||||||
|
|
||||||
def __getitem__(self, key):
|
|
||||||
"""Gibt angegebenes Device zurueck.
|
|
||||||
@param key DeviceName str() / Positionsnummer int()
|
|
||||||
@return Gefundenes RevPiDevice()-Objekt"""
|
|
||||||
return self._modio.device[key]
|
|
||||||
|
|
||||||
def __iter__(self):
|
|
||||||
"""Gibt alle Devices zurueck.
|
|
||||||
@return Iterator alle Devices"""
|
|
||||||
return iter(self._modio._device)
|
|
||||||
|
|
||||||
def __len__(self):
|
|
||||||
"""Gibt Anzahl der Devices zurueck.
|
|
||||||
@return int() Anzahl der Devices"""
|
|
||||||
return len(self._modio._device)
|
|
||||||
|
|
||||||
def auto_refresh(self, device, remove=False):
|
|
||||||
"""Registriert ein Device fuer die automatische Synchronisierung.
|
|
||||||
@param device Device fuer Synchronisierung
|
|
||||||
@param remove bool() True entfernt Device aus Synchronisierung"""
|
|
||||||
|
|
||||||
dev = device if issubclass(type(device), Device) \
|
|
||||||
else self._modio.device[device]
|
|
||||||
|
|
||||||
dev.auto_refresh(remove)
|
|
||||||
|
|
||||||
def auto_refresh_maxioerrors(self, value=None):
|
|
||||||
"""Maximale IO Fehler fuer auto_refresh.
|
|
||||||
@param value Setzt maximale Anzahl bis exception ausgeloest wird
|
|
||||||
@return Maximale Anzahl bis exception ausgeloest wird"""
|
|
||||||
return self._modio.auto_refresh_maxioerrors(value)
|
|
||||||
|
|
||||||
def auto_refresh_resetioerrors(self):
|
|
||||||
"""Setzt aktuellen IOError-Zaehler auf 0 zurueck."""
|
|
||||||
self._modio.auto_refresh_resetioerrors()
|
|
||||||
|
|
||||||
def cycleloop(self, func, cycletime=50):
|
|
||||||
"""Startet den Cycleloop.
|
|
||||||
|
|
||||||
Der aktuelle Programmthread wird hier bis Aufruf von
|
|
||||||
RevPiDevicelist.exit() "gefangen". Er fuehrt nach jeder Aktualisierung
|
|
||||||
des Prozessabbilds die uebergebene Funktion "func" aus und arbeitet sie
|
|
||||||
ab. Waehrend der Ausfuehrung der Funktion wird das Prozessabbild nicht
|
|
||||||
weiter aktualisiert. Die Inputs behalten bis zum Ende den aktuellen
|
|
||||||
Wert. Gesetzte Outputs werden nach Ende des Funktionsdurchlaufs in das
|
|
||||||
Prozessabbild geschrieben.
|
|
||||||
|
|
||||||
Verlassen wird der Cycleloop, wenn die aufgerufene Funktion einen
|
|
||||||
Rueckgabewert nicht gleich None liefert, oder durch Aufruf von
|
|
||||||
revpimodio.exit().
|
|
||||||
|
|
||||||
HINWEIS: Die Aktualisierungszeit und die Laufzeit der Funktion duerfen
|
|
||||||
die eingestellte auto_refresh Zeit, bzw. uebergebene cycletime nicht
|
|
||||||
ueberschreiten!
|
|
||||||
|
|
||||||
Ueber den Parameter cycletime kann die Aktualisierungsrate fuer das
|
|
||||||
Prozessabbild gesetzt werden (selbe Funktion wie
|
|
||||||
set_refreshtime(milliseconds)).
|
|
||||||
|
|
||||||
@param func Funktion, die ausgefuehrt werden soll
|
|
||||||
@param cycletime auto_refresh Wert in Millisekunden
|
|
||||||
@return None
|
|
||||||
|
|
||||||
"""
|
|
||||||
return self._modio.cycleloop(func, cycletime)
|
|
||||||
|
|
||||||
def exit(self, full=True):
|
|
||||||
"""Beendet mainloop() und optional auto_refresh.
|
|
||||||
|
|
||||||
Wenn sich das Programm im mainloop() befindet, wird durch Aufruf
|
|
||||||
von exit() die Kontrolle wieder an das Hauptprogramm zurueckgegeben.
|
|
||||||
|
|
||||||
Der Parameter full ist mit True vorbelegt und entfernt alle Devices aus
|
|
||||||
dem auto_refresh. Der Thread fuer die Prozessabbildsynchronisierung
|
|
||||||
wird dann gestoppt und das Programm kann sauber beendet werden.
|
|
||||||
|
|
||||||
@param full Entfernt auch alle Devices aus auto_refresh"""
|
|
||||||
self._modio.exit(full)
|
|
||||||
|
|
||||||
def get_devbyname(self, name):
|
|
||||||
"""Gibt durch Namen angegebenes Device zurueck.
|
|
||||||
@param name Devicename aus piCtory
|
|
||||||
@return Gefundenes RevPiDevice()"""
|
|
||||||
return self._modio.device[name]
|
|
||||||
|
|
||||||
def get_devbyposition(self, position):
|
|
||||||
"""Gibt durch Position angegebenes Device zurueck.
|
|
||||||
@param position Deviceposition aus piCtory
|
|
||||||
@return Gefundenes RevPiDevice()"""
|
|
||||||
return self._modio.device[position]
|
|
||||||
|
|
||||||
def get_refreshtime(self):
|
|
||||||
"""Gibt Aktualisierungsrate in ms der Prozessabbildsynchronisierung aus.
|
|
||||||
@return Millisekunden"""
|
|
||||||
return self._modio._imgwriter.refresh
|
|
||||||
|
|
||||||
def readprocimg(self, force=False, device=None):
|
|
||||||
"""Einlesen aller Inputs aller Devices vom Prozessabbild.
|
|
||||||
|
|
||||||
@param force auch Devices mit autoupdate=False
|
|
||||||
@param device nur auf einzelnes Device anwenden
|
|
||||||
@return True, wenn Arbeiten an allen Devices erfolgreich waren
|
|
||||||
|
|
||||||
"""
|
|
||||||
return self._modio.readprocimg(force, device)
|
|
||||||
|
|
||||||
def mainloop(self, freeze=False, blocking=True):
|
|
||||||
"""Startet den Mainloop mit Eventueberwachung.
|
|
||||||
|
|
||||||
Der aktuelle Programmthread wird hier bis Aufruf von
|
|
||||||
RevPiDevicelist.exit() "gefangen" (es sei denn blocking=False). Er
|
|
||||||
durchlaeuft die Eventueberwachung und prueft Aenderungen der, mit
|
|
||||||
einem Event registrierten, IOs. Wird eine Veraenderung erkannt,
|
|
||||||
fuert das Programm die dazugehoerigen Funktionen der Reihe nach aus.
|
|
||||||
|
|
||||||
Wenn der Parameter "freeze" mit True angegeben ist, wird die
|
|
||||||
Prozessabbildsynchronisierung angehalten bis alle Eventfunktionen
|
|
||||||
ausgefuehrt wurden. Inputs behalten fuer die gesamte Dauer ihren
|
|
||||||
aktuellen Wert und Outputs werden erst nach Durchlauf aller Funktionen
|
|
||||||
in das Prozessabbild geschrieben.
|
|
||||||
|
|
||||||
Wenn der Parameter "blocking" mit False angegeben wird, aktiviert
|
|
||||||
dies die Eventueberwachung und blockiert das Programm NICHT an der
|
|
||||||
Stelle des Aufrufs. Eignet sich gut fuer die GUI Programmierung, wenn
|
|
||||||
Events vom RevPi benoetigt werden, aber das Programm weiter ausgefuehrt
|
|
||||||
werden soll.
|
|
||||||
|
|
||||||
@param freeze Wenn True, Prozessabbildsynchronisierung anhalten
|
|
||||||
@param blocking Wenn False, blockiert das Programm NICHT
|
|
||||||
@return None
|
|
||||||
|
|
||||||
"""
|
|
||||||
return self._modio.mainloop(freeze, blocking)
|
|
||||||
|
|
||||||
def set_refreshtime(self, milliseconds):
|
|
||||||
"""Setzt Aktualisierungsrate der Prozessabbild-Synchronisierung.
|
|
||||||
@param milliseconds int() in Millisekunden"""
|
|
||||||
self._modio.set_refreshtime(milliseconds)
|
|
||||||
|
|
||||||
def setdefaultvalues(self, force=False, device=None):
|
|
||||||
"""Alle Outputbuffer werden auf die piCtory default Werte gesetzt.
|
|
||||||
@param force auch Devices mit autoupdate=False
|
|
||||||
@param device nur auf einzelnes Device anwenden"""
|
|
||||||
self._modio.setdefaultvalues(force, device)
|
|
||||||
|
|
||||||
def syncoutputs(self, force=False, device=None):
|
|
||||||
"""Lesen aller aktuell gesetzten Outputs im Prozessabbild.
|
|
||||||
|
|
||||||
@param force auch Devices mit autoupdate=False
|
|
||||||
@param device nur auf einzelnes Device anwenden
|
|
||||||
@return True, wenn Arbeiten an allen Devices erfolgreich waren
|
|
||||||
|
|
||||||
"""
|
|
||||||
return self._modio.syncoutputs(force, device)
|
|
||||||
|
|
||||||
def updateprocimg(self, force=False, device=None):
|
|
||||||
"""Schreiben/Lesen aller Outputs/Inputs aller Devices im Prozessab.
|
|
||||||
|
|
||||||
@param force auch Devices mit autoupdate=False
|
|
||||||
@param device nur auf einzelnes Device anwenden
|
|
||||||
@return True, wenn Arbeiten an allen Devices erfolgreich waren
|
|
||||||
|
|
||||||
"""
|
|
||||||
return self.readprocimg(force=force, device=device) and \
|
|
||||||
self.writeprocimg(force=force, device=device)
|
|
||||||
|
|
||||||
def wait(self, device, io, **kwargs):
|
|
||||||
"""Wartet auf Wertaenderung eines IOs.
|
|
||||||
|
|
||||||
Die Wertaenderung wird immer uerberprueft, wenn fuer Devices
|
|
||||||
in RevPiDevicelist.auto_refresh() neue Daten gelesen wurden.
|
|
||||||
|
|
||||||
Bei Wertaenderung, wird das Warten mit 0 als Rueckgabewert beendet.
|
|
||||||
|
|
||||||
HINWEIS: Wenn RevPiProcimgWriter() keine neuen Daten liefert, wird
|
|
||||||
bis in die Ewigkeit gewartet (nicht bei Angabe von "timeout").
|
|
||||||
|
|
||||||
Wenn edge mit RISING oder FALLING angegeben wird muss diese Flanke
|
|
||||||
ausgeloest werden. Sollte der Wert 1 sein beim Eintritt mit Flanke
|
|
||||||
RISING, wird das Warten erst bei Aenderung von 0 auf 1 beendet.
|
|
||||||
|
|
||||||
Als exitevent kann ein threading.Event()-Objekt uebergeben werden,
|
|
||||||
welches das Warten bei is_set() sofort mit 1 als Rueckgabewert
|
|
||||||
beendet.
|
|
||||||
|
|
||||||
Wenn der Wert okvalue an dem IO fuer das Warten anliegt, wird
|
|
||||||
das Warten sofort mit -1 als Rueckgabewert beendet.
|
|
||||||
|
|
||||||
Der Timeoutwert bricht beim Erreichen das Warten sofort mit
|
|
||||||
Wert 2 Rueckgabewert ab. (Das Timeout wird ueber die Zykluszeit
|
|
||||||
der auto_refresh Funktion berechnet, entspricht also nicht exact den
|
|
||||||
angegeben Millisekunden! Es wird immer nach oben gerundet!)
|
|
||||||
|
|
||||||
@param device Device auf dem sich der IO befindet
|
|
||||||
@param io Name des IOs auf dessen Aenderung gewartet wird
|
|
||||||
@param kwargs Weitere Parameter:
|
|
||||||
- edge: Flanke RISING, FALLING, BOTH bei der mit True beendet wird
|
|
||||||
- exitevent: thrading.Event() fuer vorzeitiges Beenden mit False
|
|
||||||
- okvalue: IO-Wert, bei dem das Warten sofort mit True beendet wird
|
|
||||||
- timeout: Zeit in ms nach der mit False abgebrochen wird
|
|
||||||
@return int() erfolgreich Werte <= 0
|
|
||||||
- Erfolgreich gewartet
|
|
||||||
Wert 0: IO hat den Wert gewechselt
|
|
||||||
Wert -1: okvalue stimmte mit IO ueberein
|
|
||||||
- Fehlerhaft gewartet
|
|
||||||
Wert 1: exitevent wurde gesetzt
|
|
||||||
Wert 2: timeout abgelaufen
|
|
||||||
Wert 100: RevPiDevicelist.exit() wurde aufgerufen
|
|
||||||
|
|
||||||
"""
|
|
||||||
dev = device if issubclass(type(device), Device) \
|
|
||||||
else self.__getitem__(device)
|
|
||||||
|
|
||||||
io_watch = dev[io]
|
|
||||||
if type(io_watch) == list:
|
|
||||||
if len(io_watch) == 1:
|
|
||||||
io_watch = io_watch[0]
|
|
||||||
else:
|
|
||||||
raise KeyError(
|
|
||||||
"byte '{}' contains more than one bit-input".format(io)
|
|
||||||
)
|
|
||||||
|
|
||||||
# kwargs auswerten
|
|
||||||
edge = kwargs.get("edge", BOTH)
|
|
||||||
evt_exit = kwargs.get("exitevent", None)
|
|
||||||
val_ok = kwargs.get("okvalue", None)
|
|
||||||
flt_timeout = kwargs.get("timeout", 0)
|
|
||||||
|
|
||||||
return io_watch.wait(edge, evt_exit, val_ok, flt_timeout)
|
|
||||||
|
|
||||||
def writedefaultinputs(self, virtual_device):
|
|
||||||
"""Schreibt fuer ein virtuelles Device piCtory Defaultinputwerte.
|
|
||||||
|
|
||||||
Sollten in piCtory Defaultwerte fuer Inputs eines virtuellen Devices
|
|
||||||
angegeben sein, werden diese nur beim Systemstart oder einem piControl
|
|
||||||
Reset gesetzt. Sollte danach das Prozessabbild mit NULL ueberschrieben,
|
|
||||||
gehen diese Werte verloren.
|
|
||||||
Diese Funktion kann nur auf virtuelle Devices angewendet werden!
|
|
||||||
|
|
||||||
@param virtual_device Virtuelles Device fuer Wiederherstellung
|
|
||||||
@return True, wenn Arbeiten am virtuellen Device erfolgreich waren
|
|
||||||
|
|
||||||
"""
|
|
||||||
return self._modio.writedefaultinputs(virtual_device)
|
|
||||||
|
|
||||||
def writeprocimg(self, force=False, device=None):
|
|
||||||
"""Schreiben aller Outputs aller Devices ins Prozessabbild.
|
|
||||||
|
|
||||||
@param force auch Devices mit autoupdate=False
|
|
||||||
@param device nur auf einzelnes Device anwenden
|
|
||||||
@return True, wenn Arbeiten an allen Devices erfolgreich waren
|
|
||||||
|
|
||||||
"""
|
|
||||||
return self._modio.writeprocimg(force, device)
|
|
||||||
|
|
||||||
|
|
||||||
class Device(object):
|
class Device(object):
|
||||||
|
|
||||||
"""Basisklasse fuer alle Device-Objekte der RevPiDevicelist()-Klasse.
|
"""Basisklasse fuer alle Device-Objekte der RevPiDevicelist()-Klasse.
|
||||||
@@ -403,8 +134,8 @@ class Device(object):
|
|||||||
return bytes(self._ba_devdata)
|
return bytes(self._ba_devdata)
|
||||||
|
|
||||||
def __contains__(self, key):
|
def __contains__(self, key):
|
||||||
"""Prueft ob IO existiert.
|
"""Prueft ob IO auf diesem Device liegt.
|
||||||
@param key IO-Name str() / Positionsnummer int()
|
@param key IO-Name str() / IO-Bytenummer int()
|
||||||
@return True, wenn device vorhanden"""
|
@return True, wenn device vorhanden"""
|
||||||
if type(key) == str:
|
if type(key) == str:
|
||||||
return hasattr(self._modio.io, key)
|
return hasattr(self._modio.io, key)
|
||||||
@@ -482,14 +213,14 @@ class Device(object):
|
|||||||
# Neuen IO anlegen
|
# Neuen IO anlegen
|
||||||
if bool(dict_io[key][7]) or self.producttype == 95:
|
if bool(dict_io[key][7]) or self.producttype == 95:
|
||||||
# Bei Bitwerten oder Core RevPiIOBase verwenden
|
# Bei Bitwerten oder Core RevPiIOBase verwenden
|
||||||
io_new = IOBase(
|
io_new = iomodule.IOBase(
|
||||||
self,
|
self,
|
||||||
dict_io[key],
|
dict_io[key],
|
||||||
iotype,
|
iotype,
|
||||||
byteorder="little"
|
byteorder="little"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
io_new = IntIO(
|
io_new = iomodule.IntIO(
|
||||||
self,
|
self,
|
||||||
dict_io[key],
|
dict_io[key],
|
||||||
iotype,
|
iotype,
|
||||||
@@ -611,57 +342,6 @@ class Device(object):
|
|||||||
@return IO-Objekt"""
|
@return IO-Objekt"""
|
||||||
return getattr(self._modio.io, name)
|
return getattr(self._modio.io, name)
|
||||||
|
|
||||||
def reg_event(self, io_name, func, edge=BOTH, as_thread=False):
|
|
||||||
"""Registriert ein Event bei der Eventueberwachung.
|
|
||||||
|
|
||||||
@param io_name Name des Inputs oder Outputs der ueberwacht wird
|
|
||||||
@param func Funktion die bei Aenderung aufgerufen werden soll
|
|
||||||
@param edge Ausfuehren bei RISING, FALLING or BOTH Wertaenderung
|
|
||||||
@param as_thread Bei True, Funktion als RevPiCallback-Thread ausfuehren
|
|
||||||
|
|
||||||
"""
|
|
||||||
io_event = self.__getitem__(io_name)
|
|
||||||
if type(io_event) == list:
|
|
||||||
if len(io_event) == 1:
|
|
||||||
io_event = io_event[0]
|
|
||||||
elif len(io_event) == 0:
|
|
||||||
raise KeyError(
|
|
||||||
"byte '{}' contains no io object".format(io_name))
|
|
||||||
else:
|
|
||||||
raise KeyError(
|
|
||||||
"byte '{}' contains more than one bit io object".format(
|
|
||||||
io_name
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
# NOTE: Abgelaufen
|
|
||||||
io_event.reg_event(func, edge, as_thread)
|
|
||||||
|
|
||||||
def unreg_event(self, io_name, func=None, edge=None):
|
|
||||||
"""Entfernt ein Event aus der Eventueberwachung.
|
|
||||||
|
|
||||||
@param io_name Name des Inputs, dessen Events entfert werden sollen
|
|
||||||
@param func Nur Events mit angegebener Funktion
|
|
||||||
@param edge Nur Events mit angegebener Funktion und angegebener Edge
|
|
||||||
|
|
||||||
"""
|
|
||||||
io_event = self.__getitem__(io_name)
|
|
||||||
if type(io_event) == list:
|
|
||||||
if len(io_event) == 1:
|
|
||||||
io_event = io_event[0]
|
|
||||||
elif len(io_event) == 0:
|
|
||||||
raise KeyError(
|
|
||||||
"byte '{}' contains no io object".format(io_name))
|
|
||||||
else:
|
|
||||||
raise KeyError(
|
|
||||||
"byte '{}' contains more than one bit io object".format(
|
|
||||||
io_name
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
# NOTE: Abgelaufen
|
|
||||||
io_event.unreg_event(func, edge)
|
|
||||||
|
|
||||||
|
|
||||||
class Core(Device):
|
class Core(Device):
|
||||||
|
|
||||||
@@ -913,81 +593,6 @@ class Gateway(Device):
|
|||||||
IOType.MEM: self.slc_mem
|
IOType.MEM: self.slc_mem
|
||||||
}
|
}
|
||||||
|
|
||||||
def _create_io(self, name, startio, frm, io_type, **kwargs):
|
|
||||||
"""Erstellt einen neuen IO und ersetzt den/die Bestehenden.
|
|
||||||
|
|
||||||
@param name Name des neuen IO
|
|
||||||
@param startio IO ab dem eingefuegt wird
|
|
||||||
@param frm struct() formatierung (1 Zeichen)
|
|
||||||
@param io_type IOType() Wert
|
|
||||||
@param kwargs Weitere Parameter:
|
|
||||||
- bmk: Bezeichnung fuer IO
|
|
||||||
- bit: Registriert IO als bool() am angegebenen Bit im Byte
|
|
||||||
- byteorder: Byteorder fuer diesen IO, Standardwert=little
|
|
||||||
- defaultvalue: Standardwert fuer IO, Standard ist 0
|
|
||||||
|
|
||||||
"""
|
|
||||||
if len(frm) == 1:
|
|
||||||
|
|
||||||
# Byteorder prüfen und übernehmen
|
|
||||||
byteorder = kwargs.get("byteorder", "little")
|
|
||||||
if not (byteorder == "little" or byteorder == "big"):
|
|
||||||
raise ValueError("byteorder must be 'little' or 'big'")
|
|
||||||
bofrm = "<" if byteorder == "little" else ">"
|
|
||||||
|
|
||||||
bitaddress = "" if frm != "?" else str(kwargs.get("bit", 0))
|
|
||||||
if bitaddress == "" or \
|
|
||||||
(int(bitaddress) >= 0 and int(bitaddress) < 8):
|
|
||||||
|
|
||||||
bitlength = "1" if bitaddress.isnumeric() else \
|
|
||||||
struct.calcsize(bofrm + frm) * 8
|
|
||||||
|
|
||||||
if startio in self._dict_iorefname:
|
|
||||||
startaddress = self._dict_iorefname[startio]
|
|
||||||
else:
|
|
||||||
startaddress = self.__getitem__(startio).slc_address.start
|
|
||||||
|
|
||||||
# [name,default,anzbits,adressbyte,export,adressid,bmk,bitaddress]
|
|
||||||
list_value = [
|
|
||||||
name,
|
|
||||||
kwargs.get("defaultvalue", 0),
|
|
||||||
bitlength,
|
|
||||||
startaddress,
|
|
||||||
False,
|
|
||||||
str(startaddress).rjust(4, "0"),
|
|
||||||
kwargs.get("bmk", ""),
|
|
||||||
bitaddress
|
|
||||||
]
|
|
||||||
|
|
||||||
# Neuen IO instantiieren
|
|
||||||
io_new = StructIO(
|
|
||||||
self,
|
|
||||||
list_value,
|
|
||||||
io_type,
|
|
||||||
byteorder,
|
|
||||||
bofrm + frm
|
|
||||||
)
|
|
||||||
io_new._byteorder = byteorder
|
|
||||||
|
|
||||||
# Platz für neuen IO prüfen
|
|
||||||
if (io_new.slc_address.start >=
|
|
||||||
self._dict_slc[io_type].start and
|
|
||||||
io_new.slc_address.stop <=
|
|
||||||
self._dict_slc[io_type].stop):
|
|
||||||
|
|
||||||
self._replace_io(io_new)
|
|
||||||
|
|
||||||
else:
|
|
||||||
raise BufferError(
|
|
||||||
"registered value does not fit process image scope"
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
raise AttributeError(
|
|
||||||
"bitaddress must be a value between 0 and 7"
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
raise AttributeError("parameter frm has to be a single sign")
|
|
||||||
|
|
||||||
def _getbytename(self, iobyte):
|
def _getbytename(self, iobyte):
|
||||||
"""Ermittelt den Namen eines IOs auf der Byteadresse.
|
"""Ermittelt den Namen eines IOs auf der Byteadresse.
|
||||||
@param iobyte Bytenummer
|
@param iobyte Bytenummer
|
||||||
@@ -1011,149 +616,11 @@ class Gateway(Device):
|
|||||||
else:
|
else:
|
||||||
raise KeyError("byte '{}' does not exist".format(iobyte))
|
raise KeyError("byte '{}' does not exist".format(iobyte))
|
||||||
|
|
||||||
def _replace_io(self, io):
|
|
||||||
"""Ersetzt bestehende IOs durch den neu Registrierten.
|
|
||||||
@param io Neuer IO der eingefuegt werden soll"""
|
|
||||||
if hasattr(self._modio.io, io.name):
|
|
||||||
raise NameError(
|
|
||||||
"name '{}' already exists on device '{}'".format(
|
|
||||||
io._name, self.name
|
|
||||||
)
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
dict_oldio = {}
|
|
||||||
for oldio in self._lst_io:
|
|
||||||
# Alle IOs Prüfen ob sie im neuen Speicherbereich sind
|
|
||||||
errstart = oldio.slc_address.start >= io.slc_address.start \
|
|
||||||
and oldio.slc_address.start < io.slc_address.stop
|
|
||||||
errstop = oldio.slc_address.stop > io.slc_address.start \
|
|
||||||
and oldio.slc_address.stop <= io.slc_address.stop
|
|
||||||
|
|
||||||
if errstart or errstop:
|
|
||||||
if type(oldio) == StructIO:
|
|
||||||
# Hier gibt es schon einen neuen IO
|
|
||||||
if oldio._bitaddress >= 0:
|
|
||||||
if io._bitaddress == oldio._bitaddress:
|
|
||||||
raise MemoryError(
|
|
||||||
"bit {} already assigned to '{}'".format(
|
|
||||||
io._bitaddress, oldio._name
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
else:
|
|
||||||
# Bereits überschriebene bytes() sind ungültig
|
|
||||||
raise MemoryError(
|
|
||||||
"new io '{}' overlaps memory of '{}'".format(
|
|
||||||
io._name, oldio._name
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
else:
|
|
||||||
# IOs im Speicherbereich des neuen IO merken
|
|
||||||
dict_oldio[oldio.name] = oldio
|
|
||||||
|
|
||||||
for oldio in dict_oldio.values():
|
|
||||||
if io._bitaddress >= 0:
|
|
||||||
# ios für ref bei bitaddress speichern
|
|
||||||
self._dict_iorefbyte[oldio.slc_address.start] = oldio.name
|
|
||||||
self._dict_iorefname[oldio.name] = oldio.slc_address.start
|
|
||||||
|
|
||||||
# ios aus listen entfernen
|
|
||||||
delattr(self._modio.io, oldio.name)
|
|
||||||
self._lst_io.remove(oldio)
|
|
||||||
|
|
||||||
# Namensregister erweitern
|
|
||||||
setattr(self._modio.io, io.name, io)
|
|
||||||
|
|
||||||
# io einfügen (auch wenn nicht richtige stelle wegen BitOffset)
|
|
||||||
self._lst_io.insert(io.slc_address.start, io)
|
|
||||||
|
|
||||||
# Liste neu sortieren
|
|
||||||
self._lst_io.sort(key=lambda x: x.slc_address.start)
|
|
||||||
|
|
||||||
def get_rawbytes(self):
|
def get_rawbytes(self):
|
||||||
"""Gibt die Bytes aus, die dieses Device verwendet.
|
"""Gibt die Bytes aus, die dieses Device verwendet.
|
||||||
@return bytes() des Devices"""
|
@return bytes() des Devices"""
|
||||||
return bytes(self._ba_devdata)
|
return bytes(self._ba_devdata)
|
||||||
|
|
||||||
def reg_inp(self, name, startinp, frm, **kwargs):
|
|
||||||
"""Registriert einen neuen Input.
|
|
||||||
|
|
||||||
@param name Name des neuen Inputs
|
|
||||||
@param startinp Inputname ab dem eingefuegt wird
|
|
||||||
@param frm struct() formatierung (1 Zeichen)
|
|
||||||
@param kwargs Weitere Parameter:
|
|
||||||
- bmk: Bezeichnung fuer Input
|
|
||||||
- bit: Registriert Input als bool() am angegebenen Bit im Byte
|
|
||||||
- byteorder: Byteorder fuer den Input, Standardwert=little
|
|
||||||
- defaultvalue: Standardwert fuer Input, Standard ist 0
|
|
||||||
- event: Funktion fuer Eventhandling registrieren
|
|
||||||
- as_thread: Fuehrt die event-Funktion als RevPiCallback-Thread aus
|
|
||||||
- edge: event-Ausfuehren bei RISING, FALLING or BOTH Wertaenderung
|
|
||||||
@see <a target="_blank"
|
|
||||||
href="https://docs.python.org/3/library/struct.html#format-characters"
|
|
||||||
>Python3 struct()</a>
|
|
||||||
|
|
||||||
"""
|
|
||||||
if type(startinp) == int:
|
|
||||||
# Byte int() umwandeln in Namen
|
|
||||||
startinp = self._getbytename(startinp)
|
|
||||||
|
|
||||||
if type(startinp) == str:
|
|
||||||
self._create_io(name, startinp, frm, IOType.INP, **kwargs)
|
|
||||||
else:
|
|
||||||
raise TypeError(
|
|
||||||
"start input must be str() or int() not {}".format(
|
|
||||||
type(startinp)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
# Optional Event eintragen
|
|
||||||
reg_event = kwargs.get("event", None)
|
|
||||||
if reg_event is not None:
|
|
||||||
as_thread = kwargs.get("as_thread", False)
|
|
||||||
edge = kwargs.get("edge", None)
|
|
||||||
self.reg_event(name, reg_event, as_thread=as_thread, edge=edge)
|
|
||||||
|
|
||||||
def reg_out(self, name, startout, frm, **kwargs):
|
|
||||||
"""Registriert einen neuen Output.
|
|
||||||
|
|
||||||
@param name Name des neuen Outputs
|
|
||||||
@param startout Outputname ab dem eingefuegt wird
|
|
||||||
@param frm struct() formatierung (1 Zeichen)
|
|
||||||
@param kwargs Weitere Parameter:
|
|
||||||
- bmk: Bezeichnung fuer Output
|
|
||||||
- bit: Registriert Outputs als bool() am angegebenen Bit im Byte
|
|
||||||
- byteorder: Byteorder fuer den Output, Standardwert=little
|
|
||||||
- defaultvalue: Standardwert fuer Output, Standard ist 0
|
|
||||||
- event: Funktion fuer Eventhandling registrieren
|
|
||||||
- as_thread: Fuehrt die event-Funktion als RevPiCallback-Thread aus
|
|
||||||
- edge: event-Ausfuehren bei RISING, FALLING or BOTH Wertaenderung
|
|
||||||
@see <a target="_blank"
|
|
||||||
href="https://docs.python.org/3/library/struct.html#format-characters"
|
|
||||||
>Python3 struct()</a>
|
|
||||||
|
|
||||||
"""
|
|
||||||
if type(startout) == int:
|
|
||||||
# Byte int() umwandeln in Namen
|
|
||||||
startout = self._getbytename(startout)
|
|
||||||
|
|
||||||
if type(startout) == str:
|
|
||||||
self._create_io(name, startout, frm, IOType.OUT, **kwargs)
|
|
||||||
else:
|
|
||||||
raise TypeError(
|
|
||||||
"start output must be str() or int() not {}".format(
|
|
||||||
type(startout)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
# Optional Event eintragen
|
|
||||||
reg_event = kwargs.get("event", None)
|
|
||||||
if reg_event is not None:
|
|
||||||
as_thread = kwargs.get("as_thread", False)
|
|
||||||
edge = kwargs.get("edge", None)
|
|
||||||
self.reg_event(name, reg_event, as_thread=as_thread, edge=edge)
|
|
||||||
|
|
||||||
|
|
||||||
class Virtual(Gateway):
|
class Virtual(Gateway):
|
||||||
|
|
||||||
|
|||||||
@@ -6,18 +6,10 @@
|
|||||||
#
|
#
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import struct
|
import struct
|
||||||
from .__init__ import RISING, FALLING, BOTH
|
|
||||||
from .device import Gateway
|
|
||||||
from threading import Event
|
from threading import Event
|
||||||
|
|
||||||
|
from . import device as devicemodule
|
||||||
class IOType(object):
|
from .__init__ import RISING, FALLING, BOTH, IOType
|
||||||
|
|
||||||
"""IO Typen."""
|
|
||||||
|
|
||||||
INP = 300
|
|
||||||
OUT = 301
|
|
||||||
MEM = 302
|
|
||||||
|
|
||||||
|
|
||||||
class IOList(object):
|
class IOList(object):
|
||||||
@@ -42,6 +34,8 @@ class IOList(object):
|
|||||||
"""Entfernt angegebenen IO.
|
"""Entfernt angegebenen IO.
|
||||||
@param key IO zum entfernen"""
|
@param key IO zum entfernen"""
|
||||||
# TODO: Prüfen ob auch Bit sein kann
|
# TODO: Prüfen ob auch Bit sein kann
|
||||||
|
# FIXME: IO von DeviceIO Liste entfernen
|
||||||
|
# FIXME: IO aus Eventhandling entfernen
|
||||||
dev = getattr(self, key)
|
dev = getattr(self, key)
|
||||||
self.__dict_iobyte[dev.address].remove(dev)
|
self.__dict_iobyte[dev.address].remove(dev)
|
||||||
object.__delattr__(self, key)
|
object.__delattr__(self, key)
|
||||||
@@ -58,6 +52,13 @@ class IOList(object):
|
|||||||
else:
|
else:
|
||||||
return getattr(self, key)
|
return getattr(self, key)
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
"""Gibt Iterator aller IOs zurueck.
|
||||||
|
@return Iterator aller IOs"""
|
||||||
|
for int_io in sorted(self.__dict_iobyte):
|
||||||
|
for io in self.__dict_iobyte[int_io]:
|
||||||
|
yield io
|
||||||
|
|
||||||
def __setitem__(self, key, value):
|
def __setitem__(self, key, value):
|
||||||
"""Setzt IO Wert.
|
"""Setzt IO Wert.
|
||||||
@param key IO Name oder Byte
|
@param key IO Name oder Byte
|
||||||
@@ -106,77 +107,70 @@ class IOList(object):
|
|||||||
else:
|
else:
|
||||||
getattr(self, key).value = value
|
getattr(self, key).value = value
|
||||||
|
|
||||||
|
def _replace_io(self, io):
|
||||||
|
"""Ersetzt bestehende IOs durch den neu Registrierten.
|
||||||
|
@param io Neuer IO der eingefuegt werden soll"""
|
||||||
|
dict_oldio = {}
|
||||||
|
for oldio in self._lst_io:
|
||||||
|
# Alle IOs Prüfen ob sie im neuen Speicherbereich sind
|
||||||
|
errstart = oldio.slc_address.start >= io.slc_address.start \
|
||||||
|
and oldio.slc_address.start < io.slc_address.stop
|
||||||
|
errstop = oldio.slc_address.stop > io.slc_address.start \
|
||||||
|
and oldio.slc_address.stop <= io.slc_address.stop
|
||||||
|
|
||||||
|
if errstart or errstop:
|
||||||
|
if type(oldio) == StructIO:
|
||||||
|
# Hier gibt es schon einen neuen IO
|
||||||
|
if oldio._bitaddress >= 0:
|
||||||
|
if io._bitaddress == oldio._bitaddress:
|
||||||
|
raise MemoryError(
|
||||||
|
"bit {} already assigned to '{}'".format(
|
||||||
|
io._bitaddress, oldio._name
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
else:
|
||||||
|
# Bereits überschriebene bytes() sind ungültig
|
||||||
|
raise MemoryError(
|
||||||
|
"new io '{}' overlaps memory of '{}'".format(
|
||||||
|
io._name, oldio._name
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
else:
|
||||||
|
# IOs im Speicherbereich des neuen IO merken
|
||||||
|
dict_oldio[oldio.name] = oldio
|
||||||
|
|
||||||
|
for oldio in dict_oldio.values():
|
||||||
|
if io._bitaddress >= 0:
|
||||||
|
# ios für ref bei bitaddress speichern
|
||||||
|
self._dict_iorefbyte[oldio.slc_address.start] = oldio.name
|
||||||
|
self._dict_iorefname[oldio.name] = oldio.slc_address.start
|
||||||
|
|
||||||
|
# ios aus listen entfernen
|
||||||
|
delattr(self._modio.io, oldio.name)
|
||||||
|
self._lst_io.remove(oldio)
|
||||||
|
|
||||||
|
# Namensregister erweitern
|
||||||
|
setattr(self._modio.io, io.name, io)
|
||||||
|
|
||||||
|
# io einfügen (auch wenn nicht richtige stelle wegen BitOffset)
|
||||||
|
self._lst_io.insert(io.slc_address.start, io)
|
||||||
|
|
||||||
|
# Liste neu sortieren
|
||||||
|
self._lst_io.sort(key=lambda x: x.slc_address.start)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def _testme(self):
|
def _testme(self):
|
||||||
# NOTE: Nur Debugging
|
# NOTE: Nur Debugging
|
||||||
for x in self.__dict_iobyte:
|
for x in self.__dict_iobyte:
|
||||||
if len(self.__dict_iobyte[x]) > 0:
|
if len(self.__dict_iobyte[x]) > 0:
|
||||||
print(x, self.__dict_iobyte[x])
|
print(x, self.__dict_iobyte[x])
|
||||||
|
|
||||||
def reg_inp(self, name, frm, **kwargs):
|
|
||||||
"""Registriert einen neuen Input an Adresse von Diesem.
|
|
||||||
|
|
||||||
@param name Name des neuen Inputs
|
|
||||||
@param frm struct() formatierung (1 Zeichen)
|
|
||||||
@param kwargs Weitere Parameter:
|
|
||||||
- bmk: Bezeichnung fuer Input
|
|
||||||
- bit: Registriert Input als bool() am angegebenen Bit im Byte
|
|
||||||
- byteorder: Byteorder fuer den Input, Standardwert=little
|
|
||||||
- defaultvalue: Standardwert fuer Input, Standard ist 0
|
|
||||||
- event: Funktion fuer Eventhandling registrieren
|
|
||||||
- as_thread: Fuehrt die event-Funktion als RevPiCallback-Thread aus
|
|
||||||
- edge: event-Ausfuehren bei RISING, FALLING or BOTH Wertaenderung
|
|
||||||
@see <a target="_blank"
|
|
||||||
href="https://docs.python.org/3/library/struct.html#format-characters"
|
|
||||||
>Python3 struct()</a>
|
|
||||||
|
|
||||||
"""
|
|
||||||
if not issubclass(self._parentdevice, Gateway):
|
|
||||||
raise RuntimeError(
|
|
||||||
"this function can be used on gatway or virtual devices only"
|
|
||||||
)
|
|
||||||
|
|
||||||
self._create_io(name, startinp, frm, IOType.INP, **kwargs)
|
|
||||||
|
|
||||||
# Optional Event eintragen
|
|
||||||
reg_event = kwargs.get("event", None)
|
|
||||||
if reg_event is not None:
|
|
||||||
as_thread = kwargs.get("as_thread", False)
|
|
||||||
edge = kwargs.get("edge", None)
|
|
||||||
self.reg_event(name, reg_event, as_thread=as_thread, edge=edge)
|
|
||||||
|
|
||||||
def reg_out(self, name, startout, frm, **kwargs):
|
|
||||||
"""Registriert einen neuen Output.
|
|
||||||
|
|
||||||
@param name Name des neuen Outputs
|
|
||||||
@param startout Outputname ab dem eingefuegt wird
|
|
||||||
@param frm struct() formatierung (1 Zeichen)
|
|
||||||
@param kwargs Weitere Parameter:
|
|
||||||
- bmk: Bezeichnung fuer Output
|
|
||||||
- bit: Registriert Outputs als bool() am angegebenen Bit im Byte
|
|
||||||
- byteorder: Byteorder fuer den Output, Standardwert=little
|
|
||||||
- defaultvalue: Standardwert fuer Output, Standard ist 0
|
|
||||||
- event: Funktion fuer Eventhandling registrieren
|
|
||||||
- as_thread: Fuehrt die event-Funktion als RevPiCallback-Thread aus
|
|
||||||
- edge: event-Ausfuehren bei RISING, FALLING or BOTH Wertaenderung
|
|
||||||
@see <a target="_blank"
|
|
||||||
href="https://docs.python.org/3/library/struct.html#format-characters"
|
|
||||||
>Python3 struct()</a>
|
|
||||||
|
|
||||||
"""
|
|
||||||
if not issubclass(self._parentdevice, Gateway):
|
|
||||||
raise RuntimeError(
|
|
||||||
"this function can be used on gatway or virtual devices only"
|
|
||||||
)
|
|
||||||
|
|
||||||
self._create_io(name, startout, frm, IOType.OUT, **kwargs)
|
|
||||||
|
|
||||||
# Optional Event eintragen
|
|
||||||
reg_event = kwargs.get("event", None)
|
|
||||||
if reg_event is not None:
|
|
||||||
as_thread = kwargs.get("as_thread", False)
|
|
||||||
edge = kwargs.get("edge", None)
|
|
||||||
self.reg_event(name, reg_event, as_thread=as_thread, edge=edge)
|
|
||||||
|
|
||||||
|
|
||||||
class IOBase(object):
|
class IOBase(object):
|
||||||
|
|
||||||
@@ -352,6 +346,90 @@ class IOBase(object):
|
|||||||
)
|
)
|
||||||
break
|
break
|
||||||
|
|
||||||
|
def reg_inp(self, name, frm, **kwargs):
|
||||||
|
"""Registriert einen neuen Input an Adresse von Diesem.
|
||||||
|
|
||||||
|
@param name Name des neuen Inputs
|
||||||
|
@param frm struct() formatierung (1 Zeichen)
|
||||||
|
@param kwargs Weitere Parameter:
|
||||||
|
- bmk: Bezeichnung fuer Input
|
||||||
|
- bit: Registriert Input als bool() am angegebenen Bit im Byte
|
||||||
|
- byteorder: Byteorder fuer den Input, Standardwert=little
|
||||||
|
- defaultvalue: Standardwert fuer Input, Standard ist 0
|
||||||
|
- event: Funktion fuer Eventhandling registrieren
|
||||||
|
- as_thread: Fuehrt die event-Funktion als RevPiCallback-Thread aus
|
||||||
|
- edge: event-Ausfuehren bei RISING, FALLING or BOTH Wertaenderung
|
||||||
|
@see <a target="_blank"
|
||||||
|
href="https://docs.python.org/3/library/struct.html#format-characters"
|
||||||
|
>Python3 struct()</a>
|
||||||
|
|
||||||
|
"""
|
||||||
|
if not issubclass(self._parentdevice, devicemodule.Gateway):
|
||||||
|
raise RuntimeError(
|
||||||
|
"this function can be used for ios on gatway or virtual "
|
||||||
|
"devices only"
|
||||||
|
)
|
||||||
|
|
||||||
|
# StructIO erzeugen und in IO-Liste einfügen
|
||||||
|
io_new = StructIO(
|
||||||
|
self._parentdevice,
|
||||||
|
name,
|
||||||
|
IOType.INP,
|
||||||
|
kwargs.get("byteorder", "little"),
|
||||||
|
frm,
|
||||||
|
**kwargs
|
||||||
|
)
|
||||||
|
setattr(self._parentdevice._modio.io, name, io_new)
|
||||||
|
|
||||||
|
# Optional Event eintragen
|
||||||
|
reg_event = kwargs.get("event", None)
|
||||||
|
if reg_event is not None:
|
||||||
|
as_thread = kwargs.get("as_thread", False)
|
||||||
|
edge = kwargs.get("edge", None)
|
||||||
|
io_new.reg_event(reg_event, as_thread=as_thread, edge=edge)
|
||||||
|
|
||||||
|
def reg_out(self, name, frm, **kwargs):
|
||||||
|
"""Registriert einen neuen Output.
|
||||||
|
|
||||||
|
@param name Name des neuen Outputs
|
||||||
|
@param startout Outputname ab dem eingefuegt wird
|
||||||
|
@param frm struct() formatierung (1 Zeichen)
|
||||||
|
@param kwargs Weitere Parameter:
|
||||||
|
- bmk: Bezeichnung fuer Output
|
||||||
|
- bit: Registriert Outputs als bool() am angegebenen Bit im Byte
|
||||||
|
- byteorder: Byteorder fuer den Output, Standardwert=little
|
||||||
|
- defaultvalue: Standardwert fuer Output, Standard ist 0
|
||||||
|
- event: Funktion fuer Eventhandling registrieren
|
||||||
|
- as_thread: Fuehrt die event-Funktion als RevPiCallback-Thread aus
|
||||||
|
- edge: event-Ausfuehren bei RISING, FALLING or BOTH Wertaenderung
|
||||||
|
@see <a target="_blank"
|
||||||
|
href="https://docs.python.org/3/library/struct.html#format-characters"
|
||||||
|
>Python3 struct()</a>
|
||||||
|
|
||||||
|
"""
|
||||||
|
if not issubclass(self._parentdevice, devicemodule.Gateway):
|
||||||
|
raise RuntimeError(
|
||||||
|
"this function can be used on gatway or virtual devices only"
|
||||||
|
)
|
||||||
|
|
||||||
|
# StructIO erzeugen und in IO-Liste einfügen
|
||||||
|
io_new = StructIO(
|
||||||
|
self._parentdevice,
|
||||||
|
name,
|
||||||
|
IOType.OUT,
|
||||||
|
kwargs.get("byteorder", "little"),
|
||||||
|
frm,
|
||||||
|
**kwargs
|
||||||
|
)
|
||||||
|
setattr(self._parentdevice._modio.io, name, io_new)
|
||||||
|
|
||||||
|
# Optional Event eintragen
|
||||||
|
reg_event = kwargs.get("event", None)
|
||||||
|
if reg_event is not None:
|
||||||
|
as_thread = kwargs.get("as_thread", False)
|
||||||
|
edge = kwargs.get("edge", None)
|
||||||
|
io_new.reg_event(name, reg_event, as_thread=as_thread, edge=edge)
|
||||||
|
|
||||||
def set_value(self, value):
|
def set_value(self, value):
|
||||||
"""Setzt den Wert des IOs mit bytes() oder bool().
|
"""Setzt den Wert des IOs mit bytes() oder bool().
|
||||||
@param value IO-Wert als bytes() oder bool()"""
|
@param value IO-Wert als bytes() oder bool()"""
|
||||||
@@ -605,12 +683,66 @@ class StructIO(IOBase):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, parentdevice, valuelist, iotype, byteorder, frm):
|
def __init__(self, parentio, name, iotype, byteorder, frm, **kwargs):
|
||||||
"""Erweitert IOBase um struct-Formatierung.
|
"""Erstellt einen IO mit struct-Formatierung.
|
||||||
@see #IOBase.__init__ IOBase.__init__(...)"""
|
|
||||||
super().__init__(parentdevice, valuelist, iotype, byteorder)
|
@param parentio ParentIO Objekt, welches ersetzt wird
|
||||||
|
@param name Name des neuen IO
|
||||||
|
@param iotype IOType() Wert
|
||||||
|
@param byteorder Byteorder 'little' / 'big' fuer int() Berechnung
|
||||||
|
@param frm struct() formatierung (1 Zeichen)
|
||||||
|
@param kwargs Weitere Parameter:
|
||||||
|
- bmk: Bezeichnung fuer Output
|
||||||
|
- bit: Registriert Outputs als bool() am angegebenen Bit im Byte
|
||||||
|
- defaultvalue: Standardwert fuer Output, Standard ist 0
|
||||||
|
|
||||||
|
"""
|
||||||
|
if len(frm) == 1:
|
||||||
|
# Byteorder prüfen und übernehmen
|
||||||
|
if not (byteorder == "little" or byteorder == "big"):
|
||||||
|
raise ValueError("byteorder must be 'little' or 'big'")
|
||||||
|
bofrm = "<" if byteorder == "little" else ">"
|
||||||
|
|
||||||
|
bitaddress = "" if frm != "?" else str(kwargs.get("bit", 0))
|
||||||
|
if bitaddress == "" or \
|
||||||
|
(int(bitaddress) >= 0 and int(bitaddress) < 8):
|
||||||
|
|
||||||
|
bitlength = "1" if bitaddress.isnumeric() else \
|
||||||
|
struct.calcsize(bofrm + frm) * 8
|
||||||
|
|
||||||
|
# [name,default,anzbits,adressbyte,export,adressid,bmk,bitaddress]
|
||||||
|
valuelist = [
|
||||||
|
name,
|
||||||
|
kwargs.get("defaultvalue", 0),
|
||||||
|
bitlength,
|
||||||
|
parentio.address,
|
||||||
|
False,
|
||||||
|
str(parentio.address).rjust(4, "0"),
|
||||||
|
kwargs.get("bmk", ""),
|
||||||
|
bitaddress
|
||||||
|
]
|
||||||
|
|
||||||
|
else:
|
||||||
|
raise AttributeError(
|
||||||
|
"bitaddress must be a value between 0 and 7"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
raise AttributeError("parameter frm has to be a single sign")
|
||||||
|
|
||||||
|
# Basisklasse instantiieren
|
||||||
|
super().__init__(parentio._parentdevice, valuelist, iotype, byteorder)
|
||||||
self.frm = frm
|
self.frm = frm
|
||||||
|
|
||||||
|
# Platz für neuen IO prüfen
|
||||||
|
if not (self.slc_address.start >=
|
||||||
|
parentio._parentdevice._dict_slc[iotype].start and
|
||||||
|
self.slc_address.stop <=
|
||||||
|
parentio._parentdevice._dict_slc[iotype].stop):
|
||||||
|
|
||||||
|
raise BufferError(
|
||||||
|
"registered value does not fit process image scope"
|
||||||
|
)
|
||||||
|
|
||||||
def get_structvalue(self):
|
def get_structvalue(self):
|
||||||
"""Gibt den Wert mit struct Formatierung zurueck.
|
"""Gibt den Wert mit struct Formatierung zurueck.
|
||||||
@return Wert vom Typ der struct-Formatierung"""
|
@return Wert vom Typ der struct-Formatierung"""
|
||||||
|
|||||||
@@ -6,20 +6,18 @@
|
|||||||
#
|
#
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
from . import app as appmodule
|
|
||||||
from . import device as devicemodule
|
|
||||||
from . import helper as helpermodule
|
|
||||||
from . import io as iomodule
|
|
||||||
from . import summary as summarymodule
|
|
||||||
|
|
||||||
from .__init__ import RISING, FALLING, BOTH
|
|
||||||
|
|
||||||
from json import load as jload
|
from json import load as jload
|
||||||
from os import access, F_OK, R_OK
|
from os import access, F_OK, R_OK
|
||||||
from signal import signal, SIG_DFL, SIGINT, SIGTERM
|
from signal import signal, SIG_DFL, SIGINT, SIGTERM
|
||||||
from threading import Thread, Event
|
from threading import Thread, Event
|
||||||
|
|
||||||
|
from . import app as appmodule
|
||||||
|
from . import device as devicemodule
|
||||||
|
from . import helper as helpermodule
|
||||||
|
from . import summary as summarymodule
|
||||||
|
from .io import IOList
|
||||||
|
from .__init__ import RISING, FALLING, BOTH
|
||||||
|
|
||||||
|
|
||||||
class RevPiModIO(object):
|
class RevPiModIO(object):
|
||||||
|
|
||||||
@@ -131,7 +129,8 @@ class RevPiModIO(object):
|
|||||||
|
|
||||||
# Device und IO Klassen anlegen
|
# Device und IO Klassen anlegen
|
||||||
self.device = devicemodule.DeviceList()
|
self.device = devicemodule.DeviceList()
|
||||||
self.io = iomodule.IOList()
|
#self.io = iomodule.IOList()
|
||||||
|
self.io = IOList()
|
||||||
|
|
||||||
# Devices initialisieren
|
# Devices initialisieren
|
||||||
err_names = []
|
err_names = []
|
||||||
@@ -214,10 +213,6 @@ class RevPiModIO(object):
|
|||||||
if self._syncoutputs:
|
if self._syncoutputs:
|
||||||
self.syncoutputs(force=True)
|
self.syncoutputs(force=True)
|
||||||
|
|
||||||
# NOTE: Nur noch bis Final für kompatibilität
|
|
||||||
# Devices Klasse instantiieren
|
|
||||||
self.devices = devicemodule.Devicelist(self)
|
|
||||||
|
|
||||||
# Optional ins auto_refresh aufnehmen
|
# Optional ins auto_refresh aufnehmen
|
||||||
if self._auto_refresh:
|
if self._auto_refresh:
|
||||||
for dev in self._device:
|
for dev in self._device:
|
||||||
|
|||||||
Reference in New Issue
Block a user