From a6a227e99e8a42a253ab786c7ab43e84098fa575 Mon Sep 17 00:00:00 2001 From: Sven Sager Date: Sun, 3 May 2020 13:43:09 +0200 Subject: [PATCH] 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 --- .idea/codeStyles/Project.xml | 6 ++++ .idea/codeStyles/codeStyleConfig.xml | 5 ++++ revpimodio2/device.py | 41 +++++++++++++++++++--------- revpimodio2/helper.py | 32 +++++++++++++++++----- revpimodio2/io.py | 4 +-- revpimodio2/modio.py | 11 +++++--- setup.py | 2 +- 7 files changed, 74 insertions(+), 27 deletions(-) create mode 100644 .idea/codeStyles/Project.xml create mode 100644 .idea/codeStyles/codeStyleConfig.xml diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..48d4e66 --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..79ee123 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/revpimodio2/device.py b/revpimodio2/device.py index f70b266..08092e8 100644 --- a/revpimodio2/device.py +++ b/revpimodio2/device.py @@ -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) diff --git a/revpimodio2/helper.py b/revpimodio2/helper.py index 44439b6..1b93ece 100644 --- a/revpimodio2/helper.py +++ b/revpimodio2/helper.py @@ -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( diff --git a/revpimodio2/io.py b/revpimodio2/io.py index 5e75e21..8ac2f45 100644 --- a/revpimodio2/io.py +++ b/revpimodio2/io.py @@ -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 diff --git a/revpimodio2/modio.py b/revpimodio2/modio.py index 79a67a8..75ef4b7 100644 --- a/revpimodio2/modio.py +++ b/revpimodio2/modio.py @@ -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() diff --git a/setup.py b/setup.py index 8c44350..10c68e1 100644 --- a/setup.py +++ b/setup.py @@ -17,7 +17,7 @@ setup( license="LGPLv3", name="revpimodio2", - version="2.4.5c", + version="2.4.5d", packages=["revpimodio2"], python_requires="~=3.2",