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", \
"_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):
"""Verhindert Ueberschreibung der LEDs."""
if hasattr(self, key) and key in (
"a1green", "a1red", "a2green", "a2red"):
"a1green", "a1red", "a2green", "a2red", "wd"):
raise AttributeError(
"direct assignment is not supported - use .value Attribute"
)
@@ -616,6 +617,12 @@ class Core(Base):
exp_a2red, None, "LED_A2_RED", "3"
], 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:
"""
Verwaltet das Schreiben der ErrorLimits.
@@ -694,6 +701,10 @@ class Core(Base):
else:
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)
A2 = property(_get_leda2, _set_leda2)
status = property(_get_status)
@@ -865,19 +876,17 @@ class Connect(Core):
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"
def __setattr__(self, key, value):
"""Verhindert Ueberschreibung der LEDs."""
"""Verhindert Ueberschreibung der speziellen IOs."""
if hasattr(self, key) and key in (
"a1green", "a1red", "a2green", "a2red", "a3green", "a3red",
"wd", "x2in", "x2out"):
"a3green", "a3red", "x2in", "x2out"):
raise AttributeError(
"direct assignment is not supported - use .value Attribute"
)
else:
object.__setattr__(self, key, value)
super(Connect, self).__setattr__(key, value)
def __wdtoggle(self) -> None:
"""WD Ausgang alle 10 Sekunden automatisch toggeln."""
@@ -921,10 +930,6 @@ class Connect(Core):
], OUT, "little", False)
# 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, [
"core.x2in", 0, 1, self._slc_statusbyte.start,
exp_x2in, None, "Connect_X2_IN", "6"
@@ -1015,7 +1020,7 @@ class Compact(Base):
"""
__slots__ = "_slc_temperature", "_slc_frequency", "_slc_led", \
"a1green", "a1red", "a2green", "a2red"
"a1green", "a1red", "a2green", "a2red", "wd"
def __setattr__(self, key, value):
"""Verhindert Ueberschreibung der LEDs."""
@@ -1066,6 +1071,12 @@ class Compact(Base):
exp_a2red, None, "LED_A2_RED", "3"
], 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:
"""
Gibt den Zustand der LED A1 vom Compact zurueck.
@@ -1119,6 +1130,10 @@ class Compact(Base):
else:
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)
A2 = property(_get_leda2, _set_leda2)

View File

@@ -85,12 +85,12 @@ class Cycletools:
Lampen synchron blinken zu lassen.
"""
__slots__ = "__cycle", "__cycletime", "__ucycle", \
"__dict_ton", "__dict_tof", "__dict_tp", "first", "last", \
"flag1c", "flag5c", "flag10c", "flag15c", "flag20c", \
"flank5c", "flank10c", "flank15c", "flank20c", "var"
__slots__ = "__cycle", "__cycletime", "__ucycle", "__dict_ton", \
"__dict_tof", "__dict_tp", "_start_timer", "core", "first", \
"io", "last", "flag1c", "flag5c", "flag10c", "flag15c", \
"flag20c", "flank5c", "flank10c", "flank15c", "flank20c", "var"
def __init__(self, cycletime):
def __init__(self, cycletime, revpi_object):
"""Init Cycletools class."""
self.__cycle = 0
self.__cycletime = cycletime
@@ -98,6 +98,11 @@ class Cycletools:
self.__dict_ton = {}
self.__dict_tof = {}
self.__dict_tp = {}
self._start_timer = 0.0
# Access to core and io
self.core = revpi_object.core
self.io = revpi_object.io
# Taktmerker
self.first = True
@@ -298,6 +303,17 @@ class Cycletools:
else:
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):
"""
@@ -458,9 +474,10 @@ class ProcimgWriter(Thread):
self._adjwait = self._refresh
mrk_warn = True
mrk_dt = default_timer()
while not self._work.is_set():
ot = default_timer()
ot = mrk_dt
# Lockobjekt holen und Fehler werfen, wenn nicht schnell genug
if not self.lck_refresh.acquire(timeout=self._adjwait):
@@ -550,7 +567,8 @@ class ProcimgWriter(Thread):
self._work.wait(self._adjwait)
# 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
if self._adjwait < 0:
warnings.warn(

View File

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

View File

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

View File

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