Watchdog for all RevPis, cycletools with .core/.io/.runtime, bugfix on MemIO for str()

All RevPis got .core.wd for Software-Watchdog with RevPiPyLoad
All RevPis has .core.wd_toggle() function to toggle watchdog bit
Cycletools has .core and .io attribute to be independent of rpi object
Cycletools has .runtime to get the actual runtime of function
This commit is contained in:
2020-05-03 13:43:09 +02:00
parent d54a588a78
commit a6a227e99e
7 changed files with 74 additions and 27 deletions

6
.idea/codeStyles/Project.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<option name="LINE_SEPARATOR" value="&#10;" />
<option name="RIGHT_MARGIN" value="80" />
</code_scheme>
</component>

5
.idea/codeStyles/codeStyleConfig.xml generated Normal file
View File

@@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>

View File

@@ -542,12 +542,13 @@ class Core(Base):
__slots__ = "_slc_cycle", "_slc_errorcnt", "_slc_statusbyte", \ __slots__ = "_slc_cycle", "_slc_errorcnt", "_slc_statusbyte", \
"_slc_temperature", "_slc_errorlimit1", "_slc_errorlimit2", \ "_slc_temperature", "_slc_errorlimit1", "_slc_errorlimit2", \
"_slc_frequency", "_slc_led", "a1green", "a1red", "a2green", "a2red" "_slc_frequency", "_slc_led", "a1green", "a1red", \
"a2green", "a2red", "wd"
def __setattr__(self, key, value): def __setattr__(self, key, value):
"""Verhindert Ueberschreibung der LEDs.""" """Verhindert Ueberschreibung der LEDs."""
if hasattr(self, key) and key in ( if hasattr(self, key) and key in (
"a1green", "a1red", "a2green", "a2red"): "a1green", "a1red", "a2green", "a2red", "wd"):
raise AttributeError( raise AttributeError(
"direct assignment is not supported - use .value Attribute" "direct assignment is not supported - use .value Attribute"
) )
@@ -616,6 +617,12 @@ class Core(Base):
exp_a2red, None, "LED_A2_RED", "3" exp_a2red, None, "LED_A2_RED", "3"
], OUT, "little", False) ], OUT, "little", False)
# Watchdog einrichten (Core=soft / Connect=soft/hard)
self.wd = IOBase(self, [
"core.wd", 0, 1, self._slc_led.start,
False, None, "WatchDog", "7"
], OUT, "little", False)
def __errorlimit(self, slc_io: slice, errorlimit: int) -> None: def __errorlimit(self, slc_io: slice, errorlimit: int) -> None:
""" """
Verwaltet das Schreiben der ErrorLimits. Verwaltet das Schreiben der ErrorLimits.
@@ -694,6 +701,10 @@ class Core(Base):
else: else:
raise ValueError("led status must be between 0 and 3") raise ValueError("led status must be between 0 and 3")
def wd_toggle(self):
"""Toggle watchdog bit to prevent a timeout."""
self.wd.value = not self.wd.value
A1 = property(_get_leda1, _set_leda1) A1 = property(_get_leda1, _set_leda1)
A2 = property(_get_leda2, _set_leda2) A2 = property(_get_leda2, _set_leda2)
status = property(_get_status) status = property(_get_status)
@@ -865,19 +876,17 @@ class Connect(Core):
Stellt Funktionen fuer die LEDs, Watchdog und den Status zur Verfuegung. Stellt Funktionen fuer die LEDs, Watchdog und den Status zur Verfuegung.
""" """
__slots__ = "__evt_wdtoggle", "__th_wdtoggle", "a3green", "a3red", "wd", \ __slots__ = "__evt_wdtoggle", "__th_wdtoggle", "a3green", "a3red", \
"x2in", "x2out" "x2in", "x2out"
def __setattr__(self, key, value): def __setattr__(self, key, value):
"""Verhindert Ueberschreibung der LEDs.""" """Verhindert Ueberschreibung der speziellen IOs."""
if hasattr(self, key) and key in ( if hasattr(self, key) and key in (
"a1green", "a1red", "a2green", "a2red", "a3green", "a3red", "a3green", "a3red", "x2in", "x2out"):
"wd", "x2in", "x2out"):
raise AttributeError( raise AttributeError(
"direct assignment is not supported - use .value Attribute" "direct assignment is not supported - use .value Attribute"
) )
else: super(Connect, self).__setattr__(key, value)
object.__setattr__(self, key, value)
def __wdtoggle(self) -> None: def __wdtoggle(self) -> None:
"""WD Ausgang alle 10 Sekunden automatisch toggeln.""" """WD Ausgang alle 10 Sekunden automatisch toggeln."""
@@ -921,10 +930,6 @@ class Connect(Core):
], OUT, "little", False) ], OUT, "little", False)
# IO Objekte für WD und X2 in/out erzeugen # IO Objekte für WD und X2 in/out erzeugen
self.wd = IOBase(self, [
"core.wd", 0, 1, self._slc_led.start,
exp_wd, None, "Connect_WatchDog", "7"
], OUT, "little", False)
self.x2in = IOBase(self, [ self.x2in = IOBase(self, [
"core.x2in", 0, 1, self._slc_statusbyte.start, "core.x2in", 0, 1, self._slc_statusbyte.start,
exp_x2in, None, "Connect_X2_IN", "6" exp_x2in, None, "Connect_X2_IN", "6"
@@ -1015,7 +1020,7 @@ class Compact(Base):
""" """
__slots__ = "_slc_temperature", "_slc_frequency", "_slc_led", \ __slots__ = "_slc_temperature", "_slc_frequency", "_slc_led", \
"a1green", "a1red", "a2green", "a2red" "a1green", "a1red", "a2green", "a2red", "wd"
def __setattr__(self, key, value): def __setattr__(self, key, value):
"""Verhindert Ueberschreibung der LEDs.""" """Verhindert Ueberschreibung der LEDs."""
@@ -1066,6 +1071,12 @@ class Compact(Base):
exp_a2red, None, "LED_A2_RED", "3" exp_a2red, None, "LED_A2_RED", "3"
], OUT, "little", False) ], OUT, "little", False)
# Software watchdog einrichten
self.wd = IOBase(self, [
"core.wd", 0, 1, self._slc_led.start,
False, None, "WatchDog", "7"
], OUT, "little", False)
def _get_leda1(self) -> int: def _get_leda1(self) -> int:
""" """
Gibt den Zustand der LED A1 vom Compact zurueck. Gibt den Zustand der LED A1 vom Compact zurueck.
@@ -1119,6 +1130,10 @@ class Compact(Base):
else: else:
raise ValueError("led status must be between 0 and 3") raise ValueError("led status must be between 0 and 3")
def wd_toggle(self):
"""Toggle watchdog bit to prevent a timeout."""
self.wd.value = not self.wd.value
A1 = property(_get_leda1, _set_leda1) A1 = property(_get_leda1, _set_leda1)
A2 = property(_get_leda2, _set_leda2) A2 = property(_get_leda2, _set_leda2)

View File

@@ -85,12 +85,12 @@ class Cycletools:
Lampen synchron blinken zu lassen. Lampen synchron blinken zu lassen.
""" """
__slots__ = "__cycle", "__cycletime", "__ucycle", \ __slots__ = "__cycle", "__cycletime", "__ucycle", "__dict_ton", \
"__dict_ton", "__dict_tof", "__dict_tp", "first", "last", \ "__dict_tof", "__dict_tp", "_start_timer", "core", "first", \
"flag1c", "flag5c", "flag10c", "flag15c", "flag20c", \ "io", "last", "flag1c", "flag5c", "flag10c", "flag15c", \
"flank5c", "flank10c", "flank15c", "flank20c", "var" "flag20c", "flank5c", "flank10c", "flank15c", "flank20c", "var"
def __init__(self, cycletime): def __init__(self, cycletime, revpi_object):
"""Init Cycletools class.""" """Init Cycletools class."""
self.__cycle = 0 self.__cycle = 0
self.__cycletime = cycletime self.__cycletime = cycletime
@@ -98,6 +98,11 @@ class Cycletools:
self.__dict_ton = {} self.__dict_ton = {}
self.__dict_tof = {} self.__dict_tof = {}
self.__dict_tp = {} self.__dict_tp = {}
self._start_timer = 0.0
# Access to core and io
self.core = revpi_object.core
self.io = revpi_object.io
# Taktmerker # Taktmerker
self.first = True self.first = True
@@ -298,6 +303,17 @@ class Cycletools:
else: else:
self.__dict_tp[name][1] = True self.__dict_tp[name][1] = True
@property
def runtime(self) -> float:
"""
Runtime im milliseconds of cycle function till now.
This property will return the actual runtime of the function. So on the
beginning of your function it will be about 0 and will rise during
the runtime to the max in the last line of your function.
"""
return (default_timer() - self._start_timer) * 1000
class ProcimgWriter(Thread): class ProcimgWriter(Thread):
""" """
@@ -458,9 +474,10 @@ class ProcimgWriter(Thread):
self._adjwait = self._refresh self._adjwait = self._refresh
mrk_warn = True mrk_warn = True
mrk_dt = default_timer()
while not self._work.is_set(): while not self._work.is_set():
ot = default_timer() ot = mrk_dt
# Lockobjekt holen und Fehler werfen, wenn nicht schnell genug # Lockobjekt holen und Fehler werfen, wenn nicht schnell genug
if not self.lck_refresh.acquire(timeout=self._adjwait): if not self.lck_refresh.acquire(timeout=self._adjwait):
@@ -550,7 +567,8 @@ class ProcimgWriter(Thread):
self._work.wait(self._adjwait) self._work.wait(self._adjwait)
# Wartezeit anpassen um echte self._refresh zu erreichen # Wartezeit anpassen um echte self._refresh zu erreichen
if default_timer() - ot >= self._refresh: mrk_dt = default_timer()
if mrk_dt - ot >= self._refresh:
self._adjwait -= 0.001 self._adjwait -= 0.001
if self._adjwait < 0: if self._adjwait < 0:
warnings.warn( warnings.warn(

View File

@@ -1253,10 +1253,10 @@ class MemIO(IOBase):
def get_variantvalue(self): def get_variantvalue(self):
val = bytes(self._defaultvalue) val = bytes(self._defaultvalue)
if self._bitlength == 256: if self._bitlength > 64:
# STRING # STRING
try: try:
val = val.strip(b'\x00').decode("ASCII") val = val.strip(b'\x00').decode()
except Exception: except Exception:
pass pass
return val return val

View File

@@ -734,9 +734,9 @@ class RevPiModIO(object):
# Cycleloop starten # Cycleloop starten
self._exit.clear() self._exit.clear()
self._looprunning = True self._looprunning = True
cycleinfo = helpermodule.Cycletools(self._imgwriter.refresh) cycleinfo = helpermodule.Cycletools(self._imgwriter.refresh, self)
e = None e = None # Exception
ec = None ec = None # Return value of cycle_function
try: try:
while ec is None and not cycleinfo.last: while ec is None and not cycleinfo.last:
# Auf neue Daten warten und nur ausführen wenn set() # Auf neue Daten warten und nur ausführen wenn set()
@@ -752,8 +752,11 @@ class RevPiModIO(object):
# Vor Aufruf der Funktion autorefresh sperren # Vor Aufruf der Funktion autorefresh sperren
self._imgwriter.lck_refresh.acquire() self._imgwriter.lck_refresh.acquire()
# Funktion aufrufen und auswerten # Vorbereitung für cycleinfo
cycleinfo._start_timer = default_timer()
cycleinfo.last = self._exit.is_set() cycleinfo.last = self._exit.is_set()
# Funktion aufrufen und auswerten
ec = func(cycleinfo) ec = func(cycleinfo)
cycleinfo._docycle() cycleinfo._docycle()

View File

@@ -17,7 +17,7 @@ setup(
license="LGPLv3", license="LGPLv3",
name="revpimodio2", name="revpimodio2",
version="2.4.5c", version="2.4.5d",
packages=["revpimodio2"], packages=["revpimodio2"],
python_requires="~=3.2", python_requires="~=3.2",