Fehlerverwaltung bei cycleloop und mainloop

Device.__contains__ Rückgabe bei ersetzen IOs nun False
RevPiModIO.__del__ löst klarere Fehler bei falscher Instantiierung aus
This commit is contained in:
2017-11-08 17:46:50 +01:00
parent 709c0f95be
commit 5887a22ba0
8 changed files with 67 additions and 47 deletions

View File

@@ -480,7 +480,7 @@ IO-Name <class 'str'> / IO-Bytenummer <class 'int'>
</dl><dl> </dl><dl>
<dt>Returns:</dt> <dt>Returns:</dt>
<dd> <dd>
True, wenn device vorhanden True, wenn IO auf Device vorhanden
</dd> </dd>
</dl><a NAME="Device.__getioiter" ID="Device.__getioiter"></a> </dl><a NAME="Device.__getioiter" ID="Device.__getioiter"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000"> <h3 style="background-color:#FFFFFF;color:#FF0000">

View File

@@ -541,7 +541,7 @@ Prueft ob IO existiert.
</p><dl> </p><dl>
<dt><i>key</i></dt> <dt><i>key</i></dt>
<dd> <dd>
IO-Name <class 'str'> oder Byte <class 'int'> IO-Name <class 'str'> oder Bytenummer <class 'int'>
</dd> </dd>
</dl><dl> </dl><dl>
<dt>Returns:</dt> <dt>Returns:</dt>

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Project SYSTEM "Project-5.1.dtd"> <!DOCTYPE Project SYSTEM "Project-5.1.dtd">
<!-- eric project file for project revpimodio2 --> <!-- eric project file for project revpimodio2 -->
<!-- Saved: 2017-11-02, 13:54:10 --> <!-- Saved: 2017-11-06, 13:58:17 -->
<!-- Copyright (C) 2017 Sven Sager, akira@narux.de --> <!-- Copyright (C) 2017 Sven Sager, akira@narux.de -->
<Project version="5.1"> <Project version="5.1">
<Language>en_US</Language> <Language>en_US</Language>
@@ -9,7 +9,7 @@
<ProgLanguage mixed="0">Python3</ProgLanguage> <ProgLanguage mixed="0">Python3</ProgLanguage>
<ProjectType>Console</ProjectType> <ProjectType>Console</ProjectType>
<Description>Das Modul stellt alle Devices und IOs aus der piCtory Konfiguration in Python3 zur Verfügung. Es ermöglicht den direkten Zugriff auf die Werte über deren vergebenen Namen. Lese- und Schreibaktionen mit dem Prozessabbild werden von dem Modul selbst verwaltet, ohne dass sich der Programmierer um Offsets und Adressen kümmern muss. Für die Gatewaymodule wie ModbusTCP oder Profinet sind eigene 'Inputs' und 'Outputs' über einen bestimmten Adressbereich definierbar. Auf diese IOs kann mit Python3 über den Namen direkt auf die Werte zugegriffen werden.</Description> <Description>Das Modul stellt alle Devices und IOs aus der piCtory Konfiguration in Python3 zur Verfügung. Es ermöglicht den direkten Zugriff auf die Werte über deren vergebenen Namen. Lese- und Schreibaktionen mit dem Prozessabbild werden von dem Modul selbst verwaltet, ohne dass sich der Programmierer um Offsets und Adressen kümmern muss. Für die Gatewaymodule wie ModbusTCP oder Profinet sind eigene 'Inputs' und 'Outputs' über einen bestimmten Adressbereich definierbar. Auf diese IOs kann mit Python3 über den Namen direkt auf die Werte zugegriffen werden.</Description>
<Version>2.0.6</Version> <Version>2.0.7</Version>
<Author>Sven Sager</Author> <Author>Sven Sager</Author>
<Email>akira@narux.de</Email> <Email>akira@narux.de</Email>
<Eol index="1"/> <Eol index="1"/>
@@ -31,7 +31,8 @@
<Source>test/web_virtdevdriver.py</Source> <Source>test/web_virtdevdriver.py</Source>
<Source>test/web_benniesrun.py</Source> <Source>test/web_benniesrun.py</Source>
<Source>test/web_benniesrunxxl.py</Source> <Source>test/web_benniesrunxxl.py</Source>
<Source>test_unit.py</Source> <Source>test/test_unit.py</Source>
<Source>test/test_unitnet.py</Source>
</Sources> </Sources>
<Forms/> <Forms/>
<Translations/> <Translations/>
@@ -43,7 +44,7 @@
<Other>MANIFEST.in</Other> <Other>MANIFEST.in</Other>
<Other>eric-revpimodio2.api</Other> <Other>eric-revpimodio2.api</Other>
</Others> </Others>
<MainScript>test_unit.py</MainScript> <MainScript>test/test_unit.py</MainScript>
<Vcs> <Vcs>
<VcsType>Mercurial</VcsType> <VcsType>Mercurial</VcsType>
<VcsOptions> <VcsOptions>
@@ -182,7 +183,6 @@
<value> <value>
<list> <list>
<string>setup.py</string> <string>setup.py</string>
<string>test_unit.py</string>
</list> </list>
</value> </value>
<key> <key>
@@ -229,7 +229,6 @@
<value> <value>
<list> <list>
<string>setup.py</string> <string>setup.py</string>
<string>test_unit.py</string>
</list> </list>
</value> </value>
<key> <key>
@@ -281,7 +280,7 @@
<string>ExcludeFiles</string> <string>ExcludeFiles</string>
</key> </key>
<value> <value>
<string>*/test_unit.py</string> <string>./test/*</string>
</value> </value>
<key> <key>
<string>ExcludeMessages</string> <string>ExcludeMessages</string>

View File

@@ -24,7 +24,7 @@ __all__ = [
__author__ = "Sven Sager <akira@revpimodio.org>" __author__ = "Sven Sager <akira@revpimodio.org>"
__name__ = "revpimodio2" __name__ = "revpimodio2"
__package__ = "revpimodio2" __package__ = "revpimodio2"
__version__ = "2.0.6" __version__ = "2.0.7"
# Global package values # Global package values
OFF = 0 OFF = 0

View File

@@ -171,18 +171,20 @@ class Device(object):
def __contains__(self, key): def __contains__(self, key):
"""Prueft ob IO auf diesem Device liegt. """Prueft ob IO auf diesem Device liegt.
@param key IO-Name <class 'str'> / IO-Bytenummer <class 'int'> @param key IO-Name <class 'str'> / IO-Bytenummer <class 'int'>
@return True, wenn device vorhanden""" @return True, wenn IO auf Device vorhanden"""
if type(key) == str: if issubclass(type(key), IOBase):
return key in self._modio.io \ # Umwandlung für key
and getattr(self._modio.io, key)._parentdevice == self key = key._name
elif type(key) == int:
if type(key) == int:
if key in self._modio.io: if key in self._modio.io:
for io in self._modio.io[key]: for io in self._modio.io[key]:
if io is not None and io._parentdevice == self: if io is not None and io._parentdevice == self:
return True return True
return False return False
else: else:
return key._parentdevice == self return key in self._modio.io \
and getattr(self._modio.io, key)._parentdevice == self
def __int__(self): def __int__(self):
"""Gibt die Positon im RevPi Bus zurueck. """Gibt die Positon im RevPi Bus zurueck.

View File

@@ -22,11 +22,10 @@ class IOList(object):
def __contains__(self, key): def __contains__(self, key):
"""Prueft ob IO existiert. """Prueft ob IO existiert.
@param key IO-Name <class 'str'> oder Byte <class 'int'> @param key IO-Name <class 'str'> oder Bytenummer <class 'int'>
@return True, wenn IO vorhanden / Byte belegt""" @return True, wenn IO vorhanden / Byte belegt"""
if type(key) == int: if type(key) == int:
return key in self.__dict_iobyte \ return len(self.__dict_iobyte.get(key, [])) > 0
and len(self.__dict_iobyte[key]) > 0
else: else:
return hasattr(self, key) and type(getattr(self, key)) != DeadIO return hasattr(self, key) and type(getattr(self, key)) != DeadIO

View File

@@ -86,6 +86,7 @@ class RevPiModIO(object):
def __del__(self): def __del__(self):
"""Zerstoert alle Klassen um aufzuraeumen.""" """Zerstoert alle Klassen um aufzuraeumen."""
if hasattr(self, "_exit"):
self.exit(full=True) self.exit(full=True)
if self._myfh is not None: if self._myfh is not None:
self._myfh.close() self._myfh.close()
@@ -368,10 +369,14 @@ class RevPiModIO(object):
self._looprunning = True self._looprunning = True
cycleinfo = helpermodule.Cycletools(self._imgwriter.refresh) cycleinfo = helpermodule.Cycletools(self._imgwriter.refresh)
ec = None ec = None
try:
while ec is None and not self._exit.is_set(): while ec is None and not self._exit.is_set():
# Auf neue Daten warten und nur ausführen wenn set() # Auf neue Daten warten und nur ausführen wenn set()
if not self._imgwriter.newdata.wait(2.5): if not self._imgwriter.newdata.wait(2.5):
if not self._exit.is_set() and not self._imgwriter.is_alive(): if not self._exit.is_set() \
and not self._imgwriter.is_alive():
self.exit(full=False)
self._looprunning = False
raise RuntimeError("autorefresh thread not running") raise RuntimeError("autorefresh thread not running")
continue continue
self._imgwriter.newdata.clear() self._imgwriter.newdata.clear()
@@ -385,6 +390,12 @@ class RevPiModIO(object):
# autorefresh freigeben # autorefresh freigeben
self._imgwriter.lck_refresh.release() self._imgwriter.lck_refresh.release()
except Exception as e:
if self._imgwriter.lck_refresh.locked():
self._imgwriter.lck_refresh.release()
self.exit(full=False)
self._looprunning = False
raise e
# Cycleloop beenden # Cycleloop beenden
self._looprunning = False self._looprunning = False
@@ -533,6 +544,8 @@ class RevPiModIO(object):
# Auf neue Daten warten und nur ausführen wenn set() # Auf neue Daten warten und nur ausführen wenn set()
if not self._imgwriter.newdata.wait(2.5): if not self._imgwriter.newdata.wait(2.5):
if not self._exit.is_set() and not self._imgwriter.is_alive(): if not self._exit.is_set() and not self._imgwriter.is_alive():
self.exit(full=False)
self._looprunning = False
raise RuntimeError("autorefresh thread not running") raise RuntimeError("autorefresh thread not running")
continue continue
@@ -624,6 +637,7 @@ class RevPiModIO(object):
del dict_delay[tup_fire] del dict_delay[tup_fire]
# Erst nach Datenübernahme alle Events feuern # Erst nach Datenübernahme alle Events feuern
try:
while len(lst_fire) > 0: while len(lst_fire) > 0:
tup_fire = lst_fire.pop() tup_fire = lst_fire.pop()
if tup_fire[0][2]: if tup_fire[0][2]:
@@ -634,6 +648,12 @@ class RevPiModIO(object):
else: else:
# Direct callen da Prüfung in io.IOBase.reg_event ist # Direct callen da Prüfung in io.IOBase.reg_event ist
tup_fire[0][0](tup_fire[1], tup_fire[2]) tup_fire[0][0](tup_fire[1], tup_fire[2])
except Exception as e:
if self._imgwriter.lck_refresh.locked():
self._imgwriter.lck_refresh.release()
self.exit(full=False)
self._looprunning = False
raise e
# Refreshsperre aufheben wenn freeze # Refreshsperre aufheben wenn freeze
if freeze: if freeze:

View File

@@ -16,7 +16,7 @@ setup(
license="LGPLv3", license="LGPLv3",
name="revpimodio2", name="revpimodio2",
version="2.0.6", version="2.0.7",
packages=["revpimodio2"], packages=["revpimodio2"],
python_requires="~=3.2", python_requires="~=3.2",