From ff97f1ce0254d1c9ccbcd7f8e62e85698686be23 Mon Sep 17 00:00:00 2001 From: David Edwards Date: Mon, 23 Jan 2023 14:57:39 +0000 Subject: [PATCH 1/3] Update __init__.py --- enviro/__init__.py | 66 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/enviro/__init__.py b/enviro/__init__.py index 6225250..aa917c4 100644 --- a/enviro/__init__.py +++ b/enviro/__init__.py @@ -463,6 +463,66 @@ def upload_readings(): return True + + + +# define DELAYOFF used to ensure enviro will power down even if it hangs +# ---------------------------------------------------------------------- +from machine import Pin +from rp2 import PIO, StateMachine, asm_pio + +@asm_pio(sideset_init=PIO.OUT_HIGH) +def delayoff_prog(): + label('d_loop') + jmp(y_dec, 'd_loop') [1] + label('done') + jmp('done').side(0) + +class DELAYOFF: + def __init__(self, pin, delay, sm_id=0): + delay_ms=int(delay*1000) + self._sm = StateMachine(sm_id, delayoff_prog, freq=2000, sideset_base=Pin(pin)) + self._sm.put(delay_ms) + self._sm.exec('pull()') + self._sm.exec("mov(y, osr)") #load max count into y + self._sm.active(1) + logging.debug(f'> delayoff set on gpio{pin:} for {delay_ms:} ms') + +def arm_watchdog(): + # set default alarm now in case processor hangs. Normally ths is overwritten by sleep() + + if helpers.file_exists("watchdog_live.txt"): + os.remove("watchdog_live.txt") + logging.warn("> * * Processor recovered by watchdog * *") + + # this code extracted from sleep TODO make into routine shared by both ----------------- + dt = rtc.datetime() + hour, minute = dt[3:5] + + # calculate how many minutes into the day we are + minute = math.floor(minute / config.reading_frequency) * config.reading_frequency + minute += config.reading_frequency + + while minute >= 60: + minute -= 60 + hour += 1 + if hour >= 24: + hour -= 24 + ampm = "am" if hour < 12 else "pm" + + logging.info(f" - setting default alarm to wake at {hour:02}:{minute:02}{ampm}") + + # sleep until next scheduled reading + rtc.set_alarm(0, minute, hour) + rtc.enable_alarm_interrupt(True) + #------------------------------------------------------------------end copied from sleep + + # power will be pulled if frame does not complete in teh reading frequncy * 50 seconds + delayoff = DELAYOFF(HOLD_VSYS_EN_PIN, config.reading_frequency*45) + with open("watchdog_live.txt", "w") as hangfile: + hangfile.write("") + + def startup(): import sys @@ -486,6 +546,7 @@ def startup(): # log the wake reason logging.info(" - wake reason:", wake_reason_name(reason)) + arm_watchdog() # also immediately turn on the LED to indicate that we're doing something logging.debug(" - turn on activity led") @@ -548,6 +609,10 @@ def sleep(time_override=None): # sleep until next scheduled reading rtc.set_alarm(0, minute, hour) rtc.enable_alarm_interrupt(True) + + # delete watchdog file + if helpers.file_exists("watchdog_live.txt"): + os.remove("watchdog_live.txt") # disable the vsys hold, causing us to turn off logging.info(" - shutting down") @@ -578,3 +643,4 @@ def sleep(time_override=None): # reset the board machine.reset() + \ No newline at end of file From 7aa4858b45c44d56c89a78775a0df6c825927497 Mon Sep 17 00:00:00 2001 From: David Edwards Date: Tue, 24 Jan 2023 11:43:48 +0000 Subject: [PATCH 2/3] Configurable Watchdog Timer Settings Allows user to set watchdog timer in the config file. --- enviro/__init__.py | 26 ++++++++++++++++---------- enviro/config_template.py | 3 +++ 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/enviro/__init__.py b/enviro/__init__.py index aa917c4..71ce51b 100644 --- a/enviro/__init__.py +++ b/enviro/__init__.py @@ -480,7 +480,7 @@ def delayoff_prog(): class DELAYOFF: def __init__(self, pin, delay, sm_id=0): - delay_ms=int(delay*1000) + delay_ms=int(delay * 60 * 1000) self._sm = StateMachine(sm_id, delayoff_prog, freq=2000, sideset_base=Pin(pin)) self._sm.put(delay_ms) self._sm.exec('pull()') @@ -497,11 +497,14 @@ def arm_watchdog(): # this code extracted from sleep TODO make into routine shared by both ----------------- dt = rtc.datetime() - hour, minute = dt[3:5] - - # calculate how many minutes into the day we are - minute = math.floor(minute / config.reading_frequency) * config.reading_frequency - minute += config.reading_frequency + hour, minute, second = dt[3:6] + + # make sure the Alarm in the event of watchdog is set to 1 minute ahead + minute += int(config.pio_watchdog_time) + minute += 1 + #For edge case?? May not be needed + if second > 55: + minute += 1 while minute >= 60: minute -= 60 @@ -517,8 +520,8 @@ def arm_watchdog(): rtc.enable_alarm_interrupt(True) #------------------------------------------------------------------end copied from sleep - # power will be pulled if frame does not complete in teh reading frequncy * 50 seconds - delayoff = DELAYOFF(HOLD_VSYS_EN_PIN, config.reading_frequency*45) + # power will be pulled based on wathdog time (set in config file in minutes) + delayoff = DELAYOFF(HOLD_VSYS_EN_PIN, int(config.pio_watchdog_time)) with open("watchdog_live.txt", "w") as hangfile: hangfile.write("") @@ -546,7 +549,9 @@ def startup(): # log the wake reason logging.info(" - wake reason:", wake_reason_name(reason)) - arm_watchdog() + #set watchdog if configured in config file + if config.pio_watchdog_time is not 0: + arm_watchdog() # also immediately turn on the LED to indicate that we're doing something logging.debug(" - turn on activity led") @@ -643,4 +648,5 @@ def sleep(time_override=None): # reset the board machine.reset() - \ No newline at end of file + + diff --git a/enviro/config_template.py b/enviro/config_template.py index 980a009..07c8c67 100644 --- a/enviro/config_template.py +++ b/enviro/config_template.py @@ -24,6 +24,9 @@ # how often to upload data (number of cached readings) upload_frequency = 5 +# Watchdog timer in whole minutes (integer), 0 is not active +pio_watchdog_time = 20 + # web hook settings custom_http_url = None custom_http_username = None From 80b10c07689dc86f994b24b313f4cb01fae6b056 Mon Sep 17 00:00:00 2001 From: David Edwards Date: Tue, 24 Jan 2023 12:11:54 +0000 Subject: [PATCH 3/3] Update to Devloper guide on PIO Watchdog Update on how the current watchdog timer functions. --- documentation/developer-guide.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/documentation/developer-guide.md b/documentation/developer-guide.md index 9909970..aab164c 100644 --- a/documentation/developer-guide.md +++ b/documentation/developer-guide.md @@ -62,3 +62,7 @@ The Enviro boot up process is relatively complex as we need to ensure that thing have_destination-->|No|sleep3 ``` + +### PIO watchdog + +Issues relating to hardware hangs have been corrected by @julia767 adding in a PIO based watchdog timer that will remove the power and put the board back to deep sleep after a set period of time. This can be set in the config.py in minutes. In addition, it also sets the RTC Alarm to wake one minute after the watchdog time puts it to sleep. In the normal execution where there are no hardware hangs the RTC alarm is overwritten with the normal alarm based on the reading frequency. When setting the watchdog timer consider how long the device will need to run to upload many cached files in the event of Wifi or destination outage. Testing to date (mqtt over ssl which is slow to upload) shows a watchdog time of 20 minutes will suffice to upload 100’s of cached readings but should be tuned to your own needs. \ No newline at end of file