diff --git a/doc/index-revpimodio2.html b/doc/index-revpimodio2.html index d5e3960..421e8fa 100644 --- a/doc/index-revpimodio2.html +++ b/doc/index-revpimodio2.html @@ -23,6 +23,9 @@ fuehrt das Modul bei Datenaenderung aus. Modules + + + diff --git a/doc/revpimodio2.__init__.html b/doc/revpimodio2.__init__.html index bbc660a..a4e3fc4 100644 --- a/doc/revpimodio2.__init__.html +++ b/doc/revpimodio2.__init__.html @@ -25,46 +25,35 @@ Global Attributes

Classes

revpimodio2Stellt alle Klassen fuer den RevolutionPi zur Verfuegung.
app Bildet die App Sektion von piCtory ab.
- - - - +
IOTypeIO Typen.
None

Functions

- + + + +
None
consttostrGibt fuer Konstanten zurueck.


- -

IOType

+ +

consttostr

+consttostr(value)

-IO Typen. -

-

-Derived from

-object -

-Class Attributes

- - -
INP
MEM
OUT
-

-Class Methods

- - -
None
-

-Methods

- - -
None
-

-Static Methods

- - -
None
- +Gibt fuer Konstanten zurueck. +

+ Diese Funktion ist erforderlich, da enum in Python 3.2 nicht existiert. +

+
value
+
+Konstantenwert +
+
+
Returns:
+
+ Name der Konstanten +
+
Up

\ No newline at end of file diff --git a/doc/revpimodio2.device.html b/doc/revpimodio2.device.html index 3872073..39e0e95 100644 --- a/doc/revpimodio2.device.html +++ b/doc/revpimodio2.device.html @@ -411,7 +411,7 @@ Methods get_inputs Gibt eine Liste aller Inputs zurueck. -get_memmories +get_memories Gibt eine Liste aller mems zurueck. get_outputs @@ -603,10 +603,10 @@ Gibt eine Liste aller Inputs zurueck.
Inputs
- +

-Device.get_memmories

-get_memmories() +Device.get_memories +get_memories()

Gibt eine Liste aller mems zurueck.

diff --git a/doc/revpimodio2.io.html b/doc/revpimodio2.io.html index 2b9c16f..9989511 100644 --- a/doc/revpimodio2.io.html +++ b/doc/revpimodio2.io.html @@ -163,7 +163,7 @@ Methods Gibt den Wert des IOs zurueck. reg_event -Registriert ein Event bei der Eventueberwachung. +Registriert fuer IO ein Event bei der Eventueberwachung. replace_io Ersetzt bestehenden IO mit Neuem. @@ -297,13 +297,20 @@ IO-Wert als oder

IOBase.reg_event

-reg_event(func, edge=BOTH, as_thread=False) +reg_event(func, delay=0, edge=BOTH, as_thread=False)

-Registriert ein Event bei der Eventueberwachung. +Registriert fuer IO ein Event bei der Eventueberwachung. +

+ Die uebergebene Funktion wird ausgefuehrt, wenn sich der IO Wert + aendert. Mit Angabe von optionalen Parametern kann das + Ausloeseverhalten gesteuert werden.

func
Funktion die bei Aenderung aufgerufen werden soll +
delay
+
+Verzoegerung in ms zum Ausloesen wenn Wert gleich bleibt
edge
Ausfuehren bei RISING, FALLING or BOTH Wertaenderung @@ -317,23 +324,27 @@ IOBase.replace_io replace_io(name, frm, **kwargs)

Ersetzt bestehenden IO mit Neuem. +

+ Wenn die kwargs fuer byteorder und defaultvalue nicht angegeben werden, + uebernimmt das System die Daten aus dem ersetzten IO.

name
Name des neuen Inputs
frm
-struct formatierung (1 Zeichen) +struct Formatierung (1 Zeichen)
kwargs
Weitere Parameter: - - bmk: Bezeichnung fuer Input + - bmk: interne Bezeichnung fuer IO - bit: Registriert IO als am angegebenen Bit im Byte - - byteorder: Byteorder fuer den Input, Standardwert=little - - defaultvalue: Standardwert fuer Input, Standard ist 0 + - byteorder: Byteorder fuer den IO, Standardwert=little + - defaultvalue: Standardwert fuer IO - event: Funktion fuer Eventhandling registrieren + - delay: Verzoegerung in ms zum Ausloesen wenn Wert gleich bleibt + - edge: Event ausfuehren bei RISING, FALLING or BOTH Wertaenderung - as_thread: Fuehrt die event-Funktion als RevPiCallback-Thread aus - - edge: event-Ausfuehren bei RISING, FALLING or BOTH Wertaenderung
See Also:
@@ -380,7 +391,7 @@ Wartet auf Wertaenderung eines IOs. HINWEIS: Wenn 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 + 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.

@@ -393,21 +404,21 @@ Wartet auf Wertaenderung eines IOs.

Der Timeoutwert bricht beim Erreichen das Warten sofort mit Wert 2 Rueckgabewert ab. (Das Timeout wird ueber die Zykluszeit - der autorefresh Funktion berechnet, entspricht also nicht exact den + der autorefresh Funktion berechnet, entspricht also nicht exakt den angegeben Millisekunden! Es wird immer nach oben gerundet!)

edge
-Flanke RISING, FALLING, BOTH bei der mit True beendet wird +Flanke RISING, FALLING, BOTH die eintreten muss
exitevent
fuer vorzeitiges Beenden
okvalue
-IO-Wert, bei dem das Warten sofort mit True beendet wird +IO-Wert, bei dem das Warten sofort beendet wird
timeout
-Zeit in ms nach der mit False abgebrochen wird +Zeit in ms nach der abgebrochen wird
Returns:
@@ -650,13 +661,13 @@ Methods _set_signed Left fest, ob der Wert Vorzeichenbehaftet behandelt werden soll. -get_int -Gibt IO-Wert zurueck mit Beachtung byteorder/signed. - get_intdefaultvalue Gibt die Defaultvalue als zurueck. -set_int +get_intvalue +Gibt IO-Wert zurueck mit Beachtung byteorder/signed. + +set_intvalue Setzt IO mit Beachtung byteorder/signed. @@ -709,17 +720,6 @@ Left fest, ob der Wert Vorzeichenbehaftet behandelt werden soll.
True, wenn mit Vorzeichen behandel
-
-

-IntIO.get_int

-get_int() -

-Gibt IO-Wert zurueck mit Beachtung byteorder/signed. -

-
Returns:
-
-IO-Wert als -

IntIO.get_intdefaultvalue

@@ -731,10 +731,21 @@ Gibt die Defaultvalue als zurueck.
Defaultvalue
-
+

-IntIO.set_int

-set_int(value) +IntIO.get_intvalue +get_intvalue() +

+Gibt IO-Wert zurueck mit Beachtung byteorder/signed. +

+
Returns:
+
+IO-Wert als +
+
+

+IntIO.set_intvalue

+set_intvalue(value)

Setzt IO mit Beachtung byteorder/signed.

diff --git a/doc/revpimodio2.modio.html b/doc/revpimodio2.modio.html index f880693..ae91e2c 100644 --- a/doc/revpimodio2.modio.html +++ b/doc/revpimodio2.modio.html @@ -350,7 +350,7 @@ RevPiModIO.cycleloop Startet den Cycleloop.

Der aktuelle Programmthread wird hier bis Aufruf von - RevPiDevicelist.exit() "gefangen". Er fuehrt nach jeder Aktualisierung + .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 diff --git a/eric-revpimodio2.api b/eric-revpimodio2.api index 6c11d5c..9547b10 100644 --- a/eric-revpimodio2.api +++ b/eric-revpimodio2.api @@ -5,6 +5,7 @@ revpimodio2.OFF?7 revpimodio2.RED?7 revpimodio2.RISING?7 revpimodio2.app.App?1(app) +revpimodio2.consttostr?4(value) revpimodio2.device.Core.A1?7 revpimodio2.device.Core.A2?7 revpimodio2.device.Core._devconfigure?5() @@ -33,7 +34,7 @@ revpimodio2.device.Device._get_producttype?5() 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_memories?4() revpimodio2.device.Device.get_outputs?4() revpimodio2.device.Device.length?7 revpimodio2.device.Device.name?7 @@ -84,7 +85,7 @@ revpimodio2.io.IOBase.get_defaultvalue?4() revpimodio2.io.IOBase.get_value?4() revpimodio2.io.IOBase.length?7 revpimodio2.io.IOBase.name?7 -revpimodio2.io.IOBase.reg_event?4(func, edge=BOTH, as_thread=False) +revpimodio2.io.IOBase.reg_event?4(func, delay=0, edge=BOTH, as_thread=False) revpimodio2.io.IOBase.replace_io?4(name, frm, **kwargs) revpimodio2.io.IOBase.set_value?4(value) revpimodio2.io.IOBase.type?7 @@ -99,9 +100,9 @@ revpimodio2.io.IntIO._set_byteorder?5(value) revpimodio2.io.IntIO._set_signed?5(value) revpimodio2.io.IntIO.byteorder?7 revpimodio2.io.IntIO.defaultvalue?7 -revpimodio2.io.IntIO.get_int?4() revpimodio2.io.IntIO.get_intdefaultvalue?4() -revpimodio2.io.IntIO.set_int?4(value) +revpimodio2.io.IntIO.get_intvalue?4() +revpimodio2.io.IntIO.set_intvalue?4(value) revpimodio2.io.IntIO.signed?7 revpimodio2.io.IntIO.value?7 revpimodio2.io.StructIO._get_frm?5() diff --git a/revpimodio2.e4p b/revpimodio2.e4p index 0ed1e50..5655f68 100644 --- a/revpimodio2.e4p +++ b/revpimodio2.e4p @@ -1,7 +1,7 @@ - + en_US @@ -26,7 +26,6 @@ test/test_dio_mainloop.py test/test_dio_cycleloop.py test/test_net_leistung.py - revpimodio2/net.py test/web_cycleloop.py test/web_mainloop.py @@ -338,4 +337,23 @@ + + + + + CodeMetrics + + + + + ExcludeFiles + + + */test/* + + + + + + diff --git a/revpimodio2/__init__.py b/revpimodio2/__init__.py index f277886..c9a740d 100644 --- a/revpimodio2/__init__.py +++ b/revpimodio2/__init__.py @@ -35,3 +35,28 @@ FALLING = 32 BOTH = 33 warnings.simplefilter(action="always") + + +def consttostr(value): + """Gibt fuer Konstanten zurueck. + + Diese Funktion ist erforderlich, da enum in Python 3.2 nicht existiert. + + @param value Konstantenwert + @return Name der Konstanten + + """ + if value == 0: + return "OFF" + elif value == 1: + return "GREEN" + elif value == 2: + return "RED" + elif value == 31: + return "RISING" + elif value == 32: + return "FALLING" + elif value == 33: + return "BOTH" + else: + return "" diff --git a/revpimodio2/device.py b/revpimodio2/device.py index 3433812..62d0343 100644 --- a/revpimodio2/device.py +++ b/revpimodio2/device.py @@ -317,7 +317,7 @@ class Device(object): lst_return += lst_io return lst_return - def get_memmories(self): + def get_memories(self): """Gibt eine Liste aller mems zurueck. @return Mems""" lst_return = [] diff --git a/revpimodio2/io.py b/revpimodio2/io.py index 33769ea..60371ee 100644 --- a/revpimodio2/io.py +++ b/revpimodio2/io.py @@ -8,7 +8,7 @@ """RevPiModIO Modul fuer die Verwaltung der IOs.""" import struct from threading import Event -from .__init__ import RISING, FALLING, BOTH +from .__init__ import RISING, FALLING, BOTH, consttostr class Type(object): @@ -356,32 +356,44 @@ class IOBase(object): else: 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. + def reg_event(self, func, delay=0, edge=BOTH, as_thread=False): + """Registriert fuer IO ein Event bei der Eventueberwachung. + + Die uebergebene Funktion wird ausgefuehrt, wenn sich der IO Wert + aendert. Mit Angabe von optionalen Parametern kann das + Ausloeseverhalten gesteuert werden. @param func Funktion die bei Aenderung aufgerufen werden soll + @param delay Verzoegerung in ms zum Ausloesen wenn Wert gleich bleibt @param edge Ausfuehren bei RISING, FALLING or BOTH Wertaenderung @param as_thread Bei True, Funktion als EventCallback-Thread ausfuehren """ # Prüfen ob Funktion callable ist if not callable(func): - raise RuntimeError( - "registered function '{}' ist not callable".format(func) + raise AttributeError( + "registered function '{}' is not callable".format(func) + ) + if type(delay) != int or delay < 0: + raise AttributeError( + "parameter 'delay' must be greater or equal 0" ) - if edge != BOTH and self._bitaddress < 0: raise AttributeError( "parameter 'edge' can be used with bit io objects only" ) if self not in self._parentdevice._dict_events: - self._parentdevice._dict_events[self] = [(func, edge, as_thread)] + self._parentdevice._dict_events[self] = \ + [(func, edge, as_thread, delay)] else: # Prüfen ob Funktion schon registriert ist for regfunc in self._parentdevice._dict_events[self]: + if regfunc[0] != func: + # Nächsten Eintrag testen + continue - if regfunc[0] == func and edge == BOTH: + if edge == BOTH or regfunc[1] == BOTH: if self._bitaddress < 0: raise AttributeError( "io '{}' with function '{}' already in list." @@ -389,35 +401,42 @@ class IOBase(object): ) else: raise AttributeError( - "io '{}' with function '{}' already in list. " - "edge 'BOTH' not allowed anymore".format( - self._name, func + "io '{}' with function '{}' already in list with " + "edge '{}' - edge '{}' not allowed anymore".format( + self._name, func, + consttostr(regfunc[1]), consttostr(edge) ) ) - elif regfunc[0] == func and regfunc[1] == edge: + elif regfunc[1] == edge: raise AttributeError( - "io '{}' with function '{}' for given edge " - "already in list".format(self._name, func) + "io '{}' with function '{}' for given edge '{}' " + "already in list".format( + self._name, func, consttostr(edge) + ) ) - else: - self._parentdevice._dict_events[self].append( - (func, edge, as_thread) - ) - break + + # Eventfunktion einfügen + self._parentdevice._dict_events[self].append( + (func, edge, as_thread, delay) + ) def replace_io(self, name, frm, **kwargs): """Ersetzt bestehenden IO mit Neuem. + Wenn die kwargs fuer byteorder und defaultvalue nicht angegeben werden, + uebernimmt das System die Daten aus dem ersetzten IO. + @param name Name des neuen Inputs - @param frm struct formatierung (1 Zeichen) + @param frm struct Formatierung (1 Zeichen) @param kwargs Weitere Parameter: - - bmk: Bezeichnung fuer Input + - bmk: interne Bezeichnung fuer IO - bit: Registriert IO als am angegebenen Bit im Byte - - byteorder: Byteorder fuer den Input, Standardwert=little - - defaultvalue: Standardwert fuer Input, Standard ist 0 + - byteorder: Byteorder fuer den IO, Standardwert=little + - defaultvalue: Standardwert fuer IO - event: Funktion fuer Eventhandling registrieren + - delay: Verzoegerung in ms zum Ausloesen wenn Wert gleich bleibt + - edge: Event ausfuehren bei RISING, FALLING or BOTH Wertaenderung - as_thread: Fuehrt die event-Funktion als RevPiCallback-Thread aus - - edge: event-Ausfuehren bei RISING, FALLING or BOTH Wertaenderung @see Python3 struct @@ -449,8 +468,9 @@ class IOBase(object): if reg_event is not None: io_new.reg_event( reg_event, - as_thread=kwargs.get("as_thread", False), - edge=kwargs.get("edge", BOTH) + kwargs.get("delay", 0), + kwargs.get("edge", BOTH), + kwargs.get("as_thread", False) ) def set_value(self, value): @@ -548,7 +568,7 @@ class IOBase(object): HINWEIS: Wenn 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 + 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. @@ -561,13 +581,13 @@ class IOBase(object): Der Timeoutwert bricht beim Erreichen das Warten sofort mit Wert 2 Rueckgabewert ab. (Das Timeout wird ueber die Zykluszeit - der autorefresh Funktion berechnet, entspricht also nicht exact den + der autorefresh Funktion berechnet, entspricht also nicht exakt den angegeben Millisekunden! Es wird immer nach oben gerundet!) - @param edge Flanke RISING, FALLING, BOTH bei der mit True beendet wird + @param edge Flanke RISING, FALLING, BOTH die eintreten muss @param exitevent fuer vorzeitiges Beenden - @param okvalue IO-Wert, bei dem das Warten sofort mit True beendet wird - @param timeout Zeit in ms nach der mit False abgebrochen wird + @param okvalue IO-Wert, bei dem das Warten sofort beendet wird + @param timeout Zeit in ms nach der abgebrochen wird @return erfolgreich Werte <= 0 - Erfolgreich gewartet Wert 0: IO hat den Wert gewechselt @@ -695,7 +715,7 @@ class IntIO(IOBase): self._defaultvalue, byteorder=self._byteorder, signed=self._signed ) - def get_int(self): + def get_intvalue(self): """Gibt IO-Wert zurueck mit Beachtung byteorder/signed. @return IO-Wert als """ return int.from_bytes( @@ -704,7 +724,7 @@ class IntIO(IOBase): signed=self._signed ) - def set_int(self, value): + def set_intvalue(self, value): """Setzt IO mit Beachtung byteorder/signed. @param value Wert""" if type(value) == int: @@ -722,7 +742,7 @@ class IntIO(IOBase): byteorder = property(IOBase._get_byteorder, _set_byteorder) defaultvalue = property(get_intdefaultvalue) signed = property(_get_signed, _set_signed) - value = property(get_int, set_int) + value = property(get_intvalue, set_intvalue) class StructIO(IOBase): diff --git a/revpimodio2/modio.py b/revpimodio2/modio.py index c904153..987c103 100644 --- a/revpimodio2/modio.py +++ b/revpimodio2/modio.py @@ -281,7 +281,13 @@ class RevPiModIO(object): def _set_cycletime(self, milliseconds): """Setzt Aktualisierungsrate der Prozessabbild-Synchronisierung. @param milliseconds in Millisekunden""" - self._imgwriter.refresh = milliseconds + if self._looprunning: + raise RuntimeError( + "can not change cycletime when cycleloop or mainloop are " + "running" + ) + else: + self._imgwriter.refresh = milliseconds def _set_maxioerrors(self, value): """Setzt Anzahl der maximal erlaubten Fehler bei Prozessabbildzugriff. @@ -311,7 +317,7 @@ class RevPiModIO(object): """Startet den Cycleloop. Der aktuelle Programmthread wird hier bis Aufruf von - RevPiDevicelist.exit() "gefangen". Er fuehrt nach jeder Aktualisierung + .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 @@ -518,6 +524,7 @@ class RevPiModIO(object): dev._filelock.release() lst_fire = [] + dict_delay = {} while not self._exit.is_set(): # Auf neue Daten warten und nur ausführen wenn set() @@ -560,15 +567,28 @@ class RevPiModIO(object): if regfunc[1] == BOTH \ or regfunc[1] == RISING and boolor \ or regfunc[1] == FALLING and not boolor: + if regfunc[3] == 0: + lst_fire.append(( + regfunc, io_event._name, io_event.value + )) + else: + # Verzögertes Event in dict einfügen + dict_delay[( + regfunc, io_event._name, io_event.value + )] = int( + regfunc[3] / self._imgwriter.refresh + ) + else: + for regfunc in dev._dict_events[io_event]: + if regfunc[3] == 0: lst_fire.append( (regfunc, io_event._name, io_event.value) ) - - else: - for regfunc in dev._dict_events[io_event]: - lst_fire.append( - (regfunc, io_event._name, io_event.value) - ) + else: + # Verzögertes Event in dict einfügen + dict_delay[( + regfunc, io_event._name, io_event.value + )] = int(regfunc[3] / self._imgwriter.refresh) # Nach Verarbeitung aller IOs die Bytes kopieren dev._filelock.acquire() @@ -579,20 +599,29 @@ class RevPiModIO(object): if not freeze: self._imgwriter.lck_refresh.release() + # Verzögerte Events prüfen + for tup_fire in list(dict_delay.keys()): + if getattr(self.io, tup_fire[1]).value != tup_fire[2]: + del dict_delay[tup_fire] + else: + dict_delay[tup_fire] -= 1 + if dict_delay[tup_fire] <= 0: + # Verzögertes Event übernehmen und löschen + lst_fire.append(tup_fire) + del dict_delay[tup_fire] + # Erst nach Datenübernahme alle Events feuern while len(lst_fire) > 0: + # EventTuple ((func, edge, as_thread, delay), ioname, iovalue) tup_fire = lst_fire.pop() - event_func = tup_fire[0][0] - passname = tup_fire[1] - passvalue = tup_fire[2] if tup_fire[0][2]: th = helpermodule.EventCallback( - event_func, passname, passvalue + tup_fire[0][0], tup_fire[1], tup_fire[2] ) th.start() else: - # Direct callen da Prüfung in RevPiDevice.reg_event ist - event_func(passname, passvalue) + # Direct callen da Prüfung in io.IOBase.reg_event ist + tup_fire[0][0](tup_fire[1], tup_fire[2]) # Refreshsperre aufheben wenn freeze if freeze: