From d6dd63a53f484ec37b71d2e99546f7e1e44b37c5 Mon Sep 17 00:00:00 2001 From: NaruX Date: Mon, 21 Aug 2017 12:17:49 +0200 Subject: [PATCH] =?UTF-8?q?Fehlerabfang=20bei=20procimg=20verbessert=20Dev?= =?UTF-8?q?ice.autoupdate=20entfernt=20(nie=20verwendet)=20RevPiModIO.ioer?= =?UTF-8?q?rors=20liefert=20Anzahl=20von=20=5Fimgwriter,=20wenn=20Loop=20a?= =?UTF-8?q?ktiv=20ist=20RevPiModIO.*procimg=20force=20Parameter=20entfernt?= =?UTF-8?q?,=20da=20autoupdate=20weg=20ist=20RevPiModIO.writeinputdefaults?= =?UTF-8?q?=20auf=20device.Virtual=20verschoben=20Docstrings=20angepasst?= =?UTF-8?q?=20alle=20Slices=20von=20Device=20und=20IOBase=20privatisiert?= =?UTF-8?q?=20=5F=20DeviceList.=5F=5Fdelattr=5F=5F=20eingef=C3=BCgt=20Bugf?= =?UTF-8?q?ix:=20Byteorder=20wurde=20bei=20StructIO=20nicht=20=C3=BCbernom?= =?UTF-8?q?men=20Diverse=20Verbesserungen=20an=20DeviceList=20und=20IOList?= =?UTF-8?q?=20class=20DeadIO=20eingef=C3=BCgt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/index-revpimodio2.html | 3 - doc/revpimodio2.device.html | 311 ++++++++++++++++++++++++------------ doc/revpimodio2.io.html | 104 +++++++++++- doc/revpimodio2.modio.html | 59 ++----- eric-revpimodio.api | 35 ++-- revpimodio2/device.py | 283 ++++++++++++++++++++------------ revpimodio2/helper.py | 8 +- revpimodio2/io.py | 180 +++++++++++++-------- revpimodio2/modio.py | 120 +++++--------- 9 files changed, 681 insertions(+), 422 deletions(-) diff --git a/doc/index-revpimodio2.html b/doc/index-revpimodio2.html index c4ef004..d5e3960 100644 --- a/doc/index-revpimodio2.html +++ b/doc/index-revpimodio2.html @@ -38,9 +38,6 @@ Modules modio RevPiModIO Hauptklasse. -netio - - summary Bildet die Summary-Sektion von piCtory ab. diff --git a/doc/revpimodio2.device.html b/doc/revpimodio2.device.html index 9727af0..2b7ada8 100644 --- a/doc/revpimodio2.device.html +++ b/doc/revpimodio2.device.html @@ -66,11 +66,26 @@ Class Methods Methods + + + - - + + + + + + + + + + + + + + @@ -81,15 +96,6 @@ Methods - - - - - - - - - @@ -111,12 +117,6 @@ Methods - - - - - - @@ -129,16 +129,10 @@ Static Methods
__errorlimitVerwaltet das Lesen und Schreiben der ErrorLimits.
_devconfigure Core-Klasse vorbereiten.
_errorlimitVerwaltet das Lesen und Schreiben der ErrorLimits._get_leda1Gibt den Zustand der LED A1 vom core zurueck.
_get_leda2Gibt den Zustand der LED A2 vom core zurueck.
_get_statusGibt den RevPi Core Status zurueck.
_set_leda1Setzt den Zustand der LED A1 vom core.
_set_leda2Setzt den Zustand der LED A2 vom core.
errorlimit1 Setzt RS485 ErrorLimit1 auf neuen Wert. frequency Gibt CPU Taktfrequenz zurueck.
get_leda1Gibt den Zustand der LED A1 vom core zurueck.
get_leda2Gibt den Zustand der LED A2 vom core zurueck.
get_statusGibt den RevPi Core Status zurueck.
iocycle Gibt Zykluszeit der Prozessabbildsynchronisierung zurueck.
rightgate Statusbit rechts vom RevPi ist ein piGate Modul angeschlossen.
set_leda1Setzt den Zustand der LED A1 vom core.
set_leda2Setzt den Zustand der LED A2 vom core.
temperatur Gibt CPU-Temperatur zurueck.
None
- +

-Core._devconfigure

-_devconfigure() -

-Core-Klasse vorbereiten. -

-

-Core._errorlimit

-_errorlimit(io_id, errorlimit) +Core.__errorlimit +__errorlimit(io_id, errorlimit)

Verwaltet das Lesen und Schreiben der ErrorLimits.

@@ -151,6 +145,67 @@ Index des IOs fuer ErrorLimit
Aktuellen ErrorLimit oder None wenn nicht verfuegbar
+
+

+Core._devconfigure

+_devconfigure() +

+Core-Klasse vorbereiten. +

+

+Core._get_leda1

+_get_leda1() +

+Gibt den Zustand der LED A1 vom core zurueck. +

+
Returns:
+
+0=aus, 1=gruen, 2=rot +
+
+

+Core._get_leda2

+_get_leda2() +

+Gibt den Zustand der LED A2 vom core zurueck. +

+
Returns:
+
+0=aus, 1=gruen, 2=rot +
+
+

+Core._get_status

+_get_status() +

+Gibt den RevPi Core Status zurueck. +

+
Returns:
+
+Status als int() +
+
+

+Core._set_leda1

+_set_leda1(value) +

+Setzt den Zustand der LED A1 vom core. +

+
value
+
+0=aus, 1=gruen, 2=rot +
+
+

+Core._set_leda2

+_set_leda2(value) +

+Setzt den Zustand der LED A2 vom core. +

+
value
+
+0=aus, 1=gruen, 2=rot +

Core.errorlimit1

@@ -184,39 +239,6 @@ Gibt CPU Taktfrequenz zurueck.
CPU Taktfrequenz in MHz
- -

-Core.get_leda1

-get_leda1() -

-Gibt den Zustand der LED A1 vom core zurueck. -

-
Returns:
-
-0=aus, 1=gruen, 2=rot -
-
-

-Core.get_leda2

-get_leda2() -

-Gibt den Zustand der LED A2 vom core zurueck. -

-
Returns:
-
-0=aus, 1=gruen, 2=rot -
-
-

-Core.get_status

-get_status() -

-Gibt den RevPi Core Status zurueck. -

-
Returns:
-
-Status als int() -

Core.iocycle

@@ -294,28 +316,6 @@ Statusbit rechts vom RevPi ist ein piGate Modul angeschlossen.
True, wenn piGate rechts existiert
- -

-Core.set_leda1

-set_leda1(value) -

-Setzt den Zustand der LED A1 vom core. -

-
value
-
-0=aus, 1=gruen, 2=rot -
-
-

-Core.set_leda2

-set_leda2(value) -

-Setzt den Zustand der LED A2 vom core. -

-
value
-
-0=aus, 1=gruen, 2=rot -

Core.temperatur

@@ -410,6 +410,18 @@ Methods get_outputs Gibt eine Liste aller Outputs zurueck. + +readprocimg +Alle Inputs fuer dieses Device vom Prozessabbild einlesen. + +setdefaultvalues +Alle Outputbuffer fuer dieses Device auf default Werte setzen. + +syncoutputs +Lesen aller Outputs im Prozessabbild fuer dieses Device. + +writeprocimg +Schreiben aller Outputs dieses Devices ins Prozessabbild.

@@ -420,7 +432,7 @@ Static Methods

Device (Constructor)

-Device(parentmodio, dict_device, **kwargs) +Device(parentmodio, dict_device, simulator=False)

Instantiierung der Device()-Klasse.

@@ -430,12 +442,9 @@ RevpiModIO parent object
dict_device
dict() fuer dieses Device aus piCotry Konfiguration -
kwargs
+
simulator:
-Weitere Parameter: - - autoupdate: Wenn True fuehrt dieses Device Arbeiten am - Prozessabbild bei Aufruf der read- writeprocimg Funktionen aus - - simulator: Laed das Modul als Simulator und vertauscht IOs +Laed das Modul als Simulator und vertauscht IOs

@@ -536,13 +545,13 @@ Funktion zum ueberschreiben von abgeleiteten Klassen.

Device.autorefresh

-autorefresh(remove=False) +autorefresh(activate=True)

Registriert dieses Device fuer die automatische Synchronisierung.

-
remove
+
activate
-bool() True entfernt Device aus Synchronisierung +Default True fuegt Device zur Synchronisierung hinzu

@@ -588,6 +597,50 @@ Gibt eine Liste aller Outputs zurueck.
list() Outputs
+ +

+Device.readprocimg

+readprocimg() +

+Alle Inputs fuer dieses Device vom Prozessabbild einlesen. +

+
See Also:
+
+RevPiModIO.readprocimg() +
+
+

+Device.setdefaultvalues

+setdefaultvalues() +

+Alle Outputbuffer fuer dieses Device auf default Werte setzen. +

+
See Also:
+
+RevPiModIO.setdefaultvalues() +
+
+

+Device.syncoutputs

+syncoutputs() +

+Lesen aller Outputs im Prozessabbild fuer dieses Device. +

+
See Also:
+
+RevPiModIO.syncoutputs() +
+
+

+Device.writeprocimg

+writeprocimg() +

+Schreiben aller Outputs dieses Devices ins Prozessabbild. +

+
See Also:
+
+RevPiModIO.writeprocimg() +
Up


@@ -619,6 +672,12 @@ Methods __contains__ Prueft ob Device existiert. +__delattr__ +Entfernt angegebenes Device. + +__delitem__ +Entfernt Device an angegebener Position. + __getitem__ Gibt angegebenes Device zurueck. @@ -659,6 +718,28 @@ DeviceName str() / Positionsnummer int()
True, wenn Device vorhanden
+ +

+DeviceList.__delattr__

+__delattr__(key) +

+Entfernt angegebenes Device. +

+
key
+
+Device zum entfernen +
+
+

+DeviceList.__delitem__

+__delitem__(key) +

+Entfernt Device an angegebener Position. +

+
key
+
+Deviceposition zum entfernen +

DeviceList.__getitem__

@@ -716,12 +797,16 @@ Attributobjekt Klasse fuer die RevPi Gateway-Devices.

Stellt neben den Funktionen von RevPiDevice weitere Funktionen fuer die - Gateways bereit. Es koennen ueber die reg_*-Funktionen eigene IOs definiert - werden, die ein RevPiStructIO-Objekt abbilden. + Gateways bereit. IOs auf diesem Device stellen die replace_io Funktion + zur verfuegung, ueber die eigene IOs definiert werden, die ein + RevPiStructIO-Objekt abbilden. Dieser IO-Typ kann Werte ueber mehrere Bytes verarbeiten und zurueckgeben. -

- -

+

+
See Also:
+
+replace_io(name, frm, **kwargs) +
+

Derived from

Device @@ -740,7 +825,7 @@ Methods - + @@ -754,13 +839,13 @@ Static Methods

Gateway (Constructor)

-Gateway(parent, dict_device, **kwargs) +Gateway(parent, dict_device, simulator=False)

-Erweitert RevPiDevice um reg_*-Funktionen. +Erweitert Device-Klasse um get_rawbytes-Funktionen.

See Also:
-RevPiDevice.__init__(...) +Device.__init__(...)

@@ -781,14 +866,14 @@ bytes() des Devices

Klasse fuer die RevPi Virtual-Devices.

- Stellt die selben Funktionen wie RevPiGateway zur Verfuegung. Es koennen + Stellt die selben Funktionen wie Gateway zur Verfuegung. Es koennen ueber die reg_*-Funktionen eigene IOs definiert werden, die ein RevPiStructIO-Objekt abbilden. Dieser IO-Typ kann Werte ueber mehrere Bytes verarbeiten und zurueckgeben.

See Also:
-RevPiGateway +Gateway

@@ -807,14 +892,34 @@ Class Methods

Methods

GatewayErweitert RevPiDevice um reg_*-Funktionen.Erweitert Device-Klasse um get_rawbytes-Funktionen.
get_rawbytes Gibt die Bytes aus, die dieses Device verwendet.
- + + + +
None
writeinputdefaultsSchreibt fuer ein virtuelles Device piCtory Defaultinputwerte.

Static Methods

None
- + +

+Virtual.writeinputdefaults

+writeinputdefaults() +

+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! +

+
Returns:
+
+True, wenn Arbeiten am virtuellen Device erfolgreich waren +
+
Up

\ No newline at end of file diff --git a/doc/revpimodio2.io.html b/doc/revpimodio2.io.html index 4e51ee5..d5d5fd4 100644 --- a/doc/revpimodio2.io.html +++ b/doc/revpimodio2.io.html @@ -18,6 +18,9 @@ Global Attributes Classes + + + @@ -40,6 +43,65 @@ Functions
DeadIOKlasse, mit der ersetzte IOs verwaltet werden.
IOBase Basisklasse fuer alle IO-Objekte.
None


+ +

DeadIO

+

+Klasse, mit der ersetzte IOs verwaltet werden. +

+

+Derived from

+object +

+Class Attributes

+ + +
None
+

+Class Methods

+ + +
None
+

+Methods

+ + + + + + + + +
DeadIOInstantiierung der DeadIO()-Klasse.
replace_ioStellt Funktion fuer weiter Bit-Ersetzungen bereit.
+

+Static Methods

+ + +
None
+ +

+DeadIO (Constructor)

+DeadIO(deadio) +

+Instantiierung der DeadIO()-Klasse. +

+
deadio
+
+IO, der ersetzt wurde +
+
+

+DeadIO.replace_io

+replace_io(name, frm, **kwargs) +

+Stellt Funktion fuer weiter Bit-Ersetzungen bereit. +

+
See Also:
+
+replace_io(...) +
+
+
Up
+

IOBase

@@ -415,6 +477,9 @@ Methods __iter__ Gibt Iterator aller IOs zurueck. +__len__ +Gibt die Anzahl aller IOs zurueck. + __private_replace_oldio_with_newio Ersetzt bestehende IOs durch den neu Registrierten. @@ -481,7 +546,7 @@ Verwaltet geloeschte IOs (Attribute, die nicht existieren).

key
-Wert eines alten IOs +Name oder Byte eines alten IOs
Returns:
@@ -494,15 +559,21 @@ IOList.__getitem__ __getitem__(key)

Ruft angegebenen IO ab. +

+ Wenn der Key ist, wird ein einzelner IO geliefert. Wird + der Key als uebergeben, wird eine + geliefert mit 0, 1 oder 8 Eintraegen. + Wird als Key gegeben, werden die Listen in einer Liste + zurueckgegeben.

key
-IO Name oder Byte +IO Name als oder Byte als .
Returns:
-IO Object +IO Objekt oder Liste der IOs

@@ -515,6 +586,17 @@ Gibt Iterator aller IOs zurueck.
Iterator aller IOs
+

+

+IOList.__len__

+__len__() +

+Gibt die Anzahl aller IOs zurueck. +

+
Returns:
+
+Anzahl aller IOs +

IOList.__private_replace_oldio_with_newio

@@ -721,7 +803,7 @@ IOBase

Class Attributes

- +
signed
value
frm
signed
value

Class Methods

@@ -735,6 +817,9 @@ Methods StructIO Erstellt einen IO mit struct-Formatierung. +_get_frm +Ruft die struct() Formatierung ab. + _get_signed Ruft ab, ob der Wert Vorzeichenbehaftet behandelt werden soll. @@ -774,6 +859,17 @@ Weitere Parameter: - byteorder: Byteorder fuer den Input, Standardwert=little - defaultvalue: Standardwert fuer Output, Standard ist 0 + +

+StructIO._get_frm

+_get_frm() +

+Ruft die struct() Formatierung ab. +

+
Returns:
+
+struct() Formatierung +

StructIO._get_signed

diff --git a/doc/revpimodio2.modio.html b/doc/revpimodio2.modio.html index 865b710..ed1ef4d 100644 --- a/doc/revpimodio2.modio.html +++ b/doc/revpimodio2.modio.html @@ -146,9 +146,6 @@ Methods syncoutputs Lesen aller aktuell gesetzten Outputs im Prozessabbild. -writedefaultinputs -Schreibt fuer ein virtuelles Device piCtory Defaultinputwerte. - writeprocimg Schreiben aller Outputs aller Devices ins Prozessabbild. @@ -470,14 +467,13 @@ None

RevPiModIO.readprocimg

-readprocimg(force=False, device=None) +readprocimg(device=None)

Einlesen aller Inputs aller/eines Devices vom Prozessabbild. +

+ Devices mit aktiverem autorefresh werden ausgenommen!

-
force
-
-auch Devices mit autoupdate=False -
device
+
device
nur auf einzelnes Device anwenden
@@ -495,28 +491,24 @@ Setzt aktuellen IOError-Zaehler auf 0 zurueck.

RevPiModIO.setdefaultvalues

-setdefaultvalues(force=False, device=None) +setdefaultvalues(device=None)

Alle Outputbuffer werden auf die piCtory default Werte gesetzt.

-
force
-
-auch Devices mit autoupdate=False -
device
+
device
nur auf einzelnes Device anwenden

RevPiModIO.syncoutputs

-syncoutputs(force=False, device=None) +syncoutputs(device=None)

Lesen aller aktuell gesetzten Outputs im Prozessabbild. +

+ Devices mit aktiverem autorefresh werden ausgenommen!

-
force
-
-auch Devices mit autoupdate=False -
device
+
device
nur auf einzelnes Device anwenden
@@ -525,39 +517,16 @@ nur auf einzelnes Device anwenden
True, wenn Arbeiten an allen Devices erfolgreich waren
-
-

-RevPiModIO.writedefaultinputs

-writedefaultinputs(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! -

-
virtual_device
-
-Virtuelles Device fuer Wiederherstellung -
-
-
Returns:
-
-True, wenn Arbeiten am virtuellen Device erfolgreich waren -

RevPiModIO.writeprocimg

-writeprocimg(force=False, device=None) +writeprocimg(device=None)

Schreiben aller Outputs aller Devices ins Prozessabbild. +

+ Devices mit aktiverem autorefresh werden ausgenommen!

-
force
-
-auch Devices mit autoupdate=False -
device
+
device
nur auf einzelnes Device anwenden
diff --git a/eric-revpimodio.api b/eric-revpimodio.api index cc557b1..561d775 100644 --- a/eric-revpimodio.api +++ b/eric-revpimodio.api @@ -8,13 +8,14 @@ revpimodio2.app.App?1(app) revpimodio2.device.Core.A1?7 revpimodio2.device.Core.A2?7 revpimodio2.device.Core._devconfigure?5() -revpimodio2.device.Core._errorlimit?5(io_id, errorlimit) +revpimodio2.device.Core._get_leda1?5() +revpimodio2.device.Core._get_leda2?5() +revpimodio2.device.Core._get_status?5() +revpimodio2.device.Core._set_leda1?5(value) +revpimodio2.device.Core._set_leda2?5(value) revpimodio2.device.Core.errorlimit1?4(value) revpimodio2.device.Core.errorlimit2?4(value) revpimodio2.device.Core.frequency?4() -revpimodio2.device.Core.get_leda1?4() -revpimodio2.device.Core.get_leda2?4() -revpimodio2.device.Core.get_status?4() revpimodio2.device.Core.iocycle?4() revpimodio2.device.Core.ioerrorcount?4() revpimodio2.device.Core.leftgate?4() @@ -22,22 +23,25 @@ revpimodio2.device.Core.missingdeviceorgate?4() revpimodio2.device.Core.overunderflow?4() revpimodio2.device.Core.picontrolrunning?4() revpimodio2.device.Core.rightgate?4() -revpimodio2.device.Core.set_leda1?4(value) -revpimodio2.device.Core.set_leda2?4(value) revpimodio2.device.Core.status?7 revpimodio2.device.Core.temperatur?4() revpimodio2.device.Core.unconfdevice?4() revpimodio2.device.Device._buildio?5(dict_io, iotype) revpimodio2.device.Device._devconfigure?5() -revpimodio2.device.Device.autorefresh?4(remove=False) +revpimodio2.device.Device.autorefresh?4(activate=True) revpimodio2.device.Device.get_allios?4() revpimodio2.device.Device.get_inputs?4() revpimodio2.device.Device.get_memmories?4() revpimodio2.device.Device.get_outputs?4() -revpimodio2.device.Device?1(parentmodio, dict_device, **kwargs) +revpimodio2.device.Device.readprocimg?4() +revpimodio2.device.Device.setdefaultvalues?4() +revpimodio2.device.Device.syncoutputs?4() +revpimodio2.device.Device.writeprocimg?4() +revpimodio2.device.Device?1(parentmodio, dict_device, simulator=False) revpimodio2.device.DeviceList?1() revpimodio2.device.Gateway.get_rawbytes?4() -revpimodio2.device.Gateway?1(parent, dict_device, **kwargs) +revpimodio2.device.Gateway?1(parent, dict_device, simulator=False) +revpimodio2.device.Virtual.writeinputdefaults?4() revpimodio2.helper.Cycletools._docycle?5() revpimodio2.helper.Cycletools.get_tofc?4(name) revpimodio2.helper.Cycletools.get_tonc?4(name) @@ -61,6 +65,8 @@ revpimodio2.helper.ProcimgWriter.set_maxioerrors?4(value) revpimodio2.helper.ProcimgWriter.set_refresh?4(value) revpimodio2.helper.ProcimgWriter.stop?4() revpimodio2.helper.ProcimgWriter?1(parentmodio) +revpimodio2.io.DeadIO.replace_io?4(name, frm, **kwargs) +revpimodio2.io.DeadIO?1(deadio) revpimodio2.io.IOBase._get_address?5() revpimodio2.io.IOBase._get_byteorder?5() revpimodio2.io.IOBase._get_iotype?5() @@ -91,7 +97,9 @@ revpimodio2.io.IntIO.get_int?4() revpimodio2.io.IntIO.set_int?4(value) revpimodio2.io.IntIO.signed?7 revpimodio2.io.IntIO.value?7 +revpimodio2.io.StructIO._get_frm?5() revpimodio2.io.StructIO._get_signed?5() +revpimodio2.io.StructIO.frm?7 revpimodio2.io.StructIO.get_structvalue?4() revpimodio2.io.StructIO.set_structvalue?4(value) revpimodio2.io.StructIO.signed?7 @@ -127,13 +135,12 @@ revpimodio2.modio.RevPiModIO.mainloop?4(freeze=False, blocking=True) revpimodio2.modio.RevPiModIO.maxioerrors?7 revpimodio2.modio.RevPiModIO.monitoring?7 revpimodio2.modio.RevPiModIO.procimg?7 -revpimodio2.modio.RevPiModIO.readprocimg?4(force=False, device=None) +revpimodio2.modio.RevPiModIO.readprocimg?4(device=None) revpimodio2.modio.RevPiModIO.resetioerrors?4() -revpimodio2.modio.RevPiModIO.setdefaultvalues?4(force=False, device=None) +revpimodio2.modio.RevPiModIO.setdefaultvalues?4(device=None) revpimodio2.modio.RevPiModIO.simulator?7 -revpimodio2.modio.RevPiModIO.syncoutputs?4(force=False, device=None) -revpimodio2.modio.RevPiModIO.writedefaultinputs?4(virtual_device) -revpimodio2.modio.RevPiModIO.writeprocimg?4(force=False, device=None) +revpimodio2.modio.RevPiModIO.syncoutputs?4(device=None) +revpimodio2.modio.RevPiModIO.writeprocimg?4(device=None) revpimodio2.modio.RevPiModIO?1(**kwargs) revpimodio2.modio.RevPiModIODriver?1(vdev, **kwargs) revpimodio2.modio.RevPiModIOSelected?1(deviceselection, **kwargs) diff --git a/revpimodio2/device.py b/revpimodio2/device.py index 00c28a6..d83a75a 100644 --- a/revpimodio2/device.py +++ b/revpimodio2/device.py @@ -29,11 +29,31 @@ class DeviceList(object): else: return key in self.__dict_position.values() + def __delattr__(self, key): + """Entfernt angegebenes Device. + @param key Device zum entfernen""" + dev_del = getattr(self, key) + + # Reinigungsjobs + dev_del.autorefresh(False) + for io in dev_del: + delattr(dev_del._modio.io, io.name) + + del self.__dict_position[dev_del.position] + object.__delattr__(self, key) + + def __delitem__(self, key): + """Entfernt Device an angegebener Position. + @param key Deviceposition zum entfernen""" + self.__delattr__(self[key].name) + def __getitem__(self, key): """Gibt angegebenes Device zurueck. @param key DeviceName str() / Positionsnummer int() @return Gefundenes Device()-Objekt""" if type(key) == int: + if key not in self.__dict_position: + raise KeyError("no device on position {}".format(key)) return self.__dict_position[key] else: return getattr(self, key) @@ -70,15 +90,12 @@ class Device(object): """ - def __init__(self, parentmodio, dict_device, **kwargs): + def __init__(self, parentmodio, dict_device, simulator=False): """Instantiierung der Device()-Klasse. @param parent RevpiModIO parent object @param dict_device dict() fuer dieses Device aus piCotry Konfiguration - @param kwargs Weitere Parameter: - - autoupdate: Wenn True fuehrt dieses Device Arbeiten am - Prozessabbild bei Aufruf der read- writeprocimg Funktionen aus - - simulator: Laed das Modul als Simulator und vertauscht IOs + @param simulator: Laed das Modul als Simulator und vertauscht IOs """ self._modio = parentmodio @@ -88,8 +105,6 @@ class Device(object): self._length = 0 self._selfupdate = False - self.autoupdate = kwargs.get("autoupdate", True) - # Wertzuweisung aus dict_device self.name = dict_device.pop("name") self.offset = int(dict_device.pop("offset")) @@ -97,32 +112,33 @@ class Device(object): self.producttype = int(dict_device.pop("productType")) # IOM-Objekte erstellen und Adressen in SLCs speichern - if kwargs.get("simulator", False): - self.slc_inp = self._buildio( + if simulator: + self._slc_inp = self._buildio( dict_device.pop("out"), iomodule.Type.INP) - self.slc_out = self._buildio( + self._slc_out = self._buildio( dict_device.pop("inp"), iomodule.Type.OUT) else: - self.slc_inp = self._buildio( + self._slc_inp = self._buildio( dict_device.pop("inp"), iomodule.Type.INP) - self.slc_out = self._buildio( + self._slc_out = self._buildio( dict_device.pop("out"), iomodule.Type.OUT) - self.slc_mem = self._buildio(dict_device.pop("mem"), iomodule.Type.MEM) + self._slc_mem = self._buildio( + dict_device.pop("mem"), iomodule.Type.MEM + ) # SLCs mit offset berechnen - self.slc_devoff = slice(self.offset, self.offset + self._length) - self.slc_inpoff = slice( - self.slc_inp.start + self.offset, self.slc_inp.stop + self.offset + self._slc_devoff = slice(self.offset, self.offset + self._length) + self._slc_inpoff = slice( + self._slc_inp.start + self.offset, self._slc_inp.stop + self.offset ) - self.slc_outoff = slice( - self.slc_out.start + self.offset, self.slc_out.stop + self.offset + self._slc_outoff = slice( + self._slc_out.start + self.offset, self._slc_out.stop + self.offset ) - self.slc_memoff = slice( - self.slc_mem.start + self.offset, self.slc_mem.stop + self.offset + self._slc_memoff = slice( + self._slc_mem.start + self.offset, self._slc_mem.stop + self.offset ) # Neues bytearray und Kopie für mainloop anlegen - # NOTE: Testen self._ba_devdata = bytearray(self._length) self._ba_datacp = bytearray() @@ -142,12 +158,14 @@ class Device(object): @param key IO-Name str() / IO-Bytenummer int() @return True, wenn device vorhanden""" if type(key) == str: - return hasattr(self._modio.io, key) \ + return key in self._modio.io \ and getattr(self._modio.io, key)._parentdevice == self elif type(key) == int: - return key in self._modio.io \ - and len(self._modio.io[key]) > 0 \ - and self._modio.io[key][0]._parentdevice == self + if key in self._modio.io: + for io in self._modio.io[key]: + if io is not None and io._parentdevice == self: + return True + return False else: return key._parentdevice == self @@ -159,7 +177,7 @@ class Device(object): def __iter__(self): """Gibt Iterator aller IOs zurueck. @return iter() aller IOs""" - for lst_io in self._modio.io[self.slc_devoff]: + for lst_io in self._modio.io[self._slc_devoff]: for io in lst_io: yield io @@ -207,10 +225,10 @@ class Device(object): self._length += io_new._length # Kleinste und größte Speicheradresse ermitteln - if io_new.slc_address.start < int_min: - int_min = io_new.slc_address.start - if io_new.slc_address.stop > int_max: - int_max = io_new.slc_address.stop + if io_new._slc_address.start < int_min: + int_min = io_new._slc_address.start + if io_new._slc_address.stop > int_max: + int_max = io_new._slc_address.stop return slice(int_min, int_max) @@ -218,13 +236,13 @@ class Device(object): """Funktion zum ueberschreiben von abgeleiteten Klassen.""" pass - def autorefresh(self, remove=False): + def autorefresh(self, activate=True): """Registriert dieses Device fuer die automatische Synchronisierung. - @param remove bool() True entfernt Device aus Synchronisierung""" - if not remove and self not in self._modio._lst_refresh: + @param activate Default True fuegt Device zur Synchronisierung hinzu""" + if activate and self not in self._modio._lst_refresh: # Daten bei Aufnahme direkt einlesen! - self._modio.readprocimg(True, self) + self._modio.readprocimg(self) # Datenkopie anlegen self._filelock.acquire() @@ -247,7 +265,7 @@ class Device(object): self._modio._imgwriter.refresh = imgrefresh self._modio._imgwriter.start() - elif remove and self in self._modio._lst_refresh: + elif not activate and self in self._modio._lst_refresh: # Sicher aus Liste entfernen with self._modio._imgwriter.lck_refresh: self._modio._lst_refresh.remove(self) @@ -259,14 +277,14 @@ class Device(object): # Daten beim Entfernen noch einmal schreiben if not self._modio._monitoring: - self._modio.writeprocimg(True, self) + self._modio.writeprocimg(self) def get_allios(self): """Gibt eine Liste aller Inputs und Outputs zurueck, keine MEMs. @return list() Input und Output, keine MEMs""" lst_return = [] for lst_io in self._modio.io[ - self.slc_inpoff.start:self.slc_outoff.stop]: + self._slc_inpoff.start:self._slc_outoff.stop]: lst_return += lst_io return lst_return @@ -274,7 +292,7 @@ class Device(object): """Gibt eine Liste aller Inputs zurueck. @return list() Inputs""" lst_return = [] - for lst_io in self._modio.io[self.slc_inpoff]: + for lst_io in self._modio.io[self._slc_inpoff]: lst_return += lst_io return lst_return @@ -282,7 +300,7 @@ class Device(object): """Gibt eine Liste aller Outputs zurueck. @return list() Outputs""" lst_return = [] - for lst_io in self._modio.io[self.slc_outoff]: + for lst_io in self._modio.io[self._slc_outoff]: lst_return += lst_io return lst_return @@ -290,10 +308,34 @@ class Device(object): """Gibt eine Liste aller mems zurueck. @return list() Mems""" lst_return = [] - for lst_io in self._modio.io[self.slc_memoff]: + for lst_io in self._modio.io[self._slc_memoff]: lst_return += lst_io return lst_return + def readprocimg(self): + """Alle Inputs fuer dieses Device vom Prozessabbild einlesen. + @see revpimodio2.modio#RevPiModIO.readprocimg + RevPiModIO.readprocimg()""" + self._modio.readprocimg(self) + + def setdefaultvalues(self): + """Alle Outputbuffer fuer dieses Device auf default Werte setzen. + @see revpimodio2.modio#RevPiModIO.setdefaultvalues + RevPiModIO.setdefaultvalues()""" + self._modio.setdefaultvalues(self) + + def syncoutputs(self): + """Lesen aller Outputs im Prozessabbild fuer dieses Device. + @see revpimodio2.modio#RevPiModIO.syncoutputs + RevPiModIO.syncoutputs()""" + self._modio.syncoutputs(self) + + def writeprocimg(self): + """Schreiben aller Outputs dieses Devices ins Prozessabbild. + @see revpimodio2.modio#RevPiModIO.writeprocimg + RevPiModIO.writeprocimg()""" + self._modio.writeprocimg(self) + class Core(Device): @@ -314,9 +356,9 @@ class Core(Device): self._ioerrorlimit2 = None # Eigene IO-Liste aufbauen - self._lst_io = [x for x in self.__iter__()] + self.__lst_io = [x for x in self.__iter__()] - int_lenio = len(self._lst_io) + int_lenio = len(self.__lst_io) if int_lenio == 6: # Core 1.1 self._iocycle = 1 @@ -334,87 +376,87 @@ class Core(Device): self._ioerrorlimit1 = 6 self._ioerrorlimit2 = 7 - def _errorlimit(self, io_id, errorlimit): + def __errorlimit(self, io_id, errorlimit): """Verwaltet das Lesen und Schreiben der ErrorLimits. @param io_id Index des IOs fuer ErrorLimit @return Aktuellen ErrorLimit oder None wenn nicht verfuegbar""" if errorlimit is None: return None if io_id is None else int.from_bytes( - self._lst_io[io_id].get_value(), - byteorder=self._lst_io[io_id]._byteorder + self.__lst_io[io_id].get_value(), + byteorder=self.__lst_io[io_id]._byteorder ) else: if 0 <= errorlimit <= 65535: - self._lst_io[io_id].set_value(errorlimit.to_bytes( - 2, byteorder=self._lst_io[io_id]._byteorder + self.__lst_io[io_id].set_value(errorlimit.to_bytes( + 2, byteorder=self.__lst_io[io_id]._byteorder )) else: raise ValueError( "errorlimit value int() must be between 0 and 65535" ) - def get_status(self): + def _get_status(self): """Gibt den RevPi Core Status zurueck. @return Status als int()""" return int.from_bytes( - self._lst_io[0].get_value(), byteorder=self._lst_io[0]._byteorder + self.__lst_io[0].get_value(), byteorder=self.__lst_io[0]._byteorder ) - def get_leda1(self): + def _get_leda1(self): """Gibt den Zustand der LED A1 vom core zurueck. @return 0=aus, 1=gruen, 2=rot""" int_led = int.from_bytes( - self._lst_io[self._ioled].get_value(), - byteorder=self._lst_io[self._ioled]._byteorder + self.__lst_io[self._ioled].get_value(), + byteorder=self.__lst_io[self._ioled]._byteorder ) led = int_led & 1 led += int_led & 2 return led - def get_leda2(self): + def _get_leda2(self): """Gibt den Zustand der LED A2 vom core zurueck. @return 0=aus, 1=gruen, 2=rot""" int_led = int.from_bytes( - self._lst_io[self._ioled].get_value(), - byteorder=self._lst_io[self._ioled]._byteorder + self.__lst_io[self._ioled].get_value(), + byteorder=self.__lst_io[self._ioled]._byteorder ) led = 1 if bool(int_led & 4) else 0 led = led + 2 if bool(int_led & 8) else led return led - def set_leda1(self, value): + def _set_leda1(self, value): """Setzt den Zustand der LED A1 vom core. @param value 0=aus, 1=gruen, 2=rot""" if 0 <= value <= 3: - int_led = (self.get_leda2() << 2) + value - self._lst_io[self._ioled].set_value(int_led.to_bytes( - length=1, byteorder=self._lst_io[self._ioled]._byteorder + int_led = (self._get_leda2() << 2) + value + self.__lst_io[self._ioled].set_value(int_led.to_bytes( + length=1, byteorder=self.__lst_io[self._ioled]._byteorder )) else: raise ValueError("led status int() must be between 0 and 3") - def set_leda2(self, value): + def _set_leda2(self, value): """Setzt den Zustand der LED A2 vom core. @param value 0=aus, 1=gruen, 2=rot""" if 0 <= value <= 3: - int_led = (value << 2) + self.get_leda1() - self._lst_io[self._ioled].set_value(int_led.to_bytes( - length=1, byteorder=self._lst_io[self._ioled]._byteorder + int_led = (value << 2) + self._get_leda1() + self.__lst_io[self._ioled].set_value(int_led.to_bytes( + length=1, byteorder=self.__lst_io[self._ioled]._byteorder )) else: raise ValueError("led status int() must be between 0 and 3") - A1 = property(get_leda1, set_leda1) - A2 = property(get_leda2, set_leda2) - status = property(get_status) + A1 = property(_get_leda1, _set_leda1) + A2 = property(_get_leda2, _set_leda2) + status = property(_get_status) @property def picontrolrunning(self): """Statusbit fuer piControl-Treiber laeuft. @return True, wenn Treiber laeuft""" return bool(int.from_bytes( - self._lst_io[0].get_value(), - byteorder=self._lst_io[0]._byteorder + self.__lst_io[0].get_value(), + byteorder=self.__lst_io[0]._byteorder ) & 1) @property @@ -422,8 +464,8 @@ class Core(Device): """Statusbit fuer ein IO-Modul nicht mit PiCtory konfiguriert. @return True, wenn IO Modul nicht konfiguriert""" return bool(int.from_bytes( - self._lst_io[0].get_value(), - byteorder=self._lst_io[0]._byteorder + self.__lst_io[0].get_value(), + byteorder=self.__lst_io[0]._byteorder ) & 2) @property @@ -431,8 +473,8 @@ class Core(Device): """Statusbit fuer ein IO-Modul fehlt oder piGate konfiguriert. @return True, wenn IO-Modul fehlt oder piGate konfiguriert""" return bool(int.from_bytes( - self._lst_io[0].get_value(), - byteorder=self._lst_io[0]._byteorder + self.__lst_io[0].get_value(), + byteorder=self.__lst_io[0]._byteorder ) & 4) @property @@ -440,8 +482,8 @@ class Core(Device): """Statusbit Modul belegt mehr oder weniger Speicher als konfiguriert. @return True, wenn falscher Speicher belegt ist""" return bool(int.from_bytes( - self._lst_io[0].get_value(), - byteorder=self._lst_io[0]._byteorder + self.__lst_io[0].get_value(), + byteorder=self.__lst_io[0]._byteorder ) & 8) @property @@ -449,8 +491,8 @@ class Core(Device): """Statusbit links vom RevPi ist ein piGate Modul angeschlossen. @return True, wenn piGate links existiert""" return bool(int.from_bytes( - self._lst_io[0].get_value(), - byteorder=self._lst_io[0]._byteorder + self.__lst_io[0].get_value(), + byteorder=self.__lst_io[0]._byteorder ) & 16) @property @@ -458,8 +500,8 @@ class Core(Device): """Statusbit rechts vom RevPi ist ein piGate Modul angeschlossen. @return True, wenn piGate rechts existiert""" return bool(int.from_bytes( - self._lst_io[0].get_value(), - byteorder=self._lst_io[0]._byteorder + self.__lst_io[0].get_value(), + byteorder=self.__lst_io[0]._byteorder ) & 32) @property @@ -467,8 +509,8 @@ class Core(Device): """Gibt Zykluszeit der Prozessabbildsynchronisierung zurueck. @return Zykluszeit in ms""" return None if self._iocycle is None else int.from_bytes( - self._lst_io[self._iocycle].get_value(), - byteorder=self._lst_io[self._iocycle]._byteorder + self.__lst_io[self._iocycle].get_value(), + byteorder=self.__lst_io[self._iocycle]._byteorder ) @property @@ -476,8 +518,8 @@ class Core(Device): """Gibt CPU-Temperatur zurueck. @return CPU-Temperatur in Celsius""" return None if self._iotemperatur is None else int.from_bytes( - self._lst_io[self._iotemperatur].get_value(), - byteorder=self._lst_io[self._iotemperatur]._byteorder + self.__lst_io[self._iotemperatur].get_value(), + byteorder=self.__lst_io[self._iotemperatur]._byteorder ) @property @@ -485,8 +527,8 @@ class Core(Device): """Gibt CPU Taktfrequenz zurueck. @return CPU Taktfrequenz in MHz""" return None if self._iofrequency is None else int.from_bytes( - self._lst_io[self._iofrequency].get_value(), - byteorder=self._lst_io[self._iofrequency]._byteorder + self.__lst_io[self._iofrequency].get_value(), + byteorder=self.__lst_io[self._iofrequency]._byteorder ) * 10 @property @@ -494,33 +536,33 @@ class Core(Device): """Gibt Fehleranzahl auf RS485 piBridge Bus zurueck. @return Fehleranzahl der piBridge""" return None if self._ioerrorcnt is None else int.from_bytes( - self._lst_io[self._ioerrorcnt].get_value(), - byteorder=self._lst_io[self._ioerrorcnt]._byteorder + self.__lst_io[self._ioerrorcnt].get_value(), + byteorder=self.__lst_io[self._ioerrorcnt]._byteorder ) @property def errorlimit1(self): """Gibt RS485 ErrorLimit1 Wert zurueck. @return Aktueller Wert fuer ErrorLimit1""" - return self._errorlimit(self._ioerrorlimit1, None) + return self.__errorlimit(self._ioerrorlimit1, None) @errorlimit1.setter def errorlimit1(self, value): """Setzt RS485 ErrorLimit1 auf neuen Wert. @param value Neuer ErrorLimit1 Wert""" - self._errorlimit(self._ioerrorlimit1, value) + self.__errorlimit(self._ioerrorlimit1, value) @property def errorlimit2(self): """Gibt RS485 ErrorLimit2 Wert zurueck. @return Aktueller Wert fuer ErrorLimit2""" - return self._errorlimit(self._ioerrorlimit2, None) + return self.__errorlimit(self._ioerrorlimit2, None) @errorlimit2.setter def errorlimit2(self, value): """Setzt RS485 ErrorLimit2 auf neuen Wert. @param value Neuer ErrorLimit2 Wert""" - self._errorlimit(self._ioerrorlimit2, value) + self.__errorlimit(self._ioerrorlimit2, value) class Gateway(Device): @@ -528,21 +570,23 @@ class Gateway(Device): """Klasse fuer die RevPi Gateway-Devices. Stellt neben den Funktionen von RevPiDevice weitere Funktionen fuer die - Gateways bereit. Es koennen ueber die reg_*-Funktionen eigene IOs definiert - werden, die ein RevPiStructIO-Objekt abbilden. + Gateways bereit. IOs auf diesem Device stellen die replace_io Funktion + zur verfuegung, ueber die eigene IOs definiert werden, die ein + RevPiStructIO-Objekt abbilden. Dieser IO-Typ kann Werte ueber mehrere Bytes verarbeiten und zurueckgeben. + @see revpimodio2.io#IOBase.replace_io replace_io(name, frm, **kwargs) """ - def __init__(self, parent, dict_device, **kwargs): - """Erweitert RevPiDevice um reg_*-Funktionen. - @see #RevPiDevice.__init__ RevPiDevice.__init__(...)""" - super().__init__(parent, dict_device, **kwargs) + def __init__(self, parent, dict_device, simulator=False): + """Erweitert Device-Klasse um get_rawbytes-Funktionen. + @see #Device.__init__ Device.__init__(...)""" + super().__init__(parent, dict_device, simulator) self._dict_slc = { - iomodule.Type.INP: self.slc_inp, - iomodule.Type.OUT: self.slc_out, - iomodule.Type.MEM: self.slc_mem + iomodule.Type.INP: self._slc_inp, + iomodule.Type.OUT: self._slc_out, + iomodule.Type.MEM: self._slc_mem } def get_rawbytes(self): @@ -555,15 +599,50 @@ class Virtual(Gateway): """Klasse fuer die RevPi Virtual-Devices. - Stellt die selben Funktionen wie RevPiGateway zur Verfuegung. Es koennen + Stellt die selben Funktionen wie Gateway zur Verfuegung. Es koennen ueber die reg_*-Funktionen eigene IOs definiert werden, die ein RevPiStructIO-Objekt abbilden. Dieser IO-Typ kann Werte ueber mehrere Bytes verarbeiten und zurueckgeben. - @see #RevPiGateway RevPiGateway + @see #Gateway Gateway """ - pass + def writeinputdefaults(self): + """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! + + @return True, wenn Arbeiten am virtuellen Device erfolgreich waren + + """ + if self._modio._monitoring: + raise RuntimeError( + "can not write process image, while system is in monitoring " + "mode" + ) + + workokay = True + self._filelock.acquire() + + for io in self.get_inputs(): + self._ba_devdata[io._slc_address] = io.defaultvalue + + # Outpus auf Bus schreiben + try: + self._modio._myfh.seek(self._slc_inpoff.start) + self._modio._myfh.write(self._ba_devdata[self._slc_inp]) + if self._modio._buffedwrite: + self._modio._myfh.flush() + except IOError: + self._modio._gotioerror("write") + workokay = False + + self._filelock.release() + return workokay # Nachträglicher Import diff --git a/revpimodio2/helper.py b/revpimodio2/helper.py index 1fe916e..4b196ee 100644 --- a/revpimodio2/helper.py +++ b/revpimodio2/helper.py @@ -296,17 +296,17 @@ class ProcimgWriter(Thread): # Inputs und Outputs in Puffer for dev in self._modio._lst_refresh: dev._filelock.acquire() - dev._ba_devdata[:] = bytesbuff[dev.slc_devoff] + dev._ba_devdata[:] = bytesbuff[dev._slc_devoff] dev._filelock.release() else: # Inputs in Puffer, Outputs in Prozessabbild ioerr = False for dev in self._modio._lst_refresh: dev._filelock.acquire() - dev._ba_devdata[dev.slc_inp] = bytesbuff[dev.slc_inpoff] + dev._ba_devdata[dev._slc_inp] = bytesbuff[dev._slc_inpoff] try: - fh.seek(dev.slc_outoff.start) - fh.write(dev._ba_devdata[dev.slc_out]) + fh.seek(dev._slc_outoff.start) + fh.write(dev._ba_devdata[dev._slc_out]) except IOError: ioerr = True finally: diff --git a/revpimodio2/io.py b/revpimodio2/io.py index 5aaaed9..e6af91e 100644 --- a/revpimodio2/io.py +++ b/revpimodio2/io.py @@ -27,7 +27,6 @@ class IOList(object): def __init__(self): """Init IOList class.""" self.__dict_iobyte = {k: [] for k in range(4096)} - self.__dict_iorefbyte = {} self.__dict_iorefname = {} def __contains__(self, key): @@ -38,42 +37,53 @@ class IOList(object): return key in self.__dict_iobyte \ and len(self.__dict_iobyte[key]) > 0 else: - return hasattr(self, key) + return hasattr(self, key) and type(getattr(self, key)) != DeadIO def __delattr__(self, key): """Entfernt angegebenen IO. @param key IO zum entfernen""" - # TODO: Prüfen ob auch Bit sein kann - - io_del = getattr(self, key) + io_del = object.__getattribute__(self, key) # Alte Events vom Device löschen io_del.unreg_event() # IO aus Byteliste und Attributen entfernen - self.__dict_iobyte[io_del.address].remove(io_del) + if io_del._bitaddress < 0: + self.__dict_iobyte[io_del.address].remove(io_del) + else: + self.__dict_iobyte[io_del.address][io_del._bitaddress] = None + if self.__dict_iobyte[io_del.address] == \ + [None, None, None, None, None, None, None, None]: + self.__dict_iobyte[io_del.address] = [] + object.__delattr__(self, key) def __getattr__(self, key): """Verwaltet geloeschte IOs (Attribute, die nicht existieren). - @param key Wert eines alten IOs + @param key Name oder Byte eines alten IOs @return Alten IO, wenn in Ref-Listen""" if key in self.__dict_iorefname: return self.__dict_iorefname[key] - elif key in self.__dict_iorefbyte: - return self.__dict_iorefbyte[key] else: raise AttributeError("can not find io '{}'".format(key)) def __getitem__(self, key): """Ruft angegebenen IO ab. - @param key IO Name oder Byte - @return IO Object""" + + Wenn der Key ist, wird ein einzelner IO geliefert. Wird + der Key als uebergeben, wird eine + geliefert mit 0, 1 oder 8 Eintraegen. + Wird als Key gegeben, werden die Listen in einer Liste + zurueckgegeben. + + @param key IO Name als oder Byte als . + @return IO Objekt oder Liste der IOs + + """ if type(key) == int: - if key in self.__dict_iobyte: - return self.__dict_iobyte[key] - else: + if key not in self.__dict_iobyte: raise KeyError("byte '{}' does not exist".format(key)) + return self.__dict_iobyte[key] elif type(key) == slice: return [ self.__dict_iobyte[int_io] @@ -87,25 +97,37 @@ class IOList(object): @return Iterator aller IOs""" for int_io in sorted(self.__dict_iobyte): for io in self.__dict_iobyte[int_io]: - yield io + if io is not None: + yield io + + def __len__(self): + """Gibt die Anzahl aller IOs zurueck. + @return Anzahl aller IOs""" + int_ios = 0 + for int_io in self.__dict_iobyte: + for io in self.__dict_iobyte[int_io]: + if io is not None: + int_ios += 1 + return int_ios def __setitem__(self, key, value): """Setzt IO Wert. @param key IO Name oder Byte @param value Wert, auf den der IO gesetzt wird""" if type(key) == int: - if key in self.__dict_iobyte: - if len(self.__dict_iobyte[key]) == 1: - self.__dict_iobyte[key][0].value = value - elif len(self.__dict_iobyte[key]) == 0: - raise KeyError("byte '{}' contains no input".format(key)) - else: - raise KeyError( - "byte '{}' contains more than one bit-input" - "".format(key) - ) + if key not in self.__dict_iobyte: + raise KeyError( + "byte '{}' does not contain io object".format(key) + ) + + if len(self.__dict_iobyte[key]) == 1: + self.__dict_iobyte[key][0].value = value + elif len(self.__dict_iobyte[key]) == 0: + raise KeyError("byte '{}' contains no input".format(key)) else: - raise KeyError("byte '{}' does not exist".format(key)) + raise KeyError( + "byte '{}' contains more than one bit-input".format(key) + ) else: getattr(self, key).value = value @@ -115,8 +137,7 @@ class IOList(object): @param value Wert, auf den der IO gesetzt wird""" if key in [ "_IOList__dict_iobyte", - "_IOList__dict_iorefname", - "_IOList__dict_iorefbyte" + "_IOList__dict_iorefname" ]: object.__setattr__(self, key, value) else: @@ -126,8 +147,9 @@ class IOList(object): def __private_replace_oldio_with_newio(self, io): """Ersetzt bestehende IOs durch den neu Registrierten. @param io Neuer IO der eingefuegt werden soll""" - for i in range(io.slc_address.start, io.slc_address.stop): - for oldio in self.__dict_iobyte[i + io._parentdevice.offset]: + int_length = 1 if io._length == 0 else io._length + for i in range(io.address, io.address + int_length): + for oldio in self.__dict_iobyte[i]: if type(oldio) == StructIO: # Hier gibt es schon einen neuen IO @@ -149,8 +171,7 @@ class IOList(object): # IOs im Speicherbereich des neuen IO merken if io._bitaddress >= 0: # ios für ref bei bitaddress speichern - self.__dict_iorefbyte[oldio.slc_address.start] = oldio - self.__dict_iorefname[oldio.name] = oldio + self.__dict_iorefname[oldio.name] = DeadIO(oldio) # ios aus listen entfernen delattr(self, oldio.name) @@ -171,7 +192,7 @@ class IOList(object): object.__setattr__(self, new_io.name, new_io) - # Bytedict erstellen für Adresszugriff + # Bytedict für Adresszugriff anpassen if new_io._bitaddress < 0: self.__dict_iobyte[new_io.address].append(new_io) else: @@ -182,7 +203,7 @@ class IOList(object): ] self.__dict_iobyte[new_io.address][new_io._bitaddress] = new_io else: - raise AttributeError("io must be IOBase or sub class") + raise AttributeError("io must be or sub class") def _testme(self): # NOTE: Nur Debugging @@ -190,13 +211,27 @@ class IOList(object): if len(self.__dict_iobyte[x]) > 0: print(x, self.__dict_iobyte[x]) print(self.__dict_iorefname) - print(self.__dict_iorefbyte) def _getdict(self): # NOTE: Nur Debugging return self.__dict_iobyte.copy() +class DeadIO(object): + + """Klasse, mit der ersetzte IOs verwaltet werden.""" + + def __init__(self, deadio): + """Instantiierung der DeadIO()-Klasse. + @param deadio IO, der ersetzt wurde""" + self.__deadio = deadio + + def replace_io(self, name, frm, **kwargs): + """Stellt Funktion fuer weiter Bit-Ersetzungen bereit. + @see #IOBase.replace_io replace_io(...)""" + self.__deadio.replace_io(name, frm, **kwargs) + + class IOBase(object): """Basisklasse fuer alle IO-Objekte. @@ -238,7 +273,7 @@ class IOBase(object): int_startaddress = int(valuelist[3]) if self._bitaddress == -1: - self.slc_address = slice( + self._slc_address = slice( int_startaddress, int_startaddress + self._length ) # Defaultvalue aus Zahl in Bytes umrechnen @@ -262,7 +297,7 @@ class IOBase(object): else: # Höhere Bits als 7 auf nächste Bytes umbrechen int_startaddress += int((int(valuelist[7]) % 16) / 8) - self.slc_address = slice( + self._slc_address = slice( int_startaddress, int_startaddress + 1 ) self.defaultvalue = bool(int(valuelist[1])) @@ -277,13 +312,13 @@ class IOBase(object): @return IO-Wert als bytes()""" if self._bitaddress >= 0: int_byte = int.from_bytes( - self._parentdevice._ba_devdata[self.slc_address], + self._parentdevice._ba_devdata[self._slc_address], byteorder=self._byteorder ) return b'\x01' if bool(int_byte & 1 << self._bitaddress) \ else b'\x00' else: - return bytes(self._parentdevice._ba_devdata[self.slc_address]) + return bytes(self._parentdevice._ba_devdata[self._slc_address]) def __str__(self): """str()-wert der Klasse. @@ -293,7 +328,7 @@ class IOBase(object): def _get_address(self): """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): """Gibt konfigurierte Byteorder zurueck. @@ -320,13 +355,13 @@ class IOBase(object): @return IO-Wert""" if self._bitaddress >= 0: int_byte = int.from_bytes( - self._parentdevice._ba_devdata[self.slc_address], + self._parentdevice._ba_devdata[self._slc_address], byteorder=self._byteorder ) return bool(int_byte & 1 << self._bitaddress) else: - return bytes(self._parentdevice._ba_devdata[self.slc_address]) + return bytes(self._parentdevice._ba_devdata[self._slc_address]) def reg_event(self, func, edge=BOTH, as_thread=False): """Registriert ein Event bei der Eventueberwachung. @@ -413,9 +448,11 @@ class IOBase(object): # 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", BOTH) - io_new.reg_event(reg_event, as_thread=as_thread, edge=edge) + io_new.reg_event( + reg_event, + as_thread=kwargs.get("as_thread", False), + edge=kwargs.get("edge", BOTH) + ) def set_value(self, value): """Setzt den Wert des IOs mit bytes() oder bool(). @@ -426,7 +463,7 @@ class IOBase(object): value = bool(value) # ganzes Byte laden - byte_buff = self._parentdevice._ba_devdata[self.slc_address] + byte_buff = self._parentdevice._ba_devdata[self._slc_address] # Bytes in integer umwandeln int_len = len(byte_buff) @@ -441,31 +478,37 @@ class IOBase(object): int_byte -= int_bit # Zurückschreiben wenn verändert - self._parentdevice._ba_devdata[self.slc_address] = \ + self._parentdevice._ba_devdata[self._slc_address] = \ int_byte.to_bytes(int_len, byteorder=self._byteorder) else: if type(value) == bytes: if self._length == len(value): - self._parentdevice._ba_devdata[self.slc_address] = \ + self._parentdevice._ba_devdata[self._slc_address] = \ value else: raise ValueError( - "'{}' requires a bytes() object of length {}, but " - "{} was given".format( + "'{}' requires a object of length " + "{}, but {} was given".format( self._name, self._length, len(value) ) ) else: raise ValueError( - "'{}' requires a bytes() object, not {}" + "'{}' requires a object, not {}" "".format(self._name, type(value)) ) elif self._iotype == Type.INP: - raise AttributeError( - "can not write to input '{}'".format(self._name) - ) + if self._parentdevice._modio._simulator: + raise AttributeError( + "can not write to output '{}' in simulator mode" + "".format(self._name) + ) + else: + raise AttributeError( + "can not write to input '{}'".format(self._name) + ) elif self._iotype == Type.MEM: raise AttributeError( "can not write to memory '{}'".format(self._name) @@ -582,8 +625,7 @@ class IOBase(object): flt_timecount += \ self._parentdevice._modio._imgwriter._refresh elif bool_timecount: - # TODO: Prüfen - flt_timecount += 1 + flt_timecount += 2.5 # Abbruchevent wurde gesetzt if exitevent.is_set(): @@ -637,14 +679,14 @@ class IntIO(IOBase): """Left fest, ob der Wert Vorzeichenbehaftet behandelt werden soll. @param value True, wenn mit Vorzeichen behandel""" if type(value) != bool: - raise ValueError("signed must be bool() True or False") + raise ValueError("signed must be True or False") self._signed = value def get_int(self): """Gibt IO als int() Wert zurueck mit Beachtung byteorder/signed. @return int() Wert""" return int.from_bytes( - self._parentdevice._ba_devdata[self.slc_address], + self._parentdevice._ba_devdata[self._slc_address], byteorder=self._byteorder, signed=self._signed ) @@ -660,7 +702,7 @@ class IntIO(IOBase): )) else: raise ValueError( - "'{}' need an int() value, but {} was given" + "'{}' need a value, but {} was given" "".format(self._name, type(value)) ) @@ -711,9 +753,9 @@ class StructIO(IOBase): name, kwargs.get("defaultvalue", 0), bitlength, - parentio.slc_address.start, + parentio._slc_address.start, False, - str(parentio.slc_address.start).rjust(4, "0"), + str(parentio._slc_address.start).rjust(4, "0"), kwargs.get("bmk", ""), bitaddress ] @@ -734,18 +776,23 @@ class StructIO(IOBase): byteorder, frm == frm.lower() ) - self.frm = frm + self.__frm = bofrm + frm # Platz für neuen IO prüfen - if not (self.slc_address.start >= + if not (self._slc_address.start >= parentio._parentdevice._dict_slc[parentio._iotype].start and - self.slc_address.stop <= + self._slc_address.stop <= parentio._parentdevice._dict_slc[parentio._iotype].stop): raise BufferError( "registered value does not fit process image scope" ) + def _get_frm(self): + """Ruft die struct() Formatierung ab. + @return struct() Formatierung""" + return self.__frm + def _get_signed(self): """Ruft ab, ob der Wert Vorzeichenbehaftet behandelt werden soll. @return True, wenn Vorzeichenbehaftet""" @@ -757,7 +804,7 @@ class StructIO(IOBase): if self._bitaddress >= 0: return self.get_value() else: - return struct.unpack(self.frm, self.get_value())[0] + return struct.unpack(self.__frm, self.get_value())[0] def set_structvalue(self, value): """Setzt den Wert mit struct Formatierung. @@ -765,8 +812,9 @@ class StructIO(IOBase): if self._bitaddress >= 0: self.set_value(value) else: - self.set_value(struct.pack(self.frm, value)) + self.set_value(struct.pack(self.__frm, value)) + frm = property(_get_frm) signed = property(_get_signed) value = property(get_structvalue, set_structvalue) diff --git a/revpimodio2/modio.py b/revpimodio2/modio.py index 185127b..58ada4f 100644 --- a/revpimodio2/modio.py +++ b/revpimodio2/modio.py @@ -65,7 +65,6 @@ class RevPiModIO(object): self._lst_devselect = [] self._lst_refresh = [] self._maxioerrors = 0 - self._myfh = self._create_myfh() self._th_mainloop = None self._waitexit = Event() @@ -78,6 +77,9 @@ class RevPiModIO(object): self.io = None self.summary = None + # Filehandler öffnen + self._myfh = self._create_myfh() + # Nur Konfigurieren, wenn nicht vererbt if type(self) == RevPiModIO: self._configure() @@ -85,7 +87,8 @@ class RevPiModIO(object): def __del__(self): """Zerstoert alle Klassen um aufzuraeumen.""" self.exit(full=True) - self._myfh.close() + if hasattr(self, "_myfh"): + self._myfh.close() def __evt_exit(self, signum, sigframe): """Eventhandler fuer Programmende. @@ -139,7 +142,6 @@ class RevPiModIO(object): # Bei VDev in alter piCtory Version, Position eindeutig machen if device["position"] == "adap.": device["position"] = -1 - # NOTE: Testen mit alter piCtory Version while device["position"] in self.device: device["position"] -= 1 @@ -155,7 +157,7 @@ class RevPiModIO(object): for io in dev_new.get_outputs(): io.set_value(io.defaultvalue) if not self._monitoring: - self.writeprocimg(True, dev_new) + self.writeprocimg(dev_new) elif device["type"] == "LEFT_RIGHT": # IOs @@ -209,7 +211,7 @@ class RevPiModIO(object): # Aktuellen Outputstatus von procimg einlesen if self._syncoutputs: - self.syncoutputs(force=True) + self.syncoutputs() # Optional ins autorefresh aufnehmen if self._autorefresh: @@ -237,7 +239,10 @@ class RevPiModIO(object): def _get_ioerrors(self): """Getter function. @return Aktuelle Anzahl gezaehlter Fehler""" - return self._ioerror + if self._looprunning: + return self._imgwriter._ioerror + else: + return self._ioerror def _get_length(self): """Getter function. @@ -397,14 +402,14 @@ class RevPiModIO(object): self._exit.set() self._waitexit.set() if full: - if self._imgwriter.is_alive(): + if self._imgwriter is not None and self._imgwriter.is_alive(): self._imgwriter.stop() self._imgwriter.join(self._imgwriter._refresh) while len(self._lst_refresh) > 0: dev = self._lst_refresh.pop() dev._selfupdate = False if not self._monitoring: - self.writeprocimg(True, dev) + self.writeprocimg(dev) self._looprunning = False def get_jconfigrsc(self): @@ -541,17 +546,17 @@ class RevPiModIO(object): for io_event in dev._dict_events: - if dev._ba_datacp[io_event.slc_address] == \ - dev._ba_devdata[io_event.slc_address]: + if dev._ba_datacp[io_event._slc_address] == \ + dev._ba_devdata[io_event._slc_address]: continue if io_event._bitaddress >= 0: boolcp = bool(int.from_bytes( - dev._ba_datacp[io_event.slc_address], + dev._ba_datacp[io_event._slc_address], byteorder=io_event._byteorder ) & 1 << io_event._bitaddress) boolor = bool(int.from_bytes( - dev._ba_devdata[io_event.slc_address], + dev._ba_devdata[io_event._slc_address], byteorder=io_event._byteorder ) & 1 << io_event._bitaddress) @@ -603,10 +608,11 @@ class RevPiModIO(object): # Mainloop verlassen self._looprunning = False - def readprocimg(self, force=False, device=None): + def readprocimg(self, device=None): """Einlesen aller Inputs aller/eines Devices vom Prozessabbild. - @param force auch Devices mit autoupdate=False + Devices mit aktiverem autorefresh werden ausgenommen! + @param device nur auf einzelnes Device anwenden @return True, wenn Arbeiten an allen Devices erfolgreich waren @@ -633,20 +639,20 @@ class RevPiModIO(object): return False for dev in mylist: - if (force or dev.autoupdate) and not dev._selfupdate: + if not dev._selfupdate: # FileHandler sperren dev._filelock.acquire() if self._monitoring: # Alles vom Bus einlesen - dev._ba_devdata[:] = bytesbuff[dev.slc_devoff] + dev._ba_devdata[:] = bytesbuff[dev._slc_devoff] else: # Inputs vom Bus einlesen - dev._ba_devdata[dev.slc_inp] = bytesbuff[dev.slc_inpoff] + dev._ba_devdata[dev._slc_inp] = bytesbuff[dev._slc_inpoff] # Mems vom Bus lesen - dev._ba_devdata[dev.slc_mem] = bytesbuff[dev.slc_memoff] + dev._ba_devdata[dev._slc_mem] = bytesbuff[dev._slc_memoff] dev._filelock.release() @@ -657,9 +663,8 @@ class RevPiModIO(object): self._ioerror = 0 self._imgwriter._ioerror = 0 - def setdefaultvalues(self, force=False, device=None): + def setdefaultvalues(self, 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""" if self._monitoring: raise RuntimeError( @@ -675,14 +680,14 @@ class RevPiModIO(object): mylist = [dev] for dev in mylist: - if (force or dev.autoupdate): - for io in dev.get_outputs(): - io.set_value(io.defaultvalue) + for io in dev.get_outputs(): + io.set_value(io.defaultvalue) - def syncoutputs(self, force=False, device=None): + def syncoutputs(self, device=None): """Lesen aller aktuell gesetzten Outputs im Prozessabbild. - @param force auch Devices mit autoupdate=False + Devices mit aktiverem autorefresh werden ausgenommen! + @param device nur auf einzelnes Device anwenden @return True, wenn Arbeiten an allen Devices erfolgreich waren @@ -708,65 +713,18 @@ class RevPiModIO(object): return False for dev in mylist: - if (force or dev.autoupdate) and not dev._selfupdate: + if not dev._selfupdate: dev._filelock.acquire() - # Outputs vom Bus einlesen - dev._ba_devdata[dev.slc_out] = bytesbuff[dev.slc_outoff] + dev._ba_devdata[dev._slc_out] = bytesbuff[dev._slc_outoff] dev._filelock.release() + return True - 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 - - """ - if self._monitoring: - raise RuntimeError( - "can not write process image, while system is in monitoring " - "mode" - ) - - # Device suchen - dev = virtual_device if issubclass(type(virtual_device), devicemodule.Device) \ - else self.__getitem__(virtual_device) - - # Prüfen ob es ein virtuelles Device ist - if not issubclass(type(dev), devicemodule.Virtual): - raise RuntimeError( - "this function can be used for virtual devices only" - ) - - workokay = True - dev._filelock.acquire() - - for io in dev.get_inputs(): - dev._ba_devdata[io.slc_address] = io.defaultvalue - - # Outpus auf Bus schreiben - try: - self._myfh.seek(dev.slc_inpoff.start) - self._myfh.write(dev._ba_devdata[dev.slc_inp]) - if self._buffedwrite: - self._myfh.flush() - except IOError: - self._gotioerror("write") - workokay = False - - dev._filelock.release() - return workokay - - def writeprocimg(self, force=False, device=None): + def writeprocimg(self, device=None): """Schreiben aller Outputs aller Devices ins Prozessabbild. - @param force auch Devices mit autoupdate=False + Devices mit aktiverem autorefresh werden ausgenommen! + @param device nur auf einzelnes Device anwenden @return True, wenn Arbeiten an allen Devices erfolgreich waren @@ -792,13 +750,13 @@ class RevPiModIO(object): workokay = True for dev in mylist: - if (force or dev.autoupdate) and not dev._selfupdate: + if not dev._selfupdate: dev._filelock.acquire() # Outpus auf Bus schreiben try: - self._myfh.seek(dev.slc_outoff.start) - self._myfh.write(dev._ba_devdata[dev.slc_out]) + self._myfh.seek(dev._slc_outoff.start) + self._myfh.write(dev._ba_devdata[dev._slc_out]) except IOError: workokay = False